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(®_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, ®_access, sizeof(reg_access)))
+ ret = -EFAULT;
+ break;
+ case AD7160_RAW_IOCSREG:
+ if (copy_from_user(®_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