diff options
author | Robert Collins <rcollins@nvidia.com> | 2010-11-22 14:58:10 -0800 |
---|---|---|
committer | Maria Gutowski <mgutowski@nvidia.com> | 2010-12-13 16:12:58 -0800 |
commit | 35c64ca7c5c8569cdd1a13c88a1f10ec0c596fd1 (patch) | |
tree | ea7613c14ae7dd2854fbe7584f2cc33ac361bbb7 /drivers/input | |
parent | 3a7447be5bc4225d920e3cd15e1a4ce3c6dfa745 (diff) |
[ARM/tegra] Touchscreen : Added Atmel Max-Touch driver
Change-Id: I87de64e2c1a87c8e4da89489b4c5c18860abb0f6
Reviewed-on: http://git-master/r/11491
Reviewed-by: Robert R Collins <rcollins@nvidia.com>
Tested-by: Robert R Collins <rcollins@nvidia.com>
Reviewed-by: Maria Gutowski <mgutowski@nvidia.com>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 7 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rwxr-xr-x | drivers/input/touchscreen/atmel_maxtouch.c | 2056 |
3 files changed, 2064 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index d50fd5603604..f7c25b2b7ed6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -383,6 +383,13 @@ config TOUCHSCREEN_ATMEL_TSADCC To compile this driver as a module, choose M here: the module will be called atmel_tsadcc. +config TOUCHSCREEN_ATMEL_MT_T9 + tristate "Atmel Touchscreen Interface" + depends on I2C + help + To compile this driver as a module, choose M here: the + module will be called atmel_tsadcc. + config TOUCHSCREEN_UCB1400 tristate "Philips UCB1400 touchscreen" depends on AC97_BUS diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 93e641bc320e..b588efc90bf8 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o +obj-$(CONFIG_TOUCHSCREEN_ATMEL_MT_T9) += atmel_maxtouch.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c new file mode 100755 index 000000000000..52a9744ec501 --- /dev/null +++ b/drivers/input/touchscreen/atmel_maxtouch.c @@ -0,0 +1,2056 @@ +/* + * Atmel maXTouch Touchscreen Controller + * + * + * Copyright (C) 2010 Atmel Corporation + * Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/debugfs.h> +#include <linux/cdev.h> +#include <linux/mutex.h> +#include <linux/slab.h> + +#include <linux/uaccess.h> + +#include <linux/i2c/atmel_maxtouch.h> + +/* + * This is a driver for the Atmel maXTouch Object Protocol + * + * When the driver is loaded, mxt_init is called. + * mxt_driver registers the "mxt_driver" structure in the i2c subsystem + * The mxt_idtable.name string allows the board support to associate + * the driver with its own data. + * + * The i2c subsystem will call the mxt_driver.probe == mxt_probe + * to detect the device. + * mxt_probe will reset the maXTouch device, and then + * determine the capabilities of the I2C peripheral in the + * host processor (needs to support BYTE transfers) + * + * If OK; mxt_probe will try to identify which maXTouch device it is + * by calling mxt_identify. + * + * If a known device is found, a linux input device is initialized + * the "mxt" device data structure is allocated, + * as well as an input device structure "mxt->input" + * "mxt->client" is provided as a parameter to mxt_probe. + * + * mxt_read_object_table is called to determine which objects + * are present in the device, and to determine their adresses. + * + * + * Addressing an object: + * + * The object is located at a 16-bit address in the object address space. + * + * The address is provided through an object descriptor table in the beginning + * of the object address space. This address can change between firmware + * revisions, so it's important that the driver will make no assumptions + * about addresses but instead reads the object table and gets the correct + * addresses there. + * + * Each object type can have several instances, and the number of + * instances is available in the object table as well. + * + * The base address of the first instance of an object is stored in + * "mxt->object_table[object_type].chip_addr", + * This is indexed by the object type and allows direct access to the + * first instance of an object. + * + * Each instance of an object is assigned a "Report Id" uniquely identifying + * this instance. Information about this instance is available in the + * "mxt->report_id" variable, which is a table indexed by the "Report Id". + * + * The maXTouch object protocol supports adding a checksum to messages. + * By setting the most significant bit of the maXTouch address, + * an 8 bit checksum is added to all writes. + * + * + * How to use driver. + * ----------------- + * Example: + * In arch/avr32/boards/atstk1000/atstk1002.c + * an "i2c_board_info" descriptor is declared. + * This contains info about which driver ("mXT224"), + * which i2c address and which pin for CHG interrupts are used. + * + * In the "atstk1002_init" routine, "i2c_register_board_info" is invoked + * with this information. Also, the I/O pins are configured, and the I2C + * controller registered is on the application processor. + * + * + */ + +static int debug = NO_DEBUG; +static int comms; +module_param(debug, int, 0644); +module_param(comms, int, 0644); + +MODULE_PARM_DESC(debug, "Activate debugging output"); +MODULE_PARM_DESC(comms, "Select communications mode"); + +/* Device Info descriptor */ +/* Parsed from maXTouch "Id information" inside device */ +struct mxt_device_info { + u8 family_id; + u8 variant_id; + u8 major; + u8 minor; + u8 build; + u8 num_objs; + u8 x_size; + u8 y_size; + char family_name[16]; /* Family name */ + char variant_name[16]; /* Variant name */ + u16 num_nodes; /* Number of sensor nodes */ +}; + +/* object descriptor table, parsed from maXTouch "object table" */ +struct mxt_object { + u16 chip_addr; + u8 type; + u8 size; + u8 instances; + u8 num_report_ids; +}; + +/* Mapping from report id to object type and instance */ +struct report_id_map { + u8 object; + u8 instance; +/* + * This is the first report ID belonging to object. It enables us to + * find out easily the touch number: each touch has different report + * ID (which are assigned to touches in increasing order). By + * subtracting the first report ID from current, we get the touch + * number. + */ + u8 first_rid; +}; + +/* Driver datastructure */ +struct mxt_data { + struct i2c_client *client; + struct input_dev *input; + char phys_name[32]; + int irq; + + u16 last_read_addr; + bool new_msgs; + u8 *last_message; + + int valid_irq_counter; + int invalid_irq_counter; + int irq_counter; + int message_counter; + int read_fail_counter; + + int bytes_to_read; + + struct delayed_work dwork; + u8 xpos_format; + u8 ypos_format; + + u8 numtouch; + + struct mxt_device_info device_info; + + u32 info_block_crc; + u32 configuration_crc; + u16 report_id_count; + struct report_id_map *rid_map; + struct mxt_object *object_table; + + u16 msg_proc_addr; + u8 message_size; + + u16 max_x_val; + u16 max_y_val; + + void (*init_hw) (void); + void (*exit_hw) (void); + u8(*valid_interrupt) (void); + u8(*read_chg) (void); + + /* debugfs variables */ + struct dentry *debug_dir; + int current_debug_datap; + + struct mutex debug_mutex; + u16 *debug_data; + + /* Character device variables */ + struct cdev cdev; + struct cdev cdev_messages; /* 2nd Char dev for messages */ + dev_t dev_num; + struct class *mxt_class; + + u16 address_pointer; + bool valid_ap; + + /* Message buffer & pointers */ + char *messages; + int msg_buffer_startp, msg_buffer_endp; + /* Put only non-touch messages to buffer if this is set */ + char nontouch_msg_only; + struct mutex msg_mutex; +}; + +#define I2C_RETRY_COUNT 5 +#define I2C_PAYLOAD_SIZE 254 + +/* Returns the start address of object in mXT memory. */ +#define MXT_BASE_ADDR(object_type, mxt) \ + get_object_address(object_type, 0, mxt->object_table, \ + mxt->device_info.num_objs) + +/* Maps a report ID to an object type (object type number). */ +#define REPORT_ID_TO_OBJECT(rid, mxt) \ + (((rid) == 0xff) ? 0 : mxt->rid_map[rid].object) + +/* Maps a report ID to an object type (string). */ +#define REPORT_ID_TO_OBJECT_NAME(rid, mxt) \ + object_type_name[REPORT_ID_TO_OBJECT(rid, mxt)] + +/* Returns non-zero if given object is a touch object */ +#define IS_TOUCH_OBJECT(object) \ + ((object == MXT_TOUCH_MULTITOUCHSCREEN_T9) || \ + (object == MXT_TOUCH_KEYARRAY_T15) || \ + (object == MXT_TOUCH_PROXIMITY_T23) || \ + (object == MXT_TOUCH_SINGLETOUCHSCREEN_T10) || \ + (object == MXT_TOUCH_XSLIDER_T11) || \ + (object == MXT_TOUCH_YSLIDER_T12) || \ + (object == MXT_TOUCH_XWHEEL_T13) || \ + (object == MXT_TOUCH_YWHEEL_T14) || \ + (object == MXT_TOUCH_KEYSET_T31) || \ + (object == MXT_TOUCH_XSLIDERSET_T32) ? 1 : 0) + +#define mxt_debug(level, ...) \ + do { \ + if (debug >= (level)) \ + pr_debug(__VA_ARGS__); \ + } while (0) + +static const u8 *object_type_name[] = { + [0] = "Reserved", + [5] = "GEN_MESSAGEPROCESSOR_T5", + [6] = "GEN_COMMANDPROCESSOR_T6", + [7] = "GEN_POWERCONFIG_T7", + [8] = "GEN_ACQUIRECONFIG_T8", + [9] = "TOUCH_MULTITOUCHSCREEN_T9", + [15] = "TOUCH_KEYARRAY_T15", + [17] = "SPT_COMMSCONFIG_T18", + [19] = "SPT_GPIOPWM_T19", + [20] = "PROCI_GRIPFACESUPPRESSION_T20", + [22] = "PROCG_NOISESUPPRESSION_T22", + [23] = "TOUCH_PROXIMITY_T23", + [24] = "PROCI_ONETOUCHGESTUREPROCESSOR_T24", + [25] = "SPT_SELFTEST_T25", + [27] = "PROCI_TWOTOUCHGESTUREPROCESSOR_T27", + [28] = "SPT_CTECONFIG_T28", + [37] = "DEBUG_DIAGNOSTICS_T37", + [38] = "SPT_USER_DATA_T38", + [40] = "PROCI_GRIPSUPPRESSION_T40", + [41] = "PROCI_PALMSUPPRESSION_T41", + [42] = "PROCI_FACESUPPRESSION_T42", + [43] = "SPT_DIGITIZER_T43", + [44] = "SPT_MESSAGECOUNT_T44", +}; + +static u16 get_object_address(uint8_t object_type, + uint8_t instance, + struct mxt_object *object_table, int max_objs); + +static int mxt_write_ap(struct mxt_data *mxt, u16 ap); + +static int mxt_read_block_wo_addr(struct i2c_client *client, + u16 length, u8 *value); + +ssize_t debug_data_read(struct mxt_data *mxt, char *buf, size_t count, + loff_t *ppos, u8 debug_command) +{ + int i; + u16 *data; + u16 diagnostics_reg; + int offset = 0; + int size; + int read_size; + int error; + char *buf_start; + u16 debug_data_addr; + u16 page_address; + u8 page; + u8 debug_command_reg; + + data = mxt->debug_data; + if (data == NULL) + return -EIO; + + /* If first read after open, read all data to buffer. */ + if (mxt->current_debug_datap == 0) { + + diagnostics_reg = MXT_BASE_ADDR(MXT_GEN_COMMANDPROCESSOR_T6, + mxt) + MXT_ADR_T6_DIAGNOSTIC; + if (count > (mxt->device_info.num_nodes * 2)) + count = mxt->device_info.num_nodes; + + debug_data_addr = MXT_BASE_ADDR(MXT_DEBUG_DIAGNOSTIC_T37, mxt) + + MXT_ADR_T37_DATA; + page_address = MXT_BASE_ADDR(MXT_DEBUG_DIAGNOSTIC_T37, mxt) + + MXT_ADR_T37_PAGE; + error = mxt_read_block(mxt->client, page_address, 1, &page); + if (error < 0) + return error; + mxt_debug(DEBUG_TRACE, "debug data page = %d\n", page); + while (page != 0) { + error = mxt_write_byte(mxt->client, + diagnostics_reg, + MXT_CMD_T6_PAGE_DOWN); + if (error < 0) + return error; + /* Wait for command to be handled; when it has, the + register will be cleared. */ + debug_command_reg = 1; + while (debug_command_reg != 0) { + error = mxt_read_block(mxt->client, + diagnostics_reg, 1, + &debug_command_reg); + if (error < 0) + return error; + mxt_debug(DEBUG_TRACE, + "Waiting for debug diag command " + "to propagate...\n"); + + } + error = mxt_read_block(mxt->client, page_address, 1, + &page); + if (error < 0) + return error; + mxt_debug(DEBUG_TRACE, "debug data page = %d\n", page); + } + + /* + * Lock mutex to prevent writing some unwanted data to debug + * command register. User can still write through the char + * device interface though. TODO: fix? + */ + + mutex_lock(&mxt->debug_mutex); + /* Configure Debug Diagnostics object to show deltas/refs */ + error = mxt_write_byte(mxt->client, diagnostics_reg, + debug_command); + + /* Wait for command to be handled; when it has, the + * register will be cleared. */ + debug_command_reg = 1; + while (debug_command_reg != 0) { + error = mxt_read_block(mxt->client, + diagnostics_reg, 1, + &debug_command_reg); + if (error < 0) + return error; + mxt_debug(DEBUG_TRACE, "Waiting for debug diag command " + "to propagate...\n"); + + } + + if (error < 0) { + printk(KERN_WARNING + "Error writing to maXTouch device!\n"); + return error; + } + + size = mxt->device_info.num_nodes * sizeof(u16); + + while (size > 0) { + read_size = size > 128 ? 128 : size; + mxt_debug(DEBUG_TRACE, + "Debug data read loop, reading %d bytes...\n", + read_size); + error = mxt_read_block(mxt->client, + debug_data_addr, + read_size, + (u8 *) &data[offset]); + if (error < 0) { + printk(KERN_WARNING + "Error reading debug data\n"); + goto error; + } + offset += read_size / 2; + size -= read_size; + + /* Select next page */ + error = mxt_write_byte(mxt->client, diagnostics_reg, + MXT_CMD_T6_PAGE_UP); + if (error < 0) { + printk(KERN_WARNING + "Error writing to maXTouch device!\n"); + goto error; + } + } + mutex_unlock(&mxt->debug_mutex); + } + + buf_start = buf; + i = mxt->current_debug_datap; + + while (((buf - buf_start) < (count - 6)) && + (i < mxt->device_info.num_nodes)) { + + mxt->current_debug_datap++; + if (debug_command == MXT_CMD_T6_REFERENCES_MODE) + buf += sprintf(buf, "%d: %5d\n", i, + (u16) le16_to_cpu(data[i])); + else if (debug_command == MXT_CMD_T6_DELTAS_MODE) + buf += sprintf(buf, "%d: %5d\n", i, + (s16) le16_to_cpu(data[i])); + i++; + } + + return buf - buf_start; + error: + mutex_unlock(&mxt->debug_mutex); + return error; +} + +ssize_t deltas_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return debug_data_read(file->private_data, buf, count, ppos, + MXT_CMD_T6_DELTAS_MODE); +} + +ssize_t refs_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return debug_data_read(file->private_data, buf, count, ppos, + MXT_CMD_T6_REFERENCES_MODE); +} + +int debug_data_open(struct inode *inode, struct file *file) +{ + struct mxt_data *mxt; + int i; + mxt = inode->i_private; + if (mxt == NULL) + return -EIO; + mxt->current_debug_datap = 0; + mxt->debug_data = kmalloc(mxt->device_info.num_nodes * sizeof(u16), + GFP_KERNEL); + if (mxt->debug_data == NULL) + return -ENOMEM; + + for (i = 0; i < mxt->device_info.num_nodes; i++) + mxt->debug_data[i] = 7777; + + file->private_data = mxt; + return 0; +} + +int debug_data_release(struct inode *inode, struct file *file) +{ + struct mxt_data *mxt; + mxt = file->private_data; + kfree(mxt->debug_data); + return 0; +} + +const struct file_operations delta_fops = { + .owner = THIS_MODULE, + .open = debug_data_open, + .release = debug_data_release, + .read = deltas_read, +}; + +const struct file_operations refs_fops = { + .owner = THIS_MODULE, + .open = debug_data_open, + .release = debug_data_release, + .read = refs_read, +}; + +int mxt_memory_open(struct inode *inode, struct file *file) +{ + struct mxt_data *mxt; + mxt = container_of(inode->i_cdev, struct mxt_data, cdev); + if (mxt == NULL) + return -EIO; + file->private_data = mxt; + return 0; +} + +int mxt_message_open(struct inode *inode, struct file *file) +{ + struct mxt_data *mxt; + mxt = container_of(inode->i_cdev, struct mxt_data, cdev_messages); + if (mxt == NULL) + return -EIO; + file->private_data = mxt; + return 0; +} + +ssize_t mxt_memory_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + int i; + struct mxt_data *mxt; + + mxt = file->private_data; + if (mxt->valid_ap) { + mxt_debug(DEBUG_TRACE, "Reading %d bytes from current ap\n", + (int)count); + i = mxt_read_block_wo_addr(mxt->client, count, (u8 *) buf); + } else { + mxt_debug(DEBUG_TRACE, "Address pointer changed since set;" + "writing AP (%d) before reading %d bytes", + mxt->address_pointer, (int)count); + i = mxt_read_block(mxt->client, mxt->address_pointer, count, + buf); + } + + return i; +} + +ssize_t mxt_memory_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + int i; + int whole_blocks; + int last_block_size; + struct mxt_data *mxt; + u16 address; + + mxt = file->private_data; + address = mxt->address_pointer; + + mxt_debug(DEBUG_TRACE, "mxt_memory_write entered\n"); + whole_blocks = count / I2C_PAYLOAD_SIZE; + last_block_size = count % I2C_PAYLOAD_SIZE; + + for (i = 0; i < whole_blocks; i++) { + mxt_debug(DEBUG_TRACE, "About to write to %d...", address); + mxt_write_block(mxt->client, address, I2C_PAYLOAD_SIZE, + (u8 *) buf); + address += I2C_PAYLOAD_SIZE; + buf += I2C_PAYLOAD_SIZE; + } + + mxt_write_block(mxt->client, address, last_block_size, (u8 *) buf); + + return count; +} + +static int mxt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval; + struct mxt_data *mxt; + + retval = 0; + mxt = file->private_data; + + switch (cmd) { + case MXT_SET_ADDRESS: + retval = mxt_write_ap(mxt, (u16) arg); + if (retval >= 0) { + mxt->address_pointer = (u16) arg; + mxt->valid_ap = 1; + } + break; + case MXT_RESET: + retval = mxt_write_byte(mxt->client, + MXT_BASE_ADDR + (MXT_GEN_COMMANDPROCESSOR_T6, + mxt) + MXT_ADR_T6_RESET, 1); + break; + case MXT_CALIBRATE: + retval = mxt_write_byte(mxt->client, + MXT_BASE_ADDR + (MXT_GEN_COMMANDPROCESSOR_T6, + mxt) + MXT_ADR_T6_CALIBRATE, 1); + + break; + case MXT_BACKUP: + retval = mxt_write_byte(mxt->client, + MXT_BASE_ADDR + (MXT_GEN_COMMANDPROCESSOR_T6, + mxt) + MXT_ADR_T6_BACKUPNV, + MXT_CMD_T6_BACKUP); + break; + case MXT_NONTOUCH_MSG: + mxt->nontouch_msg_only = 1; + break; + case MXT_ALL_MSG: + mxt->nontouch_msg_only = 0; + break; + default: + return -EIO; + } + + return retval; +} + +/* + * Copies messages from buffer to user space. + * + * NOTE: if less than (mxt->message_size * 5 + 1) bytes requested, + * this will return 0! + * + */ +ssize_t mxt_message_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + int i; + struct mxt_data *mxt; + char *buf_start; + + mxt = file->private_data; + if (mxt == NULL) + return -EIO; + buf_start = buf; + + mutex_lock(&mxt->msg_mutex); + /* Copy messages until buffer empty, or 'count' bytes written */ + while ((mxt->msg_buffer_startp != mxt->msg_buffer_endp) && + ((buf - buf_start) < (count - 5 * mxt->message_size - 1))) { + + for (i = 0; i < mxt->message_size; i++) { + buf += sprintf(buf, "[%2X] ", + *(mxt->messages + mxt->msg_buffer_endp * + mxt->message_size + i)); + } + buf += sprintf(buf, "\n"); + if (mxt->msg_buffer_endp < MXT_MESSAGE_BUFFER_SIZE) + mxt->msg_buffer_endp++; + else + mxt->msg_buffer_endp = 0; + } + mutex_unlock(&mxt->msg_mutex); + return buf - buf_start; +} + +const struct file_operations mxt_message_fops = { + .owner = THIS_MODULE, + .open = mxt_message_open, + .read = mxt_message_read, +}; + +const struct file_operations mxt_memory_fops = { + .owner = THIS_MODULE, + .open = mxt_memory_open, + .read = mxt_memory_read, + .write = mxt_memory_write, + .unlocked_ioctl = mxt_ioctl, +}; + +/* Writes the address pointer (to set up following reads). */ + +int mxt_write_ap(struct mxt_data *mxt, u16 ap) +{ + struct i2c_client *client; + __le16 le_ap = cpu_to_le16(ap); + client = mxt->client; + if (mxt != NULL) + mxt->last_read_addr = -1; + if (i2c_master_send(client, (u8 *) &le_ap, 2) == 2) { + mxt_debug(DEBUG_TRACE, "Address pointer set to %d\n", ap); + return 0; + } else { + mxt_debug(DEBUG_INFO, "Error writing address pointer!\n"); + return -EIO; + } +} + +/* Calculates the 24-bit CRC sum. */ +static u32 CRC_24(u32 crc, u8 byte1, u8 byte2) +{ + static const u32 crcpoly = 0x80001B; + u32 result; + u32 data_word; + + data_word = ((((u16) byte2) << 8u) | byte1); + result = ((crc << 1u) ^ data_word); + if (result & 0x1000000) + result ^= crcpoly; + return result; +} + +/* Returns object address in mXT chip, or zero if object is not found */ +static u16 get_object_address(uint8_t object_type, + uint8_t instance, + struct mxt_object *object_table, int max_objs) +{ + uint8_t object_table_index = 0; + uint8_t address_found = 0; + uint16_t address = 0; + struct mxt_object *obj; + + while ((object_table_index < max_objs) && !address_found) { + obj = &object_table[object_table_index]; + if (obj->type == object_type) { + address_found = 1; + /* Are there enough instances defined in the FW? */ + if (obj->instances >= instance) { + address = obj->chip_addr + + (obj->size + 1) * instance; + } else { + return 0; + } + } + object_table_index++; + } + return address; +} + +/* + * Reads a block of bytes from given address from mXT chip. If we are + * reading from message window, and previous read was from message window, + * there's no need to write the address pointer: the mXT chip will + * automatically set the address pointer back to message window start. + */ + +static int mxt_read_block(struct i2c_client *client, + u16 addr, u16 length, u8 *value) +{ + struct i2c_adapter *adapter = client->adapter; + struct i2c_msg msg[2]; + __le16 le_addr; + struct mxt_data *mxt; + + mxt = i2c_get_clientdata(client); + + if (mxt != NULL) { + if ((mxt->last_read_addr == addr) && + (addr == mxt->msg_proc_addr)) { + if (i2c_master_recv(client, value, length) == length) + return length; + else + return -EIO; + } else { + mxt->last_read_addr = addr; + } + } + + mxt_debug(DEBUG_TRACE, "Writing address pointer & reading %d bytes " + "in on i2c transaction...\n", length); + + le_addr = cpu_to_le16(addr); + msg[0].addr = client->addr; + msg[0].flags = 0x00; + msg[0].len = 2; + msg[0].buf = (u8 *) &le_addr; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = (u8 *) value; + if (i2c_transfer(adapter, msg, 2) == 2) + return length; + else + return -EIO; + +} + +/* Reads a block of bytes from current address from mXT chip. */ + +static int mxt_read_block_wo_addr(struct i2c_client *client, + u16 length, u8 *value) +{ + + if (i2c_master_recv(client, value, length) == length) { + mxt_debug(DEBUG_TRACE, "I2C block read ok\n"); + return length; + } else { + mxt_debug(DEBUG_INFO, "I2C block read failed\n"); + return -EIO; + } + +} + +/* Writes one byte to given address in mXT chip. */ + +static int mxt_write_byte(struct i2c_client *client, u16 addr, u8 value) +{ + struct { + __le16 le_addr; + u8 data; + + } i2c_byte_transfer; + + struct mxt_data *mxt; + + mxt = i2c_get_clientdata(client); + if (mxt != NULL) + mxt->last_read_addr = -1; + i2c_byte_transfer.le_addr = cpu_to_le16(addr); + i2c_byte_transfer.data = value; + if (i2c_master_send(client, (u8 *) &i2c_byte_transfer, 3) == 3) + return 0; + else + return -EIO; +} + +/* Writes a block of bytes (max 256) to given address in mXT chip. */ +static int mxt_write_block(struct i2c_client *client, + u16 addr, u16 length, u8 *value) +{ + int i; + struct { + __le16 le_addr; + u8 data[256]; + + } i2c_block_transfer; + + struct mxt_data *mxt; + + mxt_debug(DEBUG_TRACE, "Writing %d bytes to %d...", length, addr); + if (length > 256) + return -EINVAL; + mxt = i2c_get_clientdata(client); + if (mxt != NULL) + mxt->last_read_addr = -1; + for (i = 0; i < length; i++) + i2c_block_transfer.data[i] = *value++; + i2c_block_transfer.le_addr = cpu_to_le16(addr); + i = i2c_master_send(client, (u8 *) &i2c_block_transfer, length + 2); + if (i == (length + 2)) + return length; + else + return -EIO; +} + +/* Calculates the CRC value for mXT infoblock. */ +int calculate_infoblock_crc(u32 *crc_result, u8 *data, int crc_area_size) +{ + u32 crc = 0; + int i; + + for (i = 0; i < (crc_area_size - 1); i = i + 2) + crc = CRC_24(crc, *(data + i), *(data + i + 1)); + /* If uneven size, pad with zero */ + if (crc_area_size & 0x0001) + crc = CRC_24(crc, *(data + i), 0); + /* Return only 24 bits of CRC. */ + *crc_result = (crc & 0x00FFFFFF); + + return 0; +} + +void process_T9_message(u8 *message, struct mxt_data *mxt, int last_touch) +{ + + struct input_dev *input; + u8 status; + u16 xpos = 0xFFFF; + u16 ypos = 0xFFFF; + u8 touch_size = 255; + u8 touch_number; + u8 amplitude; + u8 report_id; + + static int stored_size[10]; + static int stored_x[10]; + static int stored_y[10]; + int i; + int active_touches = 0; + /* + * If the 'last_touch' flag is set, we have received + all the touch messages + * there are available in this cycle, so send the + events for touches that are + * active. + */ + if (last_touch) { + for (i = 0; i < 10; i++) { + if (stored_size[i]) { + active_touches++; + input_report_abs(mxt->input, ABS_MT_TRACKING_ID, + i); + input_report_abs(mxt->input, ABS_MT_TOUCH_MAJOR, + stored_size[i]); + input_report_abs(mxt->input, ABS_MT_POSITION_X, + stored_x[i]); + input_report_abs(mxt->input, ABS_MT_POSITION_Y, + stored_y[i]); + input_mt_sync(mxt->input); + } + } + if (active_touches) + input_sync(mxt->input); + else { + input_mt_sync(mxt->input); + input_sync(mxt->input); + } + + } else { + + input = mxt->input; + status = message[MXT_MSG_T9_STATUS]; + report_id = message[0]; + + if (status & MXT_MSGB_T9_SUPPRESS) { + /* Touch has been suppressed by grip/face */ + /* detection */ + mxt_debug(DEBUG_TRACE, "SUPRESS"); + } else { + xpos = message[MXT_MSG_T9_XPOSMSB] * 16 + + ((message[MXT_MSG_T9_XYPOSLSB] >> 4) & 0xF); + ypos = message[MXT_MSG_T9_YPOSMSB] * 16 + + ((message[MXT_MSG_T9_XYPOSLSB] >> 0) & 0xF); + if (mxt->max_x_val < 1024) + xpos >>= 2; + if (mxt->max_y_val < 1024) + ypos >>= 2; + + touch_number = message[MXT_MSG_REPORTID] - + mxt->rid_map[report_id].first_rid; + + stored_x[touch_number] = xpos; + stored_y[touch_number] = ypos; + + if (status & MXT_MSGB_T9_DETECT) { + /* + * TODO: more precise touch size calculation? + * mXT224 reports the number of touched nodes, + * so the exact value for touch ellipse major + * axis length would be 2*sqrt(touch_size/pi) + * (assuming round touch shape). + */ + touch_size = message[MXT_MSG_T9_TCHAREA]; + touch_size = touch_size >> 2; + if (!touch_size) + touch_size = 1; + + stored_size[touch_number] = touch_size; + + if (status & MXT_MSGB_T9_AMP) + /* Amplitude of touch has changed */ + amplitude = + message[MXT_MSG_T9_TCHAMPLITUDE]; + } + + if (status & MXT_MSGB_T9_RELEASE) { + /* The previously reported touch has + been removed. */ + stored_size[touch_number] = 0; + } + } + + if (status & MXT_MSGB_T9_SUPPRESS) { + mxt_debug(DEBUG_TRACE, "SUPRESS"); + } else { + if (status & MXT_MSGB_T9_DETECT) { + mxt_debug(DEBUG_TRACE, "DETECT:%s%s%s%s", + ((status & MXT_MSGB_T9_PRESS) ? + " PRESS" : ""), + ((status & MXT_MSGB_T9_MOVE) ? " MOVE" + : ""), + ((status & MXT_MSGB_T9_AMP) ? " AMP" : + ""), + ((status & MXT_MSGB_T9_VECTOR) ? + " VECT" : "")); + + } else if (status & MXT_MSGB_T9_RELEASE) { + mxt_debug(DEBUG_TRACE, "RELEASE"); + } + } + mxt_debug(DEBUG_TRACE, "X=%d, Y=%d, TOUCHSIZE=%d", + xpos, ypos, touch_size); + } + return; +} + +int process_message(u8 *message, u8 object, struct mxt_data *mxt) +{ + struct i2c_client *client; + u8 status; + u16 xpos = 0xFFFF; + u16 ypos = 0xFFFF; + u8 event; + u8 length; + u8 report_id; + + client = mxt->client; + length = mxt->message_size; + report_id = message[0]; + + if ((mxt->nontouch_msg_only == 0) || (!IS_TOUCH_OBJECT(object))) { + mutex_lock(&mxt->msg_mutex); + /* Copy the message to buffer */ + if (mxt->msg_buffer_startp < MXT_MESSAGE_BUFFER_SIZE) + mxt->msg_buffer_startp++; + else + mxt->msg_buffer_startp = 0; + + if (mxt->msg_buffer_startp == mxt->msg_buffer_endp) { + mxt_debug(DEBUG_TRACE, + "Message buf full, discarding last entry.\n"); + if (mxt->msg_buffer_endp < MXT_MESSAGE_BUFFER_SIZE) + mxt->msg_buffer_endp++; + else + mxt->msg_buffer_endp = 0; + } + memcpy((mxt->messages + mxt->msg_buffer_startp * length), + message, length); + mutex_unlock(&mxt->msg_mutex); + } + + switch (object) { + case MXT_GEN_COMMANDPROCESSOR_T6: + status = message[1]; + if (status & MXT_MSGB_T6_COMSERR) + dev_err(&client->dev, "maXTouch checksum error\n"); + if (status & MXT_MSGB_T6_CFGERR) { + /* + * Configuration error. A proper configuration + * needs to be written to chip and backed up. Refer + * to protocol document for further info. + */ + dev_err(&client->dev, "maXTouch configuration error\n"); + } + if (status & MXT_MSGB_T6_CAL) { + /* Calibration in action, no need to react */ + dev_info(&client->dev, + "maXTouch calibration in progress\n"); + } + if (status & MXT_MSGB_T6_SIGERR) { + /* + * Signal acquisition error, something is seriously + * wrong, not much we can in the driver to correct + * this + */ + dev_err(&client->dev, "maXTouch acquisition error\n"); + } + if (status & MXT_MSGB_T6_OFL) { + /* + * Cycle overflow, the acquisition is too short. + * Can happen temporarily when there's a complex + * touch shape on the screen requiring lots of + * processing. + */ + dev_err(&client->dev, "maXTouch cycle overflow\n"); + } + if (status & MXT_MSGB_T6_RESET) { + /* Chip has reseted, no need to react. */ + dev_info(&client->dev, "maXTouch chip reset\n"); + } + if (status == 0) { + /* Chip status back to normal. */ + dev_info(&client->dev, "maXTouch status normal\n"); + } + break; + + case MXT_TOUCH_MULTITOUCHSCREEN_T9: + process_T9_message(message, mxt, 0); + break; + + case MXT_SPT_GPIOPWM_T19: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "Receiving GPIO message\n"); + break; + + case MXT_PROCI_GRIPFACESUPPRESSION_T20: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "Receiving face suppression msg\n"); + break; + + case MXT_PROCG_NOISESUPPRESSION_T22: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "Receiving noise suppression msg\n"); + status = message[MXT_MSG_T22_STATUS]; + if (status & MXT_MSGB_T22_FHCHG) { + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "maXTouch: Freq changed\n"); + } + if (status & MXT_MSGB_T22_GCAFERR) { + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "maXTouch: High noise " "level\n"); + } + if (status & MXT_MSGB_T22_FHERR) { + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "maXTouch: Freq changed - " + "Noise level too high\n"); + } + break; + + case MXT_PROCI_ONETOUCHGESTUREPROCESSOR_T24: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "Receiving one-touch gesture msg\n"); + + event = message[MXT_MSG_T24_STATUS] & 0x0F; + xpos = message[MXT_MSG_T24_XPOSMSB] * 16 + + ((message[MXT_MSG_T24_XYPOSLSB] >> 4) & 0x0F); + ypos = message[MXT_MSG_T24_YPOSMSB] * 16 + + ((message[MXT_MSG_T24_XYPOSLSB] >> 0) & 0x0F); + xpos >>= 2; + ypos >>= 2; + + switch (event) { + case MT_GESTURE_RESERVED: + break; + case MT_GESTURE_PRESS: + break; + case MT_GESTURE_RELEASE: + break; + case MT_GESTURE_TAP: + break; + case MT_GESTURE_DOUBLE_TAP: + break; + case MT_GESTURE_FLICK: + break; + case MT_GESTURE_DRAG: + break; + case MT_GESTURE_SHORT_PRESS: + break; + case MT_GESTURE_LONG_PRESS: + break; + case MT_GESTURE_REPEAT_PRESS: + break; + case MT_GESTURE_TAP_AND_PRESS: + break; + case MT_GESTURE_THROW: + break; + default: + break; + } + break; + + case MXT_SPT_SELFTEST_T25: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "Receiving Self-Test msg\n"); + + if (message[MXT_MSG_T25_STATUS] == MXT_MSGR_T25_OK) { + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "maXTouch: Self-Test OK\n"); + + } else { + dev_err(&client->dev, + "maXTouch: Self-Test Failed [%02x]:" + "{%02x,%02x,%02x,%02x,%02x}\n", + message[MXT_MSG_T25_STATUS], + message[MXT_MSG_T25_STATUS + 0], + message[MXT_MSG_T25_STATUS + 1], + message[MXT_MSG_T25_STATUS + 2], + message[MXT_MSG_T25_STATUS + 3], + message[MXT_MSG_T25_STATUS + 4] + ); + } + break; + + case MXT_PROCI_TWOTOUCHGESTUREPROCESSOR_T27: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "Receiving 2-touch gesture message\n"); + break; + + case MXT_SPT_CTECONFIG_T28: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "Receiving CTE message...\n"); + status = message[MXT_MSG_T28_STATUS]; + if (status & MXT_MSGB_T28_CHKERR) + dev_err(&client->dev, + "maXTouch: Power-Up CRC failure\n"); + + break; + default: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "maXTouch: Unknown message!\n"); + + break; + } + + return 0; +} + +/* + * Processes messages when the interrupt line (CHG) is asserted. Keeps + * reading messages until a message with report ID 0xFF is received, + * which indicates that there is no more new messages. + * + */ + +static void mxt_worker(struct work_struct *work) +{ + struct mxt_data *mxt; + struct i2c_client *client; + + u8 *message; + u16 message_length; + u16 message_addr; + u8 report_id; + u8 object; + int error; + int i; + char *message_string; + char *message_start; + + int n = 0; + + message = NULL; + mxt = container_of(work, struct mxt_data, dwork.work); + disable_irq(mxt->irq); + client = mxt->client; + message_addr = mxt->msg_proc_addr; + message_length = mxt->message_size; + + if (message_length < 256) { + message = kmalloc(message_length, GFP_KERNEL); + if (message == NULL) { + dev_err(&client->dev, "Error allocating memory\n"); + return; + } + } else { + dev_err(&client->dev, + "Message length larger than 256 bytes not supported\n"); + return; + } + + mxt_debug("maXTouch worker active: \n"); + do { + /* Read next message, reread on failure. */ + /* -1 TO WORK AROUND A BUG ON 0.9 FW MESSAGING, needs */ + /* to be changed back if checksum is read */ + mxt->message_counter++; + for (i = 1; i < I2C_RETRY_COUNT; i++) { + error = mxt_read_block(client, + message_addr, + message_length - 1, message); + if (error >= 0) + break; + mxt->read_fail_counter++; + dev_err(&client->dev, + "Failure reading maxTouch device\n"); + } + if (error < 0) { + kfree(message); + return; + } + + if (mxt->address_pointer != message_addr) + mxt->valid_ap = 0; + report_id = message[0]; + + if (debug >= DEBUG_RAW) { + mxt_debug(DEBUG_RAW, "%s message [msg count: %08x]:", + REPORT_ID_TO_OBJECT_NAME(report_id, mxt), + mxt->message_counter); + /* 5 characters per one byte */ + message_string = kmalloc(message_length * 5, + GFP_KERNEL); + if (message_string == NULL) { + dev_err(&client->dev, + "Error allocating memory\n"); + kfree(message); + return; + } + message_start = message_string; + for (i = 0; i < message_length; i++) { + message_string += + sprintf(message_string, + "0x%02X ", message[i]); + } + mxt_debug(DEBUG_RAW, "%s", message_start); + kfree(message_start); + } + + if ((report_id != MXT_END_OF_MESSAGES) && (report_id != 0)) { + memcpy(mxt->last_message, message, message_length); + mxt->new_msgs = 1; + smp_wmb(); + /* Get type of object and process the message */ + object = mxt->rid_map[report_id].object; + process_message(message, object, mxt); + } + mxt_debug(DEBUG_TRACE, "chgline: %d\n", mxt->read_chg()); + } while (comms ? (mxt->read_chg() == 0) : + ((report_id != MXT_END_OF_MESSAGES) && (report_id != 0))); + + /* All messages processed, send the events) */ + process_T9_message(NULL, mxt, 1); + + kfree(message); + enable_irq(mxt->irq); + /* Make sure we don't miss any interrupts and read changeline. */ + if (mxt->read_chg() == 0) + schedule_delayed_work(&mxt->dwork, 0); +} + +/* + * The maXTouch device will signal the host about a new message by asserting + * the CHG line. This ISR schedules a worker routine to read the message when + * that happens. + */ + +static irqreturn_t mxt_irq_handler(int irq, void *_mxt) +{ + struct mxt_data *mxt = _mxt; + + mxt->irq_counter++; + if (mxt->valid_interrupt()) { + /* Send the signal only if falling edge generated the irq. */ + cancel_delayed_work(&mxt->dwork); + schedule_delayed_work(&mxt->dwork, 0); + mxt->valid_irq_counter++; + } else { + mxt->invalid_irq_counter++; + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +/******************************************************************************/ +/* Initialization of driver */ +/******************************************************************************/ + +static int __devinit mxt_identify(struct i2c_client *client, + struct mxt_data *mxt, u8 * id_block_data) +{ + u8 buf[7]; + int error; + int identified; + + identified = 0; + + /* Read Device info to check if chip is valid */ + error = mxt_read_block(client, MXT_ADDR_INFO_BLOCK, MXT_ID_BLOCK_SIZE, + (u8 *) buf); + + if (error < 0) { + mxt->read_fail_counter++; + dev_err(&client->dev, "Failure accessing maXTouch device\n"); + return -EIO; + } + + memcpy(id_block_data, buf, MXT_ID_BLOCK_SIZE); + + mxt->device_info.family_id = buf[0]; + mxt->device_info.variant_id = buf[1]; + mxt->device_info.major = ((buf[2] >> 4) & 0x0F); + mxt->device_info.minor = (buf[2] & 0x0F); + mxt->device_info.build = buf[3]; + mxt->device_info.x_size = buf[4]; + mxt->device_info.y_size = buf[5]; + mxt->device_info.num_objs = buf[6]; + mxt->device_info.num_nodes = mxt->device_info.x_size * + mxt->device_info.y_size; + + /* + * Check Family & Variant Info; warn if not recognized but + * still continue. + */ + + /* MXT224 */ + if (mxt->device_info.family_id == MXT224_FAMILYID) { + strcpy(mxt->device_info.family_name, "mXT224"); + + if (mxt->device_info.variant_id == MXT224_CAL_VARIANTID) { + strcpy(mxt->device_info.variant_name, "Calibrated"); + } else if (mxt->device_info.variant_id == + MXT224_UNCAL_VARIANTID) { + strcpy(mxt->device_info.variant_name, "Uncalibrated"); + } else { + dev_err(&client->dev, + "Warning: maXTouch Variant ID [%d] not " + "supported\n", mxt->device_info.variant_id); + strcpy(mxt->device_info.variant_name, "UNKNOWN"); + /* identified = -ENXIO; */ + } + + /* MXT1386 */ + } else if (mxt->device_info.family_id == MXT1386_FAMILYID) { + strcpy(mxt->device_info.family_name, "mXT1386"); + + if (mxt->device_info.variant_id == MXT1386_CAL_VARIANTID) { + strcpy(mxt->device_info.variant_name, "Calibrated"); + } else { + dev_err(&client->dev, + "Warning: maXTouch Variant ID [%d] not " + "supported\n", mxt->device_info.variant_id); + strcpy(mxt->device_info.variant_name, "UNKNOWN"); + /* identified = -ENXIO; */ + } + /* Unknown family ID! */ + } else { + dev_err(&client->dev, + "Warning: maXTouch Family ID [%d] not supported\n", + mxt->device_info.family_id); + strcpy(mxt->device_info.family_name, "UNKNOWN"); + strcpy(mxt->device_info.variant_name, "UNKNOWN"); + /* identified = -ENXIO; */ + } + + dev_info(&client->dev, + "Atmel maXTouch (Family %s (%X), Variant %s (%X)) Firmware " + "version [%d.%d] Build %d\n", + mxt->device_info.family_name, + mxt->device_info.family_id, + mxt->device_info.variant_name, + mxt->device_info.variant_id, + mxt->device_info.major, + mxt->device_info.minor, mxt->device_info.build); + dev_info(&client->dev, + "Atmel maXTouch Configuration " + "[X: %d] x [Y: %d]\n", + mxt->device_info.x_size, mxt->device_info.y_size); + return identified; +} + +/* + * Reads the object table from maXTouch chip to get object data like + * address, size, report id. For Info Block CRC calculation, already read + * id data is passed to this function too (Info Block consists of the ID + * block and object table). + * + */ +static int __devinit mxt_read_object_table(struct i2c_client *client, + struct mxt_data *mxt, + u8 *raw_id_data) +{ + u16 report_id_count; + u8 buf[MXT_OBJECT_TABLE_ELEMENT_SIZE]; + u8 *raw_ib_data; + u8 object_type; + u16 object_address; + u16 object_size; + u8 object_instances; + u8 object_report_ids; + u16 object_info_address; + u32 crc; + u32 calculated_crc; + int i; + int error; + + u8 object_instance; + u8 object_report_id; + u8 report_id; + int first_report_id; + int ib_pointer; + struct mxt_object *object_table; + + mxt_debug(DEBUG_TRACE, "maXTouch driver reading configuration\n"); + + object_table = kzalloc(sizeof(struct mxt_object) * + mxt->device_info.num_objs, GFP_KERNEL); + if (object_table == NULL) { + printk(KERN_WARNING "maXTouch: Memory allocation failed!\n"); + error = -ENOMEM; + goto err_object_table_alloc; + } + + raw_ib_data = kmalloc(MXT_OBJECT_TABLE_ELEMENT_SIZE * + mxt->device_info.num_objs + MXT_ID_BLOCK_SIZE, + GFP_KERNEL); + if (raw_ib_data == NULL) { + printk(KERN_WARNING "maXTouch: Memory allocation failed!\n"); + error = -ENOMEM; + goto err_ib_alloc; + } + + /* Copy the ID data for CRC calculation. */ + memcpy(raw_ib_data, raw_id_data, MXT_ID_BLOCK_SIZE); + ib_pointer = MXT_ID_BLOCK_SIZE; + + mxt->object_table = object_table; + + mxt_debug(DEBUG_TRACE, "maXTouch driver Memory allocated\n"); + + object_info_address = MXT_ADDR_OBJECT_TABLE; + + report_id_count = 0; + for (i = 0; i < mxt->device_info.num_objs; i++) { + mxt_debug(DEBUG_TRACE, "Reading maXTouch at [0x%04x]: ", + object_info_address); + + error = mxt_read_block(client, object_info_address, + MXT_OBJECT_TABLE_ELEMENT_SIZE, buf); + + if (error < 0) { + mxt->read_fail_counter++; + dev_err(&client->dev, + "maXTouch Object %d could not be read\n", i); + error = -EIO; + goto err_object_read; + } + + memcpy(raw_ib_data + ib_pointer, buf, + MXT_OBJECT_TABLE_ELEMENT_SIZE); + ib_pointer += MXT_OBJECT_TABLE_ELEMENT_SIZE; + + object_type = buf[0]; + object_address = (buf[2] << 8) + buf[1]; + object_size = buf[3] + 1; + object_instances = buf[4] + 1; + object_report_ids = buf[5]; + mxt_debug(DEBUG_TRACE, "Type=%03d, Address=0x%04x, " + "Size=0x%02x, %d instances, %d report id's\n", + object_type, + object_address, + object_size, object_instances, object_report_ids); + + /* TODO: check whether object is known and supported? */ + + /* Save frequently needed info. */ + if (object_type == MXT_GEN_MESSAGEPROCESSOR_T5) { + mxt->msg_proc_addr = object_address; + mxt->message_size = object_size; + printk(KERN_ALERT "message length: %d", object_size); + } + + object_table[i].type = object_type; + object_table[i].chip_addr = object_address; + object_table[i].size = object_size; + object_table[i].instances = object_instances; + object_table[i].num_report_ids = object_report_ids; + report_id_count += object_instances * object_report_ids; + + object_info_address += MXT_OBJECT_TABLE_ELEMENT_SIZE; + } + + mxt->rid_map = + kzalloc(sizeof(struct report_id_map) * (report_id_count + 1), + /* allocate for report_id 0, even if not used */ + GFP_KERNEL); + if (mxt->rid_map == NULL) { + printk(KERN_WARNING "maXTouch: Can't allocate memory!\n"); + error = -ENOMEM; + goto err_rid_map_alloc; + } + + mxt->messages = kzalloc(mxt->message_size * MXT_MESSAGE_BUFFER_SIZE, + GFP_KERNEL); + if (mxt->messages == NULL) { + printk(KERN_WARNING "maXTouch: Can't allocate memory!\n"); + error = -ENOMEM; + goto err_msg_alloc; + } + + mxt->last_message = kzalloc(mxt->message_size, GFP_KERNEL); + if (mxt->last_message == NULL) { + printk(KERN_WARNING "maXTouch: Can't allocate memory!\n"); + error = -ENOMEM; + goto err_msg_alloc; + } + + mxt->report_id_count = report_id_count; + if (report_id_count > 254) { /* 0 & 255 are reserved */ + dev_err(&client->dev, + "Too many maXTouch report id's [%d]\n", + report_id_count); + error = -ENXIO; + goto err_max_rid; + } + + /* Create a mapping from report id to object type */ + report_id = 1; /* Start from 1, 0 is reserved. */ + + /* Create table associating report id's with objects & instances */ + for (i = 0; i < mxt->device_info.num_objs; i++) { + for (object_instance = 0; + object_instance < object_table[i].instances; + object_instance++) { + first_report_id = report_id; + for (object_report_id = 0; + object_report_id < object_table[i].num_report_ids; + object_report_id++) { + mxt->rid_map[report_id].object = + object_table[i].type; + mxt->rid_map[report_id].instance = + object_instance; + mxt->rid_map[report_id].first_rid = + first_report_id; + report_id++; + } + } + } + + /* Read 3 byte CRC */ + error = mxt_read_block(client, object_info_address, 3, buf); + if (error < 0) { + mxt->read_fail_counter++; + dev_err(&client->dev, "Error reading CRC\n"); + } + + crc = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + if (calculate_infoblock_crc(&calculated_crc, raw_ib_data, ib_pointer)) { + printk(KERN_WARNING "Error while calculating CRC!\n"); + calculated_crc = 0; + } + kfree(raw_ib_data); + + mxt_debug(DEBUG_TRACE, "\nReported info block CRC = 0x%6X\n", crc); + mxt_debug(DEBUG_TRACE, "Calculated info block CRC = 0x%6X\n\n", + calculated_crc); + + if (crc == calculated_crc) { + mxt->info_block_crc = crc; + } else { + mxt->info_block_crc = 0; + printk(KERN_ALERT "maXTouch: Info block CRC invalid!\n"); + } + + if (debug >= DEBUG_VERBOSE) { + + dev_info(&client->dev, "maXTouch: %d Objects\n", + mxt->device_info.num_objs); + + for (i = 0; i < mxt->device_info.num_objs; i++) { + dev_info(&client->dev, "Type:\t\t\t[%d]: %s\n", + object_table[i].type, + object_type_name[object_table[i].type]); + dev_info(&client->dev, "\tAddress:\t0x%04X\n", + object_table[i].chip_addr); + dev_info(&client->dev, "\tSize:\t\t%d Bytes\n", + object_table[i].size); + dev_info(&client->dev, "\tInstances:\t%d\n", + object_table[i].instances); + dev_info(&client->dev, "\tReport Id's:\t%d\n", + object_table[i].num_report_ids); + } + } + + return 0; + + err_max_rid: + kfree(mxt->last_message); + err_msg_alloc: + kfree(mxt->rid_map); + err_rid_map_alloc: + err_object_read: + kfree(raw_ib_data); + err_ib_alloc: + kfree(object_table); + err_object_table_alloc: + return error; +} + +static int __devinit mxt_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mxt_data *mxt; + struct mxt_platform_data *pdata; + struct input_dev *input; + u8 *id_data; + int error; + + mxt_debug(DEBUG_INFO, "mXT224: mxt_probe\n"); + + if (client == NULL) { + pr_debug("maXTouch: client == NULL\n"); + return -EINVAL; + } else if (client->adapter == NULL) { + pr_debug("maXTouch: client->adapter == NULL\n"); + return -EINVAL; + } else if (&client->dev == NULL) { + pr_debug("maXTouch: client->dev == NULL\n"); + return -EINVAL; + } else if (&client->adapter->dev == NULL) { + pr_debug("maXTouch: client->adapter->dev == NULL\n"); + return -EINVAL; + } else if (id == NULL) { + pr_debug("maXTouch: id == NULL\n"); + return -EINVAL; + } + + mxt_debug(DEBUG_INFO, "maXTouch driver\n"); + mxt_debug(DEBUG_INFO, "\t \"%s\"\n", client->name); + mxt_debug(DEBUG_INFO, "\taddr:\t0x%04x\n", client->addr); + mxt_debug(DEBUG_INFO, "\tirq:\t%d\n", client->irq); + mxt_debug(DEBUG_INFO, "\tflags:\t0x%04x\n", client->flags); + mxt_debug(DEBUG_INFO, "\tadapter:\"%s\"\n", client->adapter->name); + mxt_debug(DEBUG_INFO, "\tdevice:\t\"%s\"\n", client->dev.init_name); + + /* Check if the I2C bus supports BYTE transfer */ + error = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); + dev_info(&client->dev, "RRC: i2c_check_functionality = %i\n", error); + error = 0xff; +/* + if (!error) { + dev_err(&client->dev, "maXTouch driver\n"); + dev_err(&client->dev, "\t \"%s\"\n", client->name); + dev_err(&client->dev, "\taddr:\t0x%04x\n", client->addr); + dev_err(&client->dev, "\tirq:\t%d\n", client->irq); + dev_err(&client->dev, "\tflags:\t0x%04x\n", client->flags); + dev_err(&client->dev, "\tadapter:\"%s\"\n", + client->adapter->name); + dev_err(&client->dev, "\tdevice:\t\"%s\"\n", + client->dev.init_name); + dev_err(&client->dev, "%s adapter not supported\n", + dev_driver_string(&client->adapter->dev)); + return -ENODEV; + } +*/ + mxt_debug(DEBUG_TRACE, "maXTouch driver functionality OK\n"); + + /* Allocate structure - we need it to identify device */ + mxt = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); + if (mxt == NULL) { + dev_err(&client->dev, "insufficient memory\n"); + error = -ENOMEM; + goto err_mxt_alloc; + } + + id_data = kmalloc(MXT_ID_BLOCK_SIZE, GFP_KERNEL); + if (id_data == NULL) { + dev_err(&client->dev, "insufficient memory\n"); + error = -ENOMEM; + goto err_id_alloc; + } + + input = input_allocate_device(); + if (!input) { + dev_err(&client->dev, "error allocating input device\n"); + error = -ENOMEM; + goto err_input_dev_alloc; + } + + /* Initialize Platform data */ + + pdata = client->dev.platform_data; + if (pdata == NULL) { + dev_err(&client->dev, "platform data is required!\n"); + error = -EINVAL; + goto err_pdata; + } + if (debug >= DEBUG_TRACE) + printk(KERN_INFO "Platform OK: pdata = 0x%08x\n", + (unsigned int)pdata); + + mxt->read_fail_counter = 0; + mxt->message_counter = 0; + mxt->max_x_val = pdata->max_x; + mxt->max_y_val = pdata->max_y; + + /* Get data that is defined in board specific code. */ + mxt->init_hw = pdata->init_platform_hw; + mxt->exit_hw = pdata->exit_platform_hw; + mxt->read_chg = pdata->read_chg; + + if (pdata->valid_interrupt != NULL) + mxt->valid_interrupt = pdata->valid_interrupt; + else + mxt->valid_interrupt = mxt_valid_interrupt_dummy; + + if (mxt->init_hw != NULL) + mxt->init_hw(); + + if (debug >= DEBUG_TRACE) + printk(KERN_INFO "maXTouch driver identifying chip\n"); + + if (mxt_identify(client, mxt, id_data) < 0) { + dev_err(&client->dev, "Chip could not be identified\n"); + error = -ENODEV; + goto err_identify; + } + /* Chip is valid and active. */ + if (debug >= DEBUG_TRACE) + printk(KERN_INFO "maXTouch driver allocating input device\n"); + + mxt->client = client; + mxt->input = input; + + INIT_DELAYED_WORK(&mxt->dwork, mxt_worker); + mutex_init(&mxt->debug_mutex); + mutex_init(&mxt->msg_mutex); + mxt_debug(DEBUG_TRACE, "maXTouch driver creating device name\n"); + + snprintf(mxt->phys_name, + sizeof(mxt->phys_name), "%s/input0", dev_name(&client->dev) + ); + input->name = "Atmel maXTouch Touchscreen controller"; + input->phys = mxt->phys_name; + input->id.bustype = BUS_I2C; + input->dev.parent = &client->dev; + + mxt_debug(DEBUG_INFO, "maXTouch name: \"%s\"\n", input->name); + mxt_debug(DEBUG_INFO, "maXTouch phys: \"%s\"\n", input->phys); + mxt_debug(DEBUG_INFO, "maXTouch driver setting abs parameters\n"); + + set_bit(BTN_TOUCH, input->keybit); + + /* Single touch */ + input_set_abs_params(input, ABS_X, 0, mxt->max_x_val, 0, 0); + input_set_abs_params(input, ABS_Y, 0, mxt->max_y_val, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, MXT_MAX_REPORTED_PRESSURE, + 0, 0); + input_set_abs_params(input, ABS_TOOL_WIDTH, 0, MXT_MAX_REPORTED_WIDTH, + 0, 0); + + /* Multitouch */ + input_set_abs_params(input, ABS_MT_POSITION_X, 0, mxt->max_x_val, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, mxt->max_y_val, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_TOUCH_SIZE, + 0, 0); + input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, MXT_MAX_NUM_TOUCHES, + 0, 0); + + __set_bit(EV_ABS, input->evbit); + __set_bit(EV_SYN, input->evbit); + __set_bit(EV_KEY, input->evbit); + + mxt_debug(DEBUG_TRACE, "maXTouch driver setting client data\n"); + i2c_set_clientdata(client, mxt); + mxt_debug(DEBUG_TRACE, "maXTouch driver setting drv data\n"); + input_set_drvdata(input, mxt); + mxt_debug(DEBUG_TRACE, "maXTouch driver input register device\n"); + error = input_register_device(mxt->input); + if (error < 0) { + dev_err(&client->dev, "Failed to register input device\n"); + goto err_register_device; + } + + error = mxt_read_object_table(client, mxt, id_data); + if (error < 0) + goto err_read_ot; + + /* Create debugfs entries. */ + mxt->debug_dir = debugfs_create_dir("maXTouch", NULL); + if (mxt->debug_dir == -ENODEV) { + /* debugfs is not enabled. */ + printk(KERN_WARNING "debugfs not enabled in kernel\n"); + } else if (mxt->debug_dir == NULL) { + printk(KERN_WARNING "error creating debugfs dir\n"); + } else { + mxt_debug(DEBUG_TRACE, "created \"maXTouch\" debugfs dir\n"); + + debugfs_create_file("deltas", S_IRUSR, mxt->debug_dir, mxt, + &delta_fops); + debugfs_create_file("refs", S_IRUSR, mxt->debug_dir, mxt, + &refs_fops); + } + + /* Create character device nodes for reading & writing registers */ + mxt->mxt_class = class_create(THIS_MODULE, "maXTouch_memory"); + /* 2 numbers; one for memory and one for messages */ + error = alloc_chrdev_region(&mxt->dev_num, 0, 2, "maXTouch_memory"); + mxt_debug(DEBUG_VERBOSE, + "device number %d allocated!\n", MAJOR(mxt->dev_num)); + if (error) + printk(KERN_WARNING "Error registering device\n"); + cdev_init(&mxt->cdev, &mxt_memory_fops); + cdev_init(&mxt->cdev_messages, &mxt_message_fops); + + mxt_debug(DEBUG_VERBOSE, "cdev initialized\n"); + mxt->cdev.owner = THIS_MODULE; + mxt->cdev_messages.owner = THIS_MODULE; + + error = cdev_add(&mxt->cdev, mxt->dev_num, 1); + if (error) + printk(KERN_WARNING "Bad cdev\n"); + + error = cdev_add(&mxt->cdev_messages, mxt->dev_num + 1, 1); + if (error) + printk(KERN_WARNING "Bad cdev\n"); + + mxt_debug(DEBUG_VERBOSE, "cdev added\n"); + + device_create(mxt->mxt_class, NULL, MKDEV(MAJOR(mxt->dev_num), 0), NULL, + "maXTouch"); + + device_create(mxt->mxt_class, NULL, MKDEV(MAJOR(mxt->dev_num), 1), NULL, + "maXTouch_messages"); + + mxt->msg_buffer_startp = 0; + mxt->msg_buffer_endp = 0; + + /* Allocate the interrupt */ + mxt_debug(DEBUG_TRACE, "maXTouch driver allocating interrupt...\n"); + mxt->irq = client->irq; + mxt->valid_irq_counter = 0; + mxt->invalid_irq_counter = 0; + mxt->irq_counter = 0; + if (mxt->irq) { + /* Try to request IRQ with falling edge first. This is + * not always supported. If it fails, try with any edge. */ + error = request_irq(mxt->irq, + mxt_irq_handler, + IRQF_TRIGGER_FALLING, + client->dev.driver->name, mxt); + if (error < 0) { + /* TODO: why only 0 works on STK1000? */ + error = request_irq(mxt->irq, + mxt_irq_handler, + 0, client->dev.driver->name, mxt); + } + + if (error < 0) { + dev_err(&client->dev, + "failed to allocate irq %d\n", mxt->irq); + goto err_irq; + } + } + + if (debug > DEBUG_INFO) + dev_info(&client->dev, "touchscreen, irq %d\n", mxt->irq); + + /* Schedule a worker routine to read any messages that might have + * been sent before interrupts were enabled. */ + cancel_delayed_work(&mxt->dwork); + schedule_delayed_work(&mxt->dwork, 0); + kfree(id_data); + + /* + TODO: REMOVE!!!!!!!!!!!!!!!!!!!!!!! + + REMOVE!!!!!!!!!!!!!!!!!!!!!!! + */ + mxt_write_byte(mxt->client, + MXT_BASE_ADDR(MXT_TOUCH_MULTITOUCHSCREEN_T9, mxt), 15); + + return 0; + + err_irq: + kfree(mxt->rid_map); + kfree(mxt->object_table); + kfree(mxt->last_message); + err_read_ot: + err_register_device: + err_identify: + err_pdata: + input_free_device(input); + err_input_dev_alloc: + kfree(id_data); + err_id_alloc: + if (mxt->exit_hw != NULL) + mxt->exit_hw(); + kfree(mxt); + err_mxt_alloc: + return error; +} + +static int __devexit mxt_remove(struct i2c_client *client) +{ + struct mxt_data *mxt; + + mxt = i2c_get_clientdata(client); + + /* Remove debug dir entries */ + debugfs_remove_recursive(mxt->debug_dir); + + if (mxt != NULL) { + + if (mxt->exit_hw != NULL) + mxt->exit_hw(); + + if (mxt->irq) + free_irq(mxt->irq, mxt); + + unregister_chrdev_region(mxt->dev_num, 2); + device_destroy(mxt->mxt_class, MKDEV(MAJOR(mxt->dev_num), 0)); + device_destroy(mxt->mxt_class, MKDEV(MAJOR(mxt->dev_num), 1)); + cdev_del(&mxt->cdev); + cdev_del(&mxt->cdev_messages); + cancel_delayed_work_sync(&mxt->dwork); + input_unregister_device(mxt->input); + class_destroy(mxt->mxt_class); + debugfs_remove(mxt->debug_dir); + + kfree(mxt->rid_map); + kfree(mxt->object_table); + kfree(mxt->last_message); + } + kfree(mxt); + + i2c_set_clientdata(client, NULL); + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "Touchscreen unregistered\n"); + + return 0; +} + +#if defined(CONFIG_PM) +static int mxt_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct mxt_data *mxt = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev)) + enable_irq_wake(mxt->irq); + + return 0; +} + +static int mxt_resume(struct i2c_client *client) +{ + struct mxt_data *mxt = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev)) + disable_irq_wake(mxt->irq); + + return 0; +} +#else +#define mxt_suspend NULL +#define mxt_resume NULL +#endif + +static const struct i2c_device_id mxt_idtable[] = { + {"maXTouch", 0,}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mxt_idtable); + +static struct i2c_driver mxt_driver = { + .driver = { + .name = "maXTouch", + .owner = THIS_MODULE, + }, + + .id_table = mxt_idtable, + .probe = mxt_probe, + .remove = __devexit_p(mxt_remove), + .suspend = mxt_suspend, + .resume = mxt_resume, + +}; + +static int __init mxt_init(void) +{ + int err; + err = i2c_add_driver(&mxt_driver); + if (err) { + printk(KERN_WARNING "Adding maXTouch driver failed " + "(errno = %d)\n", err); + } else { + mxt_debug(DEBUG_TRACE, "Successfully added driver %s\n", + mxt_driver.driver.name); + } + return err; +} + +static void __exit mxt_cleanup(void) +{ + i2c_del_driver(&mxt_driver); +} + +module_init(mxt_init); +module_exit(mxt_cleanup); + +MODULE_AUTHOR("Iiro Valkonen"); +MODULE_DESCRIPTION("Driver for Atmel maXTouch Touchscreen Controller"); +MODULE_LICENSE("GPL"); |