Browse Source

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: update multi-touch protocol documentation
  Input: add the ABS_MT_PRESSURE event
  Input: winbond-cir - remove dmesg spam
  Input: lifebook - add another Lifebook DMI signature
  Input: ad7879 - support auxiliary GPIOs via gpiolib
Linus Torvalds 15 years ago
parent
commit
499a267371

+ 40 - 8
Documentation/input/multi-touch-protocol.txt

@@ -27,12 +27,30 @@ set of events/packets.
 
 
 A set of ABS_MT events with the desired properties is defined. The events
 A set of ABS_MT events with the desired properties is defined. The events
 are divided into categories, to allow for partial implementation.  The
 are divided into categories, to allow for partial implementation.  The
-minimum set consists of ABS_MT_TOUCH_MAJOR, ABS_MT_POSITION_X and
-ABS_MT_POSITION_Y, which allows for multiple fingers to be tracked.  If the
-device supports it, the ABS_MT_WIDTH_MAJOR may be used to provide the size
-of the approaching finger. Anisotropy and direction may be specified with
-ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MINOR and ABS_MT_ORIENTATION.  The
-ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a
+minimum set consists of ABS_MT_POSITION_X and ABS_MT_POSITION_Y, which
+allows for multiple fingers to be tracked.  If the device supports it, the
+ABS_MT_TOUCH_MAJOR and ABS_MT_WIDTH_MAJOR may be used to provide the size
+of the contact area and approaching finger, respectively.
+
+The TOUCH and WIDTH parameters have a geometrical interpretation; imagine
+looking through a window at someone gently holding a finger against the
+glass.  You will see two regions, one inner region consisting of the part
+of the finger actually touching the glass, and one outer region formed by
+the perimeter of the finger. The diameter of the inner region is the
+ABS_MT_TOUCH_MAJOR, the diameter of the outer region is
+ABS_MT_WIDTH_MAJOR. Now imagine the person pressing the finger harder
+against the glass. The inner region will increase, and in general, the
+ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR, which is always smaller than
+unity, is related to the finger pressure. For pressure-based devices,
+ABS_MT_PRESSURE may be used to provide the pressure on the contact area
+instead.
+
+In addition to the MAJOR parameters, the oval shape of the finger can be
+described by adding the MINOR parameters, such that MAJOR and MINOR are the
+major and minor axis of an ellipse. Finally, the orientation of the oval
+shape can be describe with the ORIENTATION parameter.
+
+The ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a
 finger or a pen or something else.  Devices with more granular information
 finger or a pen or something else.  Devices with more granular information
 may specify general shapes as blobs, i.e., as a sequence of rectangular
 may specify general shapes as blobs, i.e., as a sequence of rectangular
 shapes grouped together by an ABS_MT_BLOB_ID. Finally, for the few devices
 shapes grouped together by an ABS_MT_BLOB_ID. Finally, for the few devices
@@ -42,11 +60,9 @@ report finger tracking from hardware [5].
 Here is what a minimal event sequence for a two-finger touch would look
 Here is what a minimal event sequence for a two-finger touch would look
 like:
 like:
 
 
-   ABS_MT_TOUCH_MAJOR
    ABS_MT_POSITION_X
    ABS_MT_POSITION_X
    ABS_MT_POSITION_Y
    ABS_MT_POSITION_Y
    SYN_MT_REPORT
    SYN_MT_REPORT
-   ABS_MT_TOUCH_MAJOR
    ABS_MT_POSITION_X
    ABS_MT_POSITION_X
    ABS_MT_POSITION_Y
    ABS_MT_POSITION_Y
    SYN_MT_REPORT
    SYN_MT_REPORT
@@ -87,6 +103,12 @@ the contact. The ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR approximates
 the notion of pressure. The fingers of the hand and the palm all have
 the notion of pressure. The fingers of the hand and the palm all have
 different characteristic widths [1].
 different characteristic widths [1].
 
 
+ABS_MT_PRESSURE
+
+The pressure, in arbitrary units, on the contact area. May be used instead
+of TOUCH and WIDTH for pressure-based devices or any device with a spatial
+signal intensity distribution.
+
 ABS_MT_ORIENTATION
 ABS_MT_ORIENTATION
 
 
 The orientation of the ellipse. The value should describe a signed quarter
 The orientation of the ellipse. The value should describe a signed quarter
@@ -170,6 +192,16 @@ There are a few devices that support trackingID in hardware. User space can
 make use of these native identifiers to reduce bandwidth and cpu usage.
 make use of these native identifiers to reduce bandwidth and cpu usage.
 
 
 
 
+Gestures
+--------
+
+In the specific application of creating gesture events, the TOUCH and WIDTH
+parameters can be used to, e.g., approximate finger pressure or distinguish
+between index finger and thumb. With the addition of the MINOR parameters,
+one can also distinguish between a sweeping finger and a pointing finger,
+and with ORIENTATION, one can detect twisting of fingers.
+
+
 Notes
 Notes
 -----
 -----
 
 

+ 1 - 0
drivers/input/input.c

@@ -46,6 +46,7 @@ static unsigned int input_abs_bypass_init_data[] __initdata = {
 	ABS_MT_TOOL_TYPE,
 	ABS_MT_TOOL_TYPE,
 	ABS_MT_BLOB_ID,
 	ABS_MT_BLOB_ID,
 	ABS_MT_TRACKING_ID,
 	ABS_MT_TRACKING_ID,
+	ABS_MT_PRESSURE,
 	0
 	0
 };
 };
 static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
 static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];

+ 1 - 1
drivers/input/misc/winbond-cir.c

@@ -768,7 +768,7 @@ wbcir_parse_rc6(struct device *dev, struct wbcir_data *data)
 		return;
 		return;
 	}
 	}
 
 
-	dev_info(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X "
+	dev_dbg(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X "
 		"toggle %u mode %u scan 0x%08X\n",
 		"toggle %u mode %u scan 0x%08X\n",
 		address,
 		address,
 		command,
 		command,

+ 6 - 0
drivers/input/mouse/lifebook.c

@@ -50,6 +50,12 @@ static const struct dmi_system_id __initconst lifebook_dmi_table[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"),
 		},
 		},
 	},
 	},
+	{
+		/* LifeBook B */
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Lifebook B Series"),
+		},
+	},
 	{
 	{
 		/* LifeBook B */
 		/* LifeBook B */
 		.matches = {
 		.matches = {

+ 141 - 56
drivers/input/touchscreen/ad7879.c

@@ -47,6 +47,7 @@
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
+#include <linux/gpio.h>
 
 
 #include <linux/spi/ad7879.h>
 #include <linux/spi/ad7879.h>
 
 
@@ -132,7 +133,9 @@ struct ad7879 {
 	struct input_dev	*input;
 	struct input_dev	*input;
 	struct work_struct	work;
 	struct work_struct	work;
 	struct timer_list	timer;
 	struct timer_list	timer;
-
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip	gc;
+#endif
 	struct mutex		mutex;
 	struct mutex		mutex;
 	unsigned		disabled:1;	/* P: mutex */
 	unsigned		disabled:1;	/* P: mutex */
 
 
@@ -150,11 +153,9 @@ struct ad7879 {
 	u8			median;
 	u8			median;
 	u16			x_plate_ohms;
 	u16			x_plate_ohms;
 	u16			pressure_max;
 	u16			pressure_max;
-	u16			gpio_init;
 	u16			cmd_crtl1;
 	u16			cmd_crtl1;
 	u16			cmd_crtl2;
 	u16			cmd_crtl2;
 	u16			cmd_crtl3;
 	u16			cmd_crtl3;
-	unsigned		gpio:1;
 };
 };
 
 
 static int ad7879_read(bus_device *, u8);
 static int ad7879_read(bus_device *, u8);
@@ -237,24 +238,6 @@ static irqreturn_t ad7879_irq(int irq, void *handle)
 
 
 static void ad7879_setup(struct ad7879 *ts)
 static void ad7879_setup(struct ad7879 *ts)
 {
 {
-	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
-			AD7879_XPLUS_BIT |
-			AD7879_Z2_BIT |
-			AD7879_Z1_BIT |
-			AD7879_TEMPMASK_BIT |
-			AD7879_AUXVBATMASK_BIT |
-			AD7879_GPIOALERTMASK_BIT;
-
-	ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
-			AD7879_AVG(ts->averaging) |
-			AD7879_MFS(ts->median) |
-			AD7879_FCD(ts->first_conversion_delay) |
-			ts->gpio_init;
-
-	ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
-			AD7879_ACQ(ts->acquisition_time) |
-			AD7879_TMR(ts->pen_down_acc_interval);
-
 	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
 	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
 	ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
 	ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
 	ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
 	ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
@@ -324,48 +307,132 @@ static ssize_t ad7879_disable_store(struct device *dev,
 
 
 static DEVICE_ATTR(disable, 0664, ad7879_disable_show, ad7879_disable_store);
 static DEVICE_ATTR(disable, 0664, ad7879_disable_show, ad7879_disable_store);
 
 
-static ssize_t ad7879_gpio_show(struct device *dev,
-				     struct device_attribute *attr, char *buf)
+static struct attribute *ad7879_attributes[] = {
+	&dev_attr_disable.attr,
+	NULL
+};
+
+static const struct attribute_group ad7879_attr_group = {
+	.attrs = ad7879_attributes,
+};
+
+#ifdef CONFIG_GPIOLIB
+static int ad7879_gpio_direction_input(struct gpio_chip *chip,
+					unsigned gpio)
 {
 {
-	struct ad7879 *ts = dev_get_drvdata(dev);
+	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	int err;
 
 
-	return sprintf(buf, "%u\n", ts->gpio);
+	mutex_lock(&ts->mutex);
+	ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
+	err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	mutex_unlock(&ts->mutex);
+
+	return err;
 }
 }
 
 
-static ssize_t ad7879_gpio_store(struct device *dev,
-				     struct device_attribute *attr,
-				     const char *buf, size_t count)
+static int ad7879_gpio_direction_output(struct gpio_chip *chip,
+					unsigned gpio, int level)
 {
 {
-	struct ad7879 *ts = dev_get_drvdata(dev);
-	unsigned long val;
-	int error;
+	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	int err;
 
 
-	error = strict_strtoul(buf, 10, &val);
-	if (error)
-		return error;
+	mutex_lock(&ts->mutex);
+	ts->cmd_crtl2 &= ~AD7879_GPIODIR;
+	ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIOPOL;
+	if (level)
+		ts->cmd_crtl2 |= AD7879_GPIO_DATA;
+	else
+		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
+
+	err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	mutex_unlock(&ts->mutex);
+
+	return err;
+}
+
+static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	u16 val;
 
 
 	mutex_lock(&ts->mutex);
 	mutex_lock(&ts->mutex);
-	ts->gpio = !!val;
-	error = ad7879_write(ts->bus, AD7879_REG_CTRL2,
-			   ts->gpio ?
-				ts->cmd_crtl2 & ~AD7879_GPIO_DATA :
-				ts->cmd_crtl2 | AD7879_GPIO_DATA);
+	val = ad7879_read(ts->bus, AD7879_REG_CTRL2);
 	mutex_unlock(&ts->mutex);
 	mutex_unlock(&ts->mutex);
 
 
-	return error ? : count;
+	return !!(val & AD7879_GPIO_DATA);
 }
 }
 
 
-static DEVICE_ATTR(gpio, 0664, ad7879_gpio_show, ad7879_gpio_store);
+static void ad7879_gpio_set_value(struct gpio_chip *chip,
+				  unsigned gpio, int value)
+{
+	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
 
 
-static struct attribute *ad7879_attributes[] = {
-	&dev_attr_disable.attr,
-	&dev_attr_gpio.attr,
-	NULL
-};
+	mutex_lock(&ts->mutex);
+	if (value)
+		ts->cmd_crtl2 |= AD7879_GPIO_DATA;
+	else
+		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
 
 
-static const struct attribute_group ad7879_attr_group = {
-	.attrs = ad7879_attributes,
-};
+	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	mutex_unlock(&ts->mutex);
+}
+
+static int __devinit ad7879_gpio_add(struct device *dev)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+	struct ad7879_platform_data *pdata = dev->platform_data;
+	int ret = 0;
+
+	if (pdata->gpio_export) {
+		ts->gc.direction_input = ad7879_gpio_direction_input;
+		ts->gc.direction_output = ad7879_gpio_direction_output;
+		ts->gc.get = ad7879_gpio_get_value;
+		ts->gc.set = ad7879_gpio_set_value;
+		ts->gc.can_sleep = 1;
+		ts->gc.base = pdata->gpio_base;
+		ts->gc.ngpio = 1;
+		ts->gc.label = "AD7879-GPIO";
+		ts->gc.owner = THIS_MODULE;
+		ts->gc.dev = dev;
+
+		ret = gpiochip_add(&ts->gc);
+		if (ret)
+			dev_err(dev, "failed to register gpio %d\n",
+				ts->gc.base);
+	}
+
+	return ret;
+}
+
+/*
+ * We mark ad7879_gpio_remove inline so there is a chance the code
+ * gets discarded when not needed. We can't do __devinit/__devexit
+ * markup since it is used in both probe and remove methods.
+ */
+static inline void ad7879_gpio_remove(struct device *dev)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+	struct ad7879_platform_data *pdata = dev->platform_data;
+	int ret;
+
+	if (pdata->gpio_export) {
+		ret = gpiochip_remove(&ts->gc);
+		if (ret)
+			dev_err(dev, "failed to remove gpio %d\n",
+				ts->gc.base);
+	}
+}
+#else
+static inline int ad7879_gpio_add(struct device *dev)
+{
+	return 0;
+}
+
+static inline void ad7879_gpio_remove(struct device *dev)
+{
+}
+#endif
 
 
 static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 {
 {
@@ -403,12 +470,6 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
 	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
 	ts->median = pdata->median;
 	ts->median = pdata->median;
 
 
-	if (pdata->gpio_output)
-		ts->gpio_init = AD7879_GPIO_EN |
-				(pdata->gpio_default ? 0 : AD7879_GPIO_DATA);
-	else
-		ts->gpio_init = AD7879_GPIO_EN | AD7879_GPIODIR;
-
 	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev));
 	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev));
 
 
 	input_dev->name = "AD7879 Touchscreen";
 	input_dev->name = "AD7879 Touchscreen";
@@ -446,6 +507,23 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 		goto err_free_mem;
 		goto err_free_mem;
 	}
 	}
 
 
+	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
+			AD7879_XPLUS_BIT |
+			AD7879_Z2_BIT |
+			AD7879_Z1_BIT |
+			AD7879_TEMPMASK_BIT |
+			AD7879_AUXVBATMASK_BIT |
+			AD7879_GPIOALERTMASK_BIT;
+
+	ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
+			AD7879_AVG(ts->averaging) |
+			AD7879_MFS(ts->median) |
+			AD7879_FCD(ts->first_conversion_delay);
+
+	ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
+			AD7879_ACQ(ts->acquisition_time) |
+			AD7879_TMR(ts->pen_down_acc_interval);
+
 	ad7879_setup(ts);
 	ad7879_setup(ts);
 
 
 	err = request_irq(bus->irq, ad7879_irq,
 	err = request_irq(bus->irq, ad7879_irq,
@@ -460,15 +538,21 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 	if (err)
 	if (err)
 		goto err_free_irq;
 		goto err_free_irq;
 
 
-	err = input_register_device(input_dev);
+	err = ad7879_gpio_add(&bus->dev);
 	if (err)
 	if (err)
 		goto err_remove_attr;
 		goto err_remove_attr;
 
 
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_remove_gpio;
+
 	dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
 	dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
 		 revid >> 8, bus->irq);
 		 revid >> 8, bus->irq);
 
 
 	return 0;
 	return 0;
 
 
+err_remove_gpio:
+	ad7879_gpio_remove(&bus->dev);
 err_remove_attr:
 err_remove_attr:
 	sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
 	sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
 err_free_irq:
 err_free_irq:
@@ -481,6 +565,7 @@ err_free_mem:
 
 
 static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
 static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
 {
 {
+	ad7879_gpio_remove(&bus->dev);
 	ad7879_disable(ts);
 	ad7879_disable(ts);
 	sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
 	sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
 	free_irq(ts->bus->irq, ts);
 	free_irq(ts->bus->irq, ts);

+ 1 - 0
include/linux/input.h

@@ -660,6 +660,7 @@ struct input_absinfo {
 #define ABS_MT_TOOL_TYPE	0x37	/* Type of touching device */
 #define ABS_MT_TOOL_TYPE	0x37	/* Type of touching device */
 #define ABS_MT_BLOB_ID		0x38	/* Group a set of packets as a blob */
 #define ABS_MT_BLOB_ID		0x38	/* Group a set of packets as a blob */
 #define ABS_MT_TRACKING_ID	0x39	/* Unique ID of initiated contact */
 #define ABS_MT_TRACKING_ID	0x39	/* Unique ID of initiated contact */
+#define ABS_MT_PRESSURE		0x3a	/* Pressure on contact area */
 
 
 #define ABS_MAX			0x3f
 #define ABS_MAX			0x3f
 #define ABS_CNT			(ABS_MAX+1)
 #define ABS_CNT			(ABS_MAX+1)

+ 8 - 4
include/linux/spi/ad7879.h

@@ -28,8 +28,12 @@ struct ad7879_platform_data {
 	 * 1 = 4, 2 = 8, 3 = 16 (median > averaging)
 	 * 1 = 4, 2 = 8, 3 = 16 (median > averaging)
 	 */
 	 */
 	u8	median;
 	u8	median;
-	/* 1 = AUX/VBAT/GPIO set to GPIO Output */
-	u8	gpio_output;
-	/* Initial GPIO pin state (valid if gpio_output = 1) */
-	u8	gpio_default;
+	/* 1 = AUX/VBAT/GPIO export GPIO to gpiolib
+	 * requires CONFIG_GPIOLIB
+	 */
+	bool	gpio_export;
+	/* identifies the first GPIO number handled by this chip;
+	 * or, if negative, requests dynamic ID allocation.
+	 */
+	s32	gpio_base;
 };
 };