Title: [9016] trunk: [#6066] AD7160 Linux Driver Support
Revision
9016
Author
hennerich
Date
2010-07-27 11:53:33 -0400 (Tue, 27 Jul 2010)

Log Message

[#6066] AD7160 Linux Driver Support
Implement haptic feedback support
There are two new sysfs entries:
-timed_haptic: turns the actuator ON for Xms  
-effect_haptic: Runs predefined haptic effects [1..6]  

Modified Paths

Diff

Modified: trunk/drivers/input/touchscreen/ad7160.c (9015 => 9016)


--- trunk/drivers/input/touchscreen/ad7160.c	2010-07-27 08:36:49 UTC (rev 9015)
+++ trunk/drivers/input/touchscreen/ad7160.c	2010-07-27 15:53:33 UTC (rev 9016)
@@ -14,6 +14,7 @@
 #include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/hrtimer.h>
 #include <asm/unaligned.h>
 
 #include <linux/input/ad7160.h>
@@ -51,13 +52,17 @@
 #define AD7160_MTL_OFFS_ADJUST_BUSY		(1 << 30)
 #define AD7160_SLF_OFFS_ADJUST_BUSY		(1 << 31)
 
-
 /* REV_ID */
 #define AD7160_INTERFACE_REV_ID_SHIFT		0
 #define AD7160_SILICON_REV_ID_SHIFT		16
 #define AD7160_INTERFACE_REV_ID_MASK		0xFFFF
 #define AD7160_SILICON_REV_ID_MASK		0xFFFF
 
+/* HAPTIC_CTRL */
+#define AD7160_HAPTIC_EFFECTS(x)		((x) & 0xF)
+#define AD7160_HAPTIC_EN			(1 << 4)
+#define AD7160_ACTUATOR_EN			(1 << 5)
+
 #define AD7160_STAT_X_OFFS			0
 #define AD7160_STAT_X_MASK			0xFFF
 #define AD7160_STAT_Y_OFFS			12
@@ -73,6 +78,7 @@
 
 #define AD7160_MAX_TRACKING_ID			0x0FFFF
 #define AD7160_TRACKING_ID_FREE			0xF0000
+#define AD7160_MAX_TIMED_HAPTIC_DUR		100000
 
 struct ad7160 {
 	struct ad7160_bus_data	bdata;
@@ -80,6 +86,10 @@
 	struct work_struct	work;
 	struct mutex		mutex;
 	struct ad7160_platform_data *pdata;
+
+	struct hrtimer		timer;
+	struct work_struct	hwork;
+	struct mutex		hmutex;
 	unsigned		disabled:1;	/* P: mutex */
 	unsigned		handle_gest:1;
 
@@ -279,12 +289,18 @@
 static void ad7160_setup(struct ad7160 *ts)
 {
 	int i;
+	u32 *effect_ctl;
 
 	for (i = 0; i < MAX_NUM_FINGERS; i++)
 		ts->tracking_lut[i] = AD7160_TRACKING_ID_FREE;
 
 	ts->tracking_id = 1;
 
+	for (i = AD7160_REG_HAPTIC_EFFECT1_CTRL,
+	     effect_ctl = &ts->pdata->haptic_effect1_ctrl;
+	     i <= AD7160_REG_HAPTIC_EFFECT6_CTRL3; i += 4)
+		ad7160_write(ts, i, *effect_ctl++);
+
 	ad7160_write(ts, AD7160_REG_LPM_CTRL, 0);
 	ad7160_write(ts, AD7160_REG_INT_GEST_EN_CTRL,
 			(ts->pdata->ev_code_tap != 0 ? AD7160_TAP_ENABLE : 0) |
@@ -371,8 +387,100 @@
 
 static DEVICE_ATTR(disable, 0664, ad7160_disable_show, ad7160_disable_store);
 
+static void ad7160_hwork(struct work_struct *work)
+{
+	struct ad7160 *ts = container_of(work, struct ad7160, hwork);
+	ad7160_write(ts, AD7160_REG_HAPTIC_CTRL, 0);
+}
+
+static enum hrtimer_restart ad7160_haptic_timer_func(struct hrtimer *timer)
+{
+	struct ad7160 *ts =
+		container_of(timer, struct ad7160, timer);
+
+	schedule_work(&ts->hwork);
+
+	return HRTIMER_NORESTART;
+}
+
+static ssize_t ad7160_timed_haptic_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ad7160 *ts = dev_get_drvdata(dev);
+	int remaining;
+
+	if (hrtimer_active(&ts->timer)) {
+		ktime_t r = hrtimer_get_remaining(&ts->timer);
+		struct timeval t = ktime_to_timeval(r);
+		remaining = t.tv_sec * 1000 + t.tv_usec / 1000;
+	} else
+		remaining = 0;
+
+	return sprintf(buf, "%d\n", remaining);
+}
+
+static ssize_t ad7160_timed_haptic_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7160 *ts = dev_get_drvdata(dev);
+	unsigned long value;
+	int error;
+
+	error = strict_strtoul(buf, 10, &value);
+	if (error)
+		return error;
+
+	mutex_lock(&ts->hmutex);
+	/* cancel previous timer and wait for the handler to finish.  */
+	hrtimer_cancel(&ts->timer);
+
+	if (value > 0) {
+		if (value > AD7160_MAX_TIMED_HAPTIC_DUR)
+			value = AD7160_MAX_TIMED_HAPTIC_DUR;
+
+		ad7160_write(ts, AD7160_REG_HAPTIC_CTRL, AD7160_ACTUATOR_EN);
+
+		hrtimer_start(&ts->timer,
+			ktime_set(value / 1000, (value % 1000) * 1000000),
+			HRTIMER_MODE_REL);
+	}
+
+	mutex_unlock(&ts->hmutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(timed_haptic, 0664, ad7160_timed_haptic_show, ad7160_timed_haptic_store);
+
+static ssize_t ad7160_effect_haptic_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7160 *ts = dev_get_drvdata(dev);
+	unsigned long value;
+	int error;
+
+	error = strict_strtoul(buf, 10, &value);
+	if (error)
+		return error;
+
+	mutex_lock(&ts->hmutex);
+
+	if ((value > 0) && (value < 16))
+		ad7160_write(ts, AD7160_REG_HAPTIC_CTRL, AD7160_HAPTIC_EFFECTS(value) | AD7160_HAPTIC_EN);
+
+	mutex_unlock(&ts->hmutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(effect_haptic, 0664, NULL, ad7160_effect_haptic_store);
+
 static struct attribute *ad7160_attributes[] = {
 	&dev_attr_disable.attr,
+	&dev_attr_timed_haptic.attr,
+	&dev_attr_effect_haptic.attr,
 	NULL
 };
 
@@ -508,6 +616,12 @@
 		goto err_free_mem;
 	}
 
+
+	INIT_WORK(&ts->hwork, ad7160_hwork);
+	mutex_init(&ts->hmutex);
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = ad7160_haptic_timer_func;
+
 	err = sysfs_create_group(&dev->kobj, &ad7160_attr_group);
 	if (err)
 		goto err_free_irq;

Modified: trunk/include/linux/input/ad7160.h (9015 => 9016)


--- trunk/include/linux/input/ad7160.h	2010-07-27 08:36:49 UTC (rev 9015)
+++ trunk/include/linux/input/ad7160.h	2010-07-27 15:53:33 UTC (rev 9016)
@@ -92,6 +92,38 @@
 	 */
 
 	u32 ev_code_double_tap;
+
+	/*
+	 * The number of pulses varies for each effect. It is possible to
+	 * define the ON and the OFF time of each pulse. The time is defined
+	 * over 7 bits with a resolution of 100uS.
+	 */
+
+#define AD7160_HAPTIC_SLOT_A(x)			(((x) & 0x7F) << 0)
+#define AD7160_HAPTIC_SLOT_B(x)			(((x) & 0x7F) << 8)
+#define AD7160_HAPTIC_SLOT_C(x)			(((x) & 0x7F) << 16)
+#define AD7160_HAPTIC_SLOT_D(x)			(((x) & 0x7F) << 24)
+#define AD7160_HAPTIC_SLOT_A_LVL_HIGH		(1 << 7)
+#define AD7160_HAPTIC_SLOT_B_LVL_HIGH		(1 << 15)
+#define AD7160_HAPTIC_SLOT_C_LVL_HIGH		(1 << 23)
+#define AD7160_HAPTIC_SLOT_D_LVL_HIGH		(1 << 31)
+#define AD7160_HAPTIC_SLOT_A_LVL_LOW		(0 << 7)
+#define AD7160_HAPTIC_SLOT_B_LVL_LOW		(0 << 15)
+#define AD7160_HAPTIC_SLOT_C_LVL_LOW		(0 << 23)
+#define AD7160_HAPTIC_SLOT_D_LVL_LOW		(0 << 31)
+
+	u32 haptic_effect1_ctrl;	/* 2 Slots */
+	u32 haptic_effect2_ctrl;	/* 4 Slots */
+	u32 haptic_effect3_ctrl1;	/* 6 Slots */
+	u32 haptic_effect3_ctrl2;
+	u32 haptic_effect4_ctrl1;	/* 8 Slots */
+	u32 haptic_effect4_ctrl2;
+	u32 haptic_effect5_ctrl1;	/* 10 Slots */
+	u32 haptic_effect5_ctrl2;
+	u32 haptic_effect5_ctrl3;
+	u32 haptic_effect6_ctrl1;	/* 12 Slots */
+	u32 haptic_effect6_ctrl2;
+	u32 haptic_effect6_ctrl3;
 };
 
 struct ad7160_iocreg_access {
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to