Kernel  |  3.3

下载     查看原文件
C++程序  |  677行  |  17.36 KB
/*
 * clearpad_tm1217.c - Touch Screen driver for Synaptics Clearpad
 * TM1217 controller
 *
 * Copyright (C) 2008 Intel Corp
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * 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; version 2 of the License.
 *
 * 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; ifnot, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * Questions/Comments/Bug fixes to Ramesh Agarwal (ramesh.agarwal@intel.com)
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/hrtimer.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include "cp_tm1217.h"

#define CPTM1217_DEVICE_NAME		"cptm1217"
#define CPTM1217_DRIVER_NAME		CPTM1217_DEVICE_NAME

#define MAX_TOUCH_SUPPORTED		2
#define TOUCH_SUPPORTED			1
#define SAMPLING_FREQ			80	/* Frequency in HZ */
#define DELAY_BTWIN_SAMPLE		(1000 / SAMPLING_FREQ)
#define WAIT_FOR_RESPONSE		5	/* 5msec just works */
#define MAX_RETRIES			5	/* As above */
#define INCREMENTAL_DELAY		5	/* As above */

/* Regster Definitions */
#define TMA1217_DEV_STATUS		0x13	/* Device Status */
#define TMA1217_INT_STATUS		0x14	/* Interrupt Status */

/* Controller can detect up to 2 possible finger touches.
 * Each finger touch provides  12 bit X Y co-ordinates, the values are split
 * across 2 registers, and an 8 bit  Z value */
#define TMA1217_FINGER_STATE		0x18 /* Finger State */
#define TMA1217_FINGER1_X_HIGHER8	0x19 /* Higher 8 bit of X coordinate */
#define TMA1217_FINGER1_Y_HIGHER8	0x1A /* Higher 8 bit of Y coordinate */
#define TMA1217_FINGER1_XY_LOWER4	0x1B /* Lower 4 bits of X and Y */
#define TMA1217_FINGER1_Z_VALUE		0x1D /* 8 bit Z value for finger 1 */
#define TMA1217_FINGER2_X_HIGHER8	0x1E /* Higher 8 bit of X coordinate */
#define TMA1217_FINGER2_Y_HIGHER8	0x1F /* Higher 8 bit of Y coordinate */
#define TMA1217_FINGER2_XY_LOWER4	0x20 /* Lower 4 bits of X and Y */
#define TMA1217_FINGER2_Z_VALUE		0x22 /* 8 bit Z value for finger 2 */
#define TMA1217_DEVICE_CTRL		0x23 /* Device Control */
#define TMA1217_INTERRUPT_ENABLE	0x24 /* Interrupt Enable */
#define TMA1217_REPORT_MODE		0x2B /* Reporting Mode */
#define TMA1217_MAX_X_LOWER8		0x31 /* Bit 0-7 for Max X */
#define TMA1217_MAX_X_HIGHER4		0x32 /* Bit 8-11 for Max X */
#define TMA1217_MAX_Y_LOWER8		0x33 /* Bit 0-7 for Max Y */
#define TMA1217_MAX_Y_HIGHER4		0x34 /* Bit 8-11 for Max Y */
#define TMA1217_DEVICE_CMD_RESET	0x67 /* Device CMD reg for reset */
#define TMA1217_DEVICE_CMD_REZERO	0x69 /* Device CMD reg for rezero */

#define TMA1217_MANUFACTURER_ID		0x73 /* Manufacturer Id */
#define TMA1217_PRODUCT_FAMILY		0x75 /* Product Family */
#define TMA1217_FIRMWARE_REVISION	0x76 /* Firmware Revision */
#define TMA1217_SERIAL_NO_HIGH		0x7C /* Bit 8-15 of device serial no. */
#define TMA1217_SERIAL_NO_LOW		0x7D /* Bit 0-7 of device serial no. */
#define TMA1217_PRODUCT_ID_START	0x7E /* Start address for 10 byte ID */
#define TMA1217_DEVICE_CAPABILITY	0x8B /* Reporting capability */


/*
 * The touch position structure.
 */
struct touch_state {
	int	x;
	int	y;
	bool button;
};

/* Device Specific info given by the controller */
struct cp_dev_info {
	u16	maxX;
	u16	maxY;
};

/* Vendor related info given by the controller */
struct cp_vendor_info {
	u8	vendor_id;
	u8	product_family;
	u8	firmware_rev;
	u16	serial_no;
};

/*
 * Private structure to store the device details
 */
struct cp_tm1217_device {
	struct i2c_client	*client;
	struct device		*dev;
	struct cp_vendor_info	vinfo;
	struct cp_dev_info	dinfo;
	struct input_dev_info {
		char			phys[32];
		char			name[128];
		struct input_dev	*input;
		struct touch_state	touch;
	} cp_input_info[MAX_TOUCH_SUPPORTED];

	int	thread_running;
	struct mutex	thread_mutex;

	int gpio;
};


/* The following functions are used to read/write registers on the device
 * as per the RMI prorocol. Technically, a page select should be written
 * before doing read/write but since the register offsets are below 0xFF
 * we can use the default value of page which is 0x00
 */
static int cp_tm1217_read(struct cp_tm1217_device *ts,
				u8 *req, int size)
{
	int i, retval;

	/* Send the address */
	retval = i2c_master_send(ts->client, &req[0], 1);
	if (retval != 1) {
		dev_err(ts->dev, "cp_tm1217: I2C send failed\n");
		return retval;
	}
	msleep(WAIT_FOR_RESPONSE);
	for (i = 0; i < MAX_RETRIES; i++) {
		retval = i2c_master_recv(ts->client, &req[1], size);
		if (retval == size) {
			break;
		} else {
			msleep(INCREMENTAL_DELAY);
			dev_dbg(ts->dev, "cp_tm1217: Retry count is %d\n", i);
		}
	}
	if (retval != size)
		dev_err(ts->dev, "cp_tm1217: Read from device failed\n");

	return retval;
}

static int cp_tm1217_write(struct cp_tm1217_device *ts,
				u8 *req, int size)
{
	int retval;

	/* Send the address and the data to be written */
	retval = i2c_master_send(ts->client, &req[0], size + 1);
	if (retval != size + 1) {
		dev_err(ts->dev, "cp_tm1217: I2C write  failed: %d\n", retval);
		return retval;
	}
	/* Wait for the write to complete. TBD why this is required */
	msleep(WAIT_FOR_RESPONSE);

	return size;
}

static int cp_tm1217_mask_interrupt(struct cp_tm1217_device *ts)
{
	u8 req[2];
	int retval;

	req[0] = TMA1217_INTERRUPT_ENABLE;
	req[1] = 0x0;
	retval = cp_tm1217_write(ts, req, 1);
	if (retval != 1)
		return -EIO;

	return 0;
}

static int cp_tm1217_unmask_interrupt(struct cp_tm1217_device *ts)
{
	u8 req[2];
	int retval;

	req[0] = TMA1217_INTERRUPT_ENABLE;
	req[1] = 0xa;
	retval = cp_tm1217_write(ts, req, 1);
	if (retval != 1)
		return -EIO;

	return 0;
}

static void process_touch(struct cp_tm1217_device *ts, int index)
{
	int retval;
	struct input_dev_info *input_info =
		(struct input_dev_info *)&ts->cp_input_info[index];
	u8 xy_data[6];

	if (index == 0)
		xy_data[0] = TMA1217_FINGER1_X_HIGHER8;
	else
		xy_data[0] = TMA1217_FINGER2_X_HIGHER8;

	retval = cp_tm1217_read(ts, xy_data, 5);
	if (retval < 5) {
		dev_err(ts->dev, "cp_tm1217: XY read from device failed\n");
		return;
	}

	/* Note: Currently not using the Z values but may be requried in
	   the future. */
	input_info->touch.x = (xy_data[1] << 4)
					| (xy_data[3] & 0x0F);
	input_info->touch.y = (xy_data[2] << 4)
					| ((xy_data[3] & 0xF0) >> 4);
	input_report_abs(input_info->input, ABS_X, input_info->touch.x);
	input_report_abs(input_info->input, ABS_Y, input_info->touch.y);
	input_sync(input_info->input);
}

static void cp_tm1217_get_data(struct cp_tm1217_device *ts)
{
	u8 req[2];
	int retval, i, finger_touched = 0;

	do {
		req[0] = TMA1217_FINGER_STATE;
		retval = cp_tm1217_read(ts, req, 1);
		if (retval != 1) {
			dev_err(ts->dev,
				"cp_tm1217: Read from device failed\n");
			continue;
		}
		finger_touched = 0;
		/* Start sampling until the pressure is below
		  threshold */
		for (i = 0; i < TOUCH_SUPPORTED; i++) {
			if (req[1] & 0x3) {
				finger_touched++;
				if (ts->cp_input_info[i].touch.button == 0) {
					/* send the button touch event */
					input_report_key(
						ts->cp_input_info[i].input,
						BTN_TOUCH, 1);
					ts->cp_input_info[i].touch.button = 1;
				}
				process_touch(ts, i);
			} else {
				if (ts->cp_input_info[i].touch.button == 1) {
					/* send the button release event */
					input_report_key(
						ts->cp_input_info[i].input,
						BTN_TOUCH, 0);
					input_sync(ts->cp_input_info[i].input);
					ts->cp_input_info[i].touch.button = 0;
				}
			}
			req[1] = req[1] >> 2;
		}
		msleep(DELAY_BTWIN_SAMPLE);
	} while (finger_touched > 0);
}

static irqreturn_t cp_tm1217_sample_thread(int irq, void *handle)
{
	struct cp_tm1217_device *ts = (struct cp_tm1217_device *) handle;
	u8 req[2];
	int retval;

	/* Chedk if another thread is already running */
	mutex_lock(&ts->thread_mutex);
	if (ts->thread_running == 1) {
		mutex_unlock(&ts->thread_mutex);
		return IRQ_HANDLED;
	} else {
		ts->thread_running = 1;
		mutex_unlock(&ts->thread_mutex);
	}

	/* Mask the interrupts */
	retval = cp_tm1217_mask_interrupt(ts);

	/* Read the Interrupt Status register to find the cause of the
	   Interrupt */
	req[0] = TMA1217_INT_STATUS;
	retval = cp_tm1217_read(ts, req, 1);
	if (retval != 1)
		goto exit_thread;

	if (!(req[1] & 0x8))
		goto exit_thread;

	cp_tm1217_get_data(ts);

exit_thread:
	/* Unmask the interrupts before going to sleep */
	retval = cp_tm1217_unmask_interrupt(ts);

	mutex_lock(&ts->thread_mutex);
	ts->thread_running = 0;
	mutex_unlock(&ts->thread_mutex);

	return IRQ_HANDLED;
}

static int cp_tm1217_init_data(struct cp_tm1217_device *ts)
{
	int retval;
	u8	req[2];

	/* Read the vendor id/ fw revision etc. Ignoring return check as this
	   is non critical info  */
	req[0] = TMA1217_MANUFACTURER_ID;
	retval = cp_tm1217_read(ts, req, 1);
	ts->vinfo.vendor_id = req[1];

	req[0] = TMA1217_PRODUCT_FAMILY;
	retval = cp_tm1217_read(ts, req, 1);
	ts->vinfo.product_family = req[1];

	req[0] = TMA1217_FIRMWARE_REVISION;
	retval = cp_tm1217_read(ts, req, 1);
	ts->vinfo.firmware_rev = req[1];

	req[0] = TMA1217_SERIAL_NO_HIGH;
	retval = cp_tm1217_read(ts, req, 1);
	ts->vinfo.serial_no = (req[1] << 8);

	req[0] = TMA1217_SERIAL_NO_LOW;
	retval = cp_tm1217_read(ts, req, 1);
	ts->vinfo.serial_no = ts->vinfo.serial_no | req[1];

	req[0] = TMA1217_MAX_X_HIGHER4;
	retval = cp_tm1217_read(ts, req, 1);
	ts->dinfo.maxX = (req[1] & 0xF) << 8;

	req[0] = TMA1217_MAX_X_LOWER8;
	retval = cp_tm1217_read(ts, req, 1);
	ts->dinfo.maxX = ts->dinfo.maxX | req[1];

	req[0] = TMA1217_MAX_Y_HIGHER4;
	retval = cp_tm1217_read(ts, req, 1);
	ts->dinfo.maxY = (req[1] & 0xF) << 8;

	req[0] = TMA1217_MAX_Y_LOWER8;
	retval = cp_tm1217_read(ts, req, 1);
	ts->dinfo.maxY = ts->dinfo.maxY | req[1];

	return 0;

}

/*
 *	Set up a GPIO for use as the interrupt. We can't simply do this at
 *	boot time because the GPIO drivers themselves may not be around at
 *	boot/firmware set up time to do the work. Instead defer it to driver
 *	detection.
 */

static int cp_tm1217_setup_gpio_irq(struct cp_tm1217_device *ts)
{
	int retval;

	/* Hook up the irq handler */
	retval = gpio_request(ts->gpio, "cp_tm1217_touch");
	if (retval < 0) {
		dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
								retval);
		return retval;
	}

	retval = gpio_direction_input(ts->gpio);
	if (retval < 0) {
		dev_err(ts->dev,
		"cp_tm1217: GPIO direction configuration failed, error %d\n",
								retval);
		gpio_free(ts->gpio);
		return retval;
	}

	retval = gpio_to_irq(ts->gpio);
	if (retval < 0) {
		dev_err(ts->dev, "cp_tm1217: GPIO to IRQ failedi,"
		" error %d\n", retval);
		gpio_free(ts->gpio);
	}
	dev_dbg(ts->dev,
		"cp_tm1217: Got IRQ number is %d for GPIO %d\n",
		retval, ts->gpio);
	return retval;
}

static int cp_tm1217_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct cp_tm1217_device *ts;
	struct input_dev *input_dev;
	struct input_dev_info	*input_info;
	struct cp_tm1217_platform_data *pdata;
	u8 req[2];
	int i, retval;

	/* No pdata is fine - we then use "normal" IRQ mode */

	pdata = client->dev.platform_data;

	ts = kzalloc(sizeof(struct cp_tm1217_device), GFP_KERNEL);
	if (!ts) {
		dev_err(&client->dev,
			"cp_tm1217: Private Device Struct alloc failed\n");
		return -ENOMEM;
	}

	ts->client = client;
	ts->dev = &client->dev;
	i2c_set_clientdata(client, ts);

	ts->thread_running = 0;
	mutex_init(&ts->thread_mutex);

	/* Reset the Controller */
	req[0] = TMA1217_DEVICE_CMD_RESET;
	req[1] = 0x1;
	retval = cp_tm1217_write(ts, req, 1);
	if (retval != 1) {
		dev_err(ts->dev, "cp_tm1217: Controller reset failed\n");
		kfree(ts);
		return -EIO;
	}

	/* Clear up the interrupt status from reset. */
	req[0] = TMA1217_INT_STATUS;
	retval = cp_tm1217_read(ts, req, 1);

	/* Mask all the interrupts */
	retval = cp_tm1217_mask_interrupt(ts);

	/* Read the controller information */
	cp_tm1217_init_data(ts);

	/* The following code will register multiple event devices when
	   multi-pointer is enabled, the code has not been tested
	   with MPX */
	for (i = 0; i < TOUCH_SUPPORTED; i++) {
		input_dev = input_allocate_device();
		if (input_dev == NULL) {
			dev_err(ts->dev,
				"cp_tm1217:Input Device Struct alloc failed\n");
			retval = -ENOMEM;
			goto fail;
		}
		input_info = &ts->cp_input_info[i];
		snprintf(input_info->name, sizeof(input_info->name),
			"cp_tm1217_touchscreen_%d", i);
		input_dev->name = input_info->name;
		snprintf(input_info->phys, sizeof(input_info->phys),
			"%s/input%d", dev_name(&client->dev), i);

		input_dev->phys = input_info->phys;
		input_dev->id.bustype = BUS_I2C;

		input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
		input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);

		input_set_abs_params(input_dev, ABS_X, 0, ts->dinfo.maxX, 0, 0);
		input_set_abs_params(input_dev, ABS_Y, 0, ts->dinfo.maxY, 0, 0);

		retval = input_register_device(input_dev);
		if (retval) {
			dev_err(ts->dev,
				"Input dev registration failed for %s\n",
					input_dev->name);
			input_free_device(input_dev);
			goto fail;
		}
		input_info->input = input_dev;
	}

	/* Setup the reporting mode to send an interrupt only when
	   finger arrives or departs. */
	req[0] = TMA1217_REPORT_MODE;
	req[1] = 0x02;
	retval = cp_tm1217_write(ts, req, 1);

	/* Setup the device to no sleep mode for now and make it configured */
	req[0] = TMA1217_DEVICE_CTRL;
	req[1] = 0x84;
	retval = cp_tm1217_write(ts, req, 1);

	/* Check for the status of the device */
	req[0] = TMA1217_DEV_STATUS;
	retval = cp_tm1217_read(ts, req, 1);
	if (req[1] != 0) {
		dev_err(ts->dev,
			"cp_tm1217: Device Status 0x%x != 0: config failed\n",
			req[1]);

		retval = -EIO;
		goto fail;
	}

	if (pdata && pdata->gpio) {
		ts->gpio = pdata->gpio;
		retval = cp_tm1217_setup_gpio_irq(ts);
	} else
		retval = client->irq;

	if (retval < 0) {
		dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
								retval);
		goto fail;
	}

	client->irq = retval;


	retval = request_threaded_irq(client->irq,
		NULL, cp_tm1217_sample_thread,
		IRQF_TRIGGER_FALLING, "cp_tm1217_touch", ts);
	if (retval < 0) {
		dev_err(ts->dev, "cp_tm1217: Request IRQ error %d\n", retval);
		goto fail_gpio;
	}

	/* Unmask the interrupts */
	retval = cp_tm1217_unmask_interrupt(ts);
	if (retval == 0)
		return 0;

	free_irq(client->irq, ts);
fail_gpio:
	if (ts->gpio)
		gpio_free(ts->gpio);
fail:
	/* Clean up before returning failure */
	for (i = 0; i < TOUCH_SUPPORTED; i++) {
		if (ts->cp_input_info[i].input) {
			input_unregister_device(ts->cp_input_info[i].input);
			input_free_device(ts->cp_input_info[i].input);
		}
	}
	kfree(ts);
	return retval;

}

/*
 * cp_tm1217 suspend
 *
 */
static int cp_tm1217_suspend(struct i2c_client *client, pm_message_t mesg)
{
	struct cp_tm1217_device *ts = i2c_get_clientdata(client);
	u8 req[2];
	int retval;

	/* Put the controller to sleep */
	req[0] = TMA1217_DEVICE_CTRL;
	retval = cp_tm1217_read(ts, req, 1);
	req[1] = (req[1] & 0xF8) | 0x1;
	retval = cp_tm1217_write(ts, req, 1);

	if (device_may_wakeup(&client->dev))
		enable_irq_wake(client->irq);

	return 0;
}

/*
 * cp_tm1217_resume
 *
 */
static int cp_tm1217_resume(struct i2c_client *client)
{
	struct cp_tm1217_device *ts = i2c_get_clientdata(client);
	u8 req[2];
	int retval;

	/* Take the controller out of sleep */
	req[0] = TMA1217_DEVICE_CTRL;
	retval = cp_tm1217_read(ts, req, 1);
	req[1] = (req[1] & 0xF8) | 0x4;
	retval = cp_tm1217_write(ts, req, 1);

	/* Restore the register settings sinc the power to the
	   could have been cut off */

	/* Setup the reporting mode to send an interrupt only when
	   finger arrives or departs. */
	req[0] = TMA1217_REPORT_MODE;
	req[1] = 0x02;
	retval = cp_tm1217_write(ts, req, 1);

	/* Setup the device to no sleep mode for now and make it configured */
	req[0] = TMA1217_DEVICE_CTRL;
	req[1] = 0x84;
	retval = cp_tm1217_write(ts, req, 1);

	/* Setup the interrupt mask */
	retval = cp_tm1217_unmask_interrupt(ts);

	if (device_may_wakeup(&client->dev))
		disable_irq_wake(client->irq);

	return 0;
}

/*
 * cp_tm1217_remove
 *
 */
static int cp_tm1217_remove(struct i2c_client *client)
{
	struct cp_tm1217_device *ts = i2c_get_clientdata(client);
	int i;

	free_irq(client->irq, ts);
	if (ts->gpio)
		gpio_free(ts->gpio);
	for (i = 0; i < TOUCH_SUPPORTED; i++)
		input_unregister_device(ts->cp_input_info[i].input);
	kfree(ts);
	return 0;
}

static struct i2c_device_id cp_tm1217_idtable[] = {
	{ CPTM1217_DEVICE_NAME, 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, cp_tm1217_idtable);

static struct i2c_driver cp_tm1217_driver = {
	.driver = {
		.owner	= THIS_MODULE,
		.name	= CPTM1217_DRIVER_NAME,
	},
	.id_table	= cp_tm1217_idtable,
	.probe		= cp_tm1217_probe,
	.remove		= cp_tm1217_remove,
	.suspend    = cp_tm1217_suspend,
	.resume     = cp_tm1217_resume,
};

static int __init clearpad_tm1217_init(void)
{
	return i2c_add_driver(&cp_tm1217_driver);
}

static void __exit clearpad_tm1217_exit(void)
{
	i2c_del_driver(&cp_tm1217_driver);
}

module_init(clearpad_tm1217_init);
module_exit(clearpad_tm1217_exit);

MODULE_AUTHOR("Ramesh Agarwal <ramesh.agarwal@intel.com>");
MODULE_DESCRIPTION("Synaptics TM1217 TouchScreen Driver");
MODULE_LICENSE("GPL v2");