Title: [8943] trunk: [#6066] AD7160 Linux Driver Support
Revision
8943
Author
hennerich
Date
2010-06-24 09:47:31 -0400 (Thu, 24 Jun 2010)

Log Message

[#6066] AD7160 Linux Driver Support
Add AD7160 touchscreen optional debug char type interface
for SELF and MUTUAL CDC results

Modified Paths

Added Paths

Diff

Modified: trunk/drivers/input/touchscreen/Kconfig (8942 => 8943)


--- trunk/drivers/input/touchscreen/Kconfig	2010-06-24 10:50:34 UTC (rev 8942)
+++ trunk/drivers/input/touchscreen/Kconfig	2010-06-24 13:47:31 UTC (rev 8943)
@@ -99,6 +99,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7160.
 
+config TOUCHSCREEN_AD7160_RAW
+	tristate "AD7160 based touchscreens raw data interface"
+	depends on TOUCHSCREEN_AD7160
+	help
+	  Say Y here if you have a touchscreen interface using the AD7160
+	  and you want the raw data character interface
+
 config TOUCHSCREEN_BITSY
 	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
 	depends on SA1100_BITSY

Modified: trunk/drivers/input/touchscreen/Makefile (8942 => 8943)


--- trunk/drivers/input/touchscreen/Makefile	2010-06-24 10:50:34 UTC (rev 8942)
+++ trunk/drivers/input/touchscreen/Makefile	2010-06-24 13:47:31 UTC (rev 8943)
@@ -49,3 +49,4 @@
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_AD7160)	+= ad7160.o ad7160-i2c.o
+obj-$(CONFIG_TOUCHSCREEN_AD7160_RAW)	+= ad7160-raw.o

Modified: trunk/drivers/input/touchscreen/ad7160-i2c.c (8942 => 8943)


--- trunk/drivers/input/touchscreen/ad7160-i2c.c	2010-06-24 10:50:34 UTC (rev 8942)
+++ trunk/drivers/input/touchscreen/ad7160-i2c.c	2010-06-24 13:47:31 UTC (rev 8943)
@@ -40,21 +40,21 @@
 {
 	struct i2c_client *client = dev;
 	struct i2c_msg msg[2];
-	u32 block_data[MAX_DATA_CNT];
+	u32 block_data;
 	int ret, icnt;
 
-	block_data[0] = cpu_to_be32(reg);
+	block_data = cpu_to_be32(reg);
 
 	msg[0].addr = client->addr;
 	msg[0].flags = client->flags & I2C_M_TEN;
 	msg[0].len = REG_SIZE_BYTES;
-	msg[0].buf = (char *)block_data;
+	msg[0].buf = (char *)&block_data;
 
 	msg[1].addr = client->addr;
 	msg[1].flags = client->flags & I2C_M_TEN;
 	msg[1].flags |= I2C_M_RD;
 	msg[1].len = len * REG_SIZE_BYTES;
-	msg[1].buf = (char *)block_data;
+	msg[1].buf = (char *)data;
 
 	ret = i2c_transfer(client->adapter, msg, 2);
 	if (ret != 2) {
@@ -63,7 +63,7 @@
 	}
 
 	for (icnt = 0; icnt < len; icnt++)
-		data[icnt] = be32_to_cpu(block_data[icnt]);
+		data[icnt] = be32_to_cpu(data[icnt]);
 
 	return len;
 }
@@ -127,17 +127,29 @@
 static int __devinit ad7160_i2c_probe(struct i2c_client *client,
 				      const struct i2c_device_id *id)
 {
+	int ret;
 	struct ad7160_bus_data bdata = {
 		.client = client,
 		.irq = client->irq,
 		.bops = &bops,
 	};
 
-	return ad7160_probe(&client->dev, &bdata, AD7160_DEVID, BUS_I2C);
+	ret = ad7160_probe(&client->dev, &bdata, AD7160_DEVID, BUS_I2C);
+	if (ret < 0)
+		return ret;
+
+	ret = ad7160_probe_raw(&client->dev, &bdata, AD7160_DEVID, BUS_I2C);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to add raw data interface\n");
+		ad7160_remove(&client->dev);
+	}
+
+	return ret;
 }
 
 static int __devexit ad7160_i2c_remove(struct i2c_client *client)
 {
+	ad7160_remove_raw(&client->dev);
 	return ad7160_remove(&client->dev);
 }
 

Added: trunk/drivers/input/touchscreen/ad7160-raw.c (0 => 8943)


--- trunk/drivers/input/touchscreen/ad7160-raw.c	                        (rev 0)
+++ trunk/drivers/input/touchscreen/ad7160-raw.c	2010-06-24 13:47:31 UTC (rev 8943)
@@ -0,0 +1,303 @@
+/*
+ * AD7160 touchscreen optional debug char type interface
+ * for SELF and MUTUAL CDC results
+ *
+ * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/input/ad7160.h>
+#include "ad7160.h"
+
+/* Self CDC Result */
+#define AFE_SLF_CDCVAL0		0x40051A00
+#define MAX_NUM_SLF_CDC		28
+/* Mutual CDC Results */
+#define AFE_MTL_CDCVAL0		0x40051B80
+#define MAX_NUM_MTL_CDC		182
+
+#define AD7160_RAW_JUNK_SIZE	((MAX_NUM_SLF_CDC + MAX_NUM_MTL_CDC) * sizeof(unsigned int))
+#define AD7160_RAW_FIFO_SIZE	(10 * AD7160_RAW_JUNK_SIZE)
+
+#define MAX_I2C_READNUM		63	/* Some I2C adaptors limitation */
+
+/* NOTE:
+ * It's assumed that only one instance of this driver,
+ * with only one user is running the same time.
+ * So it's ok to use global data structures
+ */
+
+static struct ad7160_raw_device {
+	struct ad7160_bus_data	bdata;
+	struct mutex lock;
+	struct kfifo fifo;
+	spinlock_t fifo_lock;
+	wait_queue_head_t waitq;
+	struct fasync_struct *fifo_async;
+	int open:1;	/* lock */
+	unsigned int *buffer;
+} ad7160_raw_device;
+
+static int ad7160_read_multi(u32 reg, u32 len, u32 *data)
+{
+	unsigned readnum, count = 0;
+	int ret;
+
+	do {
+		if (len > (count + MAX_I2C_READNUM))
+			readnum = MAX_I2C_READNUM;
+		else
+			readnum = len - count;
+
+		ret = ad7160_raw_device.bdata.bops->multi_read(
+				ad7160_raw_device.bdata.client,
+				reg + count,
+				readnum,
+				&data[count]);
+		count += readnum;
+
+	} while (count < len);
+
+	return ret;
+}
+
+void ad7160_feed_raw(void)
+{
+	int ret;
+
+	if (!ad7160_raw_device.open)
+		return;
+
+	ret = ad7160_read_multi(AFE_SLF_CDCVAL0,
+			MAX_NUM_SLF_CDC,
+			&ad7160_raw_device.buffer[0]);
+
+	ret = ad7160_read_multi(AFE_MTL_CDCVAL0,
+			MAX_NUM_MTL_CDC,
+			&ad7160_raw_device.buffer[MAX_NUM_SLF_CDC]);
+
+	mutex_lock(&ad7160_raw_device.lock);
+	ret = kfifo_in(&ad7160_raw_device.fifo,
+			&ad7160_raw_device.buffer[0],
+			AD7160_RAW_JUNK_SIZE);
+
+	if (ret != AD7160_RAW_JUNK_SIZE) {
+		printk(KERN_ERR "FIFO Buffer Overflow: failed to put %lu bytes,"
+		 "fifo reached %d\n Resetting FIFO\n",
+		 AD7160_RAW_JUNK_SIZE - ret,
+		 kfifo_len(&ad7160_raw_device.fifo));
+
+		 kfifo_reset(&ad7160_raw_device.fifo);
+		 kfifo_in(&ad7160_raw_device.fifo,
+			&ad7160_raw_device.buffer[0],
+			AD7160_RAW_JUNK_SIZE);
+	}
+
+	kill_fasync(&ad7160_raw_device.fifo_async, SIGIO, POLL_IN);
+	wake_up_interruptible(&ad7160_raw_device.waitq);
+	mutex_unlock(&ad7160_raw_device.lock);
+
+	return;
+}
+
+static int ad7160_raw_misc_fasync(int fd, struct file *filp, int on)
+{
+	return fasync_helper(fd, filp, on, &ad7160_raw_device.fifo_async);
+}
+
+static int ad7160_raw_misc_release(struct inode *inode, struct file *file)
+{
+	mutex_lock(&ad7160_raw_device.lock);
+	ad7160_raw_device.open = false;
+	mutex_unlock(&ad7160_raw_device.lock);
+
+	return 0;
+}
+
+static int ad7160_raw_misc_open(struct inode *inode, struct file *file)
+{
+	mutex_lock(&ad7160_raw_device.lock);
+	/* Flush input queue on open */
+	kfifo_reset(&ad7160_raw_device.fifo);
+	ad7160_raw_device.open = true;
+	mutex_unlock(&ad7160_raw_device.lock);
+
+	return 0;
+}
+
+static ssize_t ad7160_raw_misc_read(struct file *file, char __user *buf,
+				size_t count, loff_t *pos)
+{
+	ssize_t ret;
+	unsigned int copied;
+
+	if ((kfifo_len(&ad7160_raw_device.fifo) == 0) &&
+	    (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	ret = wait_event_interruptible(ad7160_raw_device.waitq,
+				kfifo_len(&ad7160_raw_device.fifo) >=
+				AD7160_RAW_JUNK_SIZE);
+	if (ret)
+		return ret;
+
+	if (mutex_lock_interruptible(&ad7160_raw_device.lock))
+		return -ERESTARTSYS;
+
+	ret = kfifo_to_user(&ad7160_raw_device.fifo, buf, count, &copied);
+
+	mutex_unlock(&ad7160_raw_device.lock);
+
+	if (ret > 0) {
+		struct inode *inode = file->f_path.dentry->d_inode;
+		inode->i_atime = current_fs_time(inode->i_sb);
+	}
+
+	return ret ? ret : copied;
+}
+
+static unsigned int ad7160_raw_misc_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &ad7160_raw_device.waitq, wait);
+	if (kfifo_len(&ad7160_raw_device.fifo))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static long ad7160_raw_misc_ioctl(struct file *fp,
+			     unsigned int cmd, unsigned long arg)
+{
+	long ret = 0;
+	void __user *argp = (void __user *)arg;
+	s32 val32;
+
+	struct ad7160_iocreg_access reg_access;
+
+	mutex_lock(&ad7160_raw_device.lock);
+	switch (cmd) {
+	case AD7160_RAW_IOCGREG:
+		if (copy_from_user(&reg_access, argp, sizeof(reg_access))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		val32 = ad7160_raw_device.bdata.bops->read(
+				ad7160_raw_device.bdata.client,
+				reg_access.reg);
+
+		if (val32 < 0) {
+			ret = -EIO;
+			break;
+		}
+
+		reg_access.data = ""
+
+		if (copy_to_user(argp, &reg_access, sizeof(reg_access)))
+			ret = -EFAULT;
+		break;
+	case AD7160_RAW_IOCSREG:
+		if (copy_from_user(&reg_access, argp, sizeof(reg_access))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (ad7160_raw_device.bdata.bops->write(
+				ad7160_raw_device.bdata.client,
+				reg_access.reg,
+				reg_access.data) < 0) {
+			ret = -EIO;
+			break;
+		}
+		break;
+	case AD7160_RAW_IOCGJUNKSIZE:
+		val32 = AD7160_RAW_JUNK_SIZE;
+		if (copy_to_user(argp, &val32, sizeof(val32)))
+			ret = -EFAULT;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&ad7160_raw_device.lock);
+	return ret;
+}
+
+static const struct file_operations ad7160_raw_misc_fops = {
+	.owner		= THIS_MODULE,
+	.read		= ad7160_raw_misc_read,
+	.poll		= ad7160_raw_misc_poll,
+	.open		= ad7160_raw_misc_open,
+	.release	= ad7160_raw_misc_release,
+	.fasync		= ad7160_raw_misc_fasync,
+	.unlocked_ioctl	= ad7160_raw_misc_ioctl,
+	.llseek		= no_llseek,
+};
+
+static struct miscdevice ad7160_raw_misc_device = {
+	.minor		= MISC_DYNAMIC_MINOR,
+	.name		= "ad7160_raw",
+	.fops		= &ad7160_raw_misc_fops,
+};
+
+__devinit int
+ad7160_probe_raw(struct device *dev, struct ad7160_bus_data *bdata,
+		u32 devid, u16 bustype)
+{
+	int error;
+
+	spin_lock_init(&ad7160_raw_device.fifo_lock);
+	error = kfifo_alloc(&ad7160_raw_device.fifo, AD7160_RAW_FIFO_SIZE, GFP_KERNEL);
+	if (error) {
+		printk(KERN_ERR "ad7160_raw: kfifo_alloc failed\n");
+		return error;
+	}
+
+	ad7160_raw_device.buffer = kzalloc(AD7160_RAW_JUNK_SIZE, GFP_KERNEL);
+	if (ad7160_raw_device.buffer == NULL) {
+		printk(KERN_ERR "ad7160_raw: buffer alloc failed\n");
+		goto err_kfifo_free;
+	}
+
+	init_waitqueue_head(&ad7160_raw_device.waitq);
+	mutex_init(&ad7160_raw_device.lock);
+
+	ad7160_raw_device.bdata = *bdata;
+
+	error = misc_register(&ad7160_raw_misc_device);
+	if (error) {
+		printk(KERN_ERR "ad7160_raw: misc_register failed\n");
+		goto err_free_buffer;
+	}
+
+	return 0;
+
+ err_free_buffer:
+	kfree(ad7160_raw_device.buffer);
+ err_kfifo_free:
+	kfifo_free(&ad7160_raw_device.fifo);
+
+	return error;
+}
+
+__devexit int ad7160_remove_raw(struct device *dev)
+{
+	misc_deregister(&ad7160_raw_misc_device);
+	kfifo_free(&ad7160_raw_device.fifo);
+	kfree(ad7160_raw_device.buffer);
+
+	return 0;
+}

Modified: trunk/drivers/input/touchscreen/ad7160.c (8942 => 8943)


--- trunk/drivers/input/touchscreen/ad7160.c	2010-06-24 10:50:34 UTC (rev 8942)
+++ trunk/drivers/input/touchscreen/ad7160.c	2010-06-24 13:47:31 UTC (rev 8943)
@@ -297,6 +297,7 @@
 	}
 
 	ad7160_report(ts);
+	ad7160_feed_raw();
 }
 
 static irqreturn_t ad7160_irq(int irq, void *handle)

Modified: trunk/drivers/input/touchscreen/ad7160.h (8942 => 8943)


--- trunk/drivers/input/touchscreen/ad7160.h	2010-06-24 10:50:34 UTC (rev 8942)
+++ trunk/drivers/input/touchscreen/ad7160.h	2010-06-24 13:47:31 UTC (rev 8943)
@@ -33,8 +33,24 @@
 int ad7160_probe(struct device *dev, struct ad7160_bus_data *bdata, u32 devid, u16 bustype);
 int ad7160_remove(struct device *dev);
 
-#ifdef	CONFIG_AD7160_RAW_DATA_IFACE
-void ad7160_do_raw_data(struct ad7160_bus_data *bdata);
-#endif
+#ifdef CONFIG_TOUCHSCREEN_AD7160_RAW
+int ad7160_probe_raw(struct device *dev, struct ad7160_bus_data *bdata, u32 devid, u16 bustype);
+int ad7160_remove_raw(struct device *dev);
+void ad7160_feed_raw(void);
+#else
+static inline void ad7160_feed_raw(void)
+{
+}
 
-#endif
+static inline int ad7160_probe_raw(struct device *dev, struct ad7160_bus_data *bdata, u32 devid, u16 bustype)
+{
+	return 0;
+}
+
+static inline int ad7160_remove_raw(struct device *dev)
+{
+	return 0;
+}
+
+#endif /* CONFIG_AD7160_RAW_DATA_IFACE */
+#endif /* _AD7160_H_ */

Modified: trunk/include/linux/input/ad7160.h (8942 => 8943)


--- trunk/include/linux/input/ad7160.h	2010-06-24 10:50:34 UTC (rev 8942)
+++ trunk/include/linux/input/ad7160.h	2010-06-24 13:47:31 UTC (rev 8943)
@@ -13,6 +13,8 @@
 #ifndef __LINUX_INPUT_AD7160_H__
 #define __LINUX_INPUT_AD7160_H__
 
+#include <linux/types.h>
+
 struct ad7160_platform_data {
 	u32 sensor_x_res;
 	u32 sensor_y_res;
@@ -91,4 +93,14 @@
 
 	u32 ev_code_double_tap;
 };
+
+struct ad7160_iocreg_access {
+	__u32 reg;
+	__u32 data;
+} __attribute__ ((packed));
+
+#define AD7160_RAW_IOCSREG	_IOW('o', 1, struct ad7160_iocreg_access)
+#define AD7160_RAW_IOCGREG	_IOR('o', 2, struct ad7160_iocreg_access)
+#define AD7160_RAW_IOCGJUNKSIZE	_IOR('o', 3, unsigned int)
+
 #endif
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to