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: (64 commits)
  Input: tc3589x-keypad - add missing kerneldoc
  Input: ucb1400-ts - switch to using dev_xxx() for diagnostic messages
  Input: ucb1400_ts - convert to threaded IRQ
  Input: ucb1400_ts - drop inline annotations
  Input: usb1400_ts - add __devinit/__devexit section annotations
  Input: ucb1400_ts - set driver owner
  Input: ucb1400_ts - convert to use dev_pm_ops
  Input: psmouse - make sure we do not use stale methods
  Input: evdev - do not block waiting for an event if fd is nonblock
  Input: evdev - if no events and non-block, return EAGAIN not 0
  Input: evdev - only allow reading events if a full packet is present
  Input: add driver for pixcir i2c touchscreens
  Input: samsung-keypad - implement runtime power management support
  Input: tegra-kbc - report wakeup key for some platforms
  Input: tegra-kbc - add device tree bindings
  Input: add driver for AUO In-Cell touchscreens using pixcir ICs
  Input: mpu3050 - configure the sampling method
  Input: mpu3050 - ensure we enable interrupts
  Input: mpu3050 - add of_match table for device-tree probing
  Input: sentelic - document the latest hardware
  ...

Fix up fairly trivial conflicts (device tree matching conflicting with
some independent cleanups) in drivers/input/keyboard/samsung-keypad.c
This commit is contained in:
Linus Torvalds
2012-01-10 10:55:52 -08:00
132 changed files with 5550 additions and 1645 deletions
+1 -12
View File
@@ -217,18 +217,7 @@ static struct platform_driver pm860x_touch_driver = {
.probe = pm860x_touch_probe,
.remove = __devexit_p(pm860x_touch_remove),
};
static int __init pm860x_touch_init(void)
{
return platform_driver_register(&pm860x_touch_driver);
}
module_init(pm860x_touch_init);
static void __exit pm860x_touch_exit(void)
{
platform_driver_unregister(&pm860x_touch_driver);
}
module_exit(pm860x_touch_exit);
module_platform_driver(pm860x_touch_driver);
MODULE_DESCRIPTION("Touchscreen driver for Marvell Semiconductor 88PM860x");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+41
View File
@@ -98,6 +98,19 @@ config TOUCHSCREEN_ATMEL_MXT
To compile this driver as a module, choose M here: the
module will be called atmel_mxt_ts.
config TOUCHSCREEN_AUO_PIXCIR
tristate "AUO in-cell touchscreen using Pixcir ICs"
depends on I2C
depends on GPIOLIB
help
Say Y here if you have a AUO display with in-cell touchscreen
using Pixcir ICs.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called auo-pixcir-ts.
config TOUCHSCREEN_BITSY
tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
depends on SA1100_BITSY
@@ -177,6 +190,16 @@ config TOUCHSCREEN_EETI
To compile this driver as a module, choose M here: the
module will be called eeti_ts.
config TOUCHSCREEN_EGALAX
tristate "EETI eGalax multi-touch panel support"
depends on I2C
help
Say Y here to enable support for I2C connected EETI
eGalax multi-touch panels.
To compile this driver as a module, choose M here: the
module will be called egalax_ts.
config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen"
select SERIO
@@ -435,6 +458,18 @@ config TOUCHSCREEN_UCB1400
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
config TOUCHSCREEN_PIXCIR
tristate "PIXCIR I2C touchscreens"
depends on I2C
help
Say Y here if you have a pixcir i2c touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called pixcir_i2c_ts.
config TOUCHSCREEN_WM831X
tristate "Support for WM831x touchscreen controllers"
depends on MFD_WM831X
@@ -541,6 +576,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- GoTop Super_Q2/GogoPen/PenPower tablets
- JASTEC USB Touch Controller/DigiTech DTR-02U
- Zytronic controllers
- Elo TouchSystems 2700 IntelliTouch
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@@ -620,6 +656,11 @@ config TOUCHSCREEN_USB_JASTEC
bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ELO
default y
bool "Elo TouchSystems 2700 IntelliTouch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_E2I
default y
bool "e2i Touchscreen controller (e.g. from Mimo 740)"
+3
View File
@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
@@ -23,6 +24,7 @@ obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
@@ -39,6 +41,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+8 -9
View File
@@ -488,10 +488,10 @@ static ssize_t ad7877_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
@@ -518,10 +518,10 @@ static ssize_t ad7877_dac_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
@@ -548,10 +548,10 @@ static ssize_t ad7877_gpio3_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
@@ -579,10 +579,10 @@ static ssize_t ad7877_gpio4_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
@@ -853,7 +853,6 @@ static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
static struct spi_driver ad7877_driver = {
.driver = {
.name = "ad7877",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &ad7877_pm,
},
+3 -28
View File
@@ -16,30 +16,6 @@
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
#ifdef CONFIG_PM_SLEEP
static int ad7879_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_suspend(ts);
return 0;
}
static int ad7879_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_resume(ts);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume);
/* All registers are word-sized.
* AD7879 uses a high-byte first convention.
*/
@@ -47,7 +23,7 @@ static int ad7879_i2c_read(struct device *dev, u8 reg)
{
struct i2c_client *client = to_i2c_client(dev);
return swab16(i2c_smbus_read_word_data(client, reg));
return i2c_smbus_read_word_swapped(client, reg);
}
static int ad7879_i2c_multi_read(struct device *dev,
@@ -68,7 +44,7 @@ static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
{
struct i2c_client *client = to_i2c_client(dev);
return i2c_smbus_write_word_data(client, reg, swab16(val));
return i2c_smbus_write_word_swapped(client, reg, val);
}
static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
@@ -119,7 +95,7 @@ static struct i2c_driver ad7879_i2c_driver = {
.driver = {
.name = "ad7879",
.owner = THIS_MODULE,
.pm = &ad7879_i2c_pm,
.pm = &ad7879_pm_ops,
},
.probe = ad7879_i2c_probe,
.remove = __devexit_p(ad7879_i2c_remove),
@@ -141,4 +117,3 @@ module_exit(ad7879_i2c_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:ad7879");
+1 -26
View File
@@ -22,30 +22,6 @@
#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
#define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ)
#ifdef CONFIG_PM_SLEEP
static int ad7879_spi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct ad7879 *ts = spi_get_drvdata(spi);
ad7879_suspend(ts);
return 0;
}
static int ad7879_spi_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct ad7879 *ts = spi_get_drvdata(spi);
ad7879_resume(ts);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ad7879_spi_pm, ad7879_spi_suspend, ad7879_spi_resume);
/*
* ad7879_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done in ad7879_collect().
@@ -174,9 +150,8 @@ static int __devexit ad7879_spi_remove(struct spi_device *spi)
static struct spi_driver ad7879_spi_driver = {
.driver = {
.name = "ad7879",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &ad7879_spi_pm,
.pm = &ad7879_pm_ops,
},
.probe = ad7879_spi_probe,
.remove = __devexit_p(ad7879_spi_remove),
+18 -7
View File
@@ -281,8 +281,11 @@ static void ad7879_close(struct input_dev* input)
__ad7879_disable(ts);
}
void ad7879_suspend(struct ad7879 *ts)
#ifdef CONFIG_PM_SLEEP
static int ad7879_suspend(struct device *dev)
{
struct ad7879 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
if (!ts->suspended && !ts->disabled && ts->input->users)
@@ -291,11 +294,14 @@ void ad7879_suspend(struct ad7879 *ts)
ts->suspended = true;
mutex_unlock(&ts->input->mutex);
}
EXPORT_SYMBOL(ad7879_suspend);
void ad7879_resume(struct ad7879 *ts)
return 0;
}
static int ad7879_resume(struct device *dev)
{
struct ad7879 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
if (ts->suspended && !ts->disabled && ts->input->users)
@@ -304,8 +310,13 @@ void ad7879_resume(struct ad7879 *ts)
ts->suspended = false;
mutex_unlock(&ts->input->mutex);
return 0;
}
EXPORT_SYMBOL(ad7879_resume);
#endif
SIMPLE_DEV_PM_OPS(ad7879_pm_ops, ad7879_suspend, ad7879_resume);
EXPORT_SYMBOL(ad7879_pm_ops);
static void ad7879_toggle(struct ad7879 *ts, bool disable)
{
@@ -340,10 +351,10 @@ static ssize_t ad7879_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct ad7879 *ts = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int error;
error = strict_strtoul(buf, 10, &val);
error = kstrtouint(buf, 10, &val);
if (error)
return error;
+2 -2
View File
@@ -21,8 +21,8 @@ struct ad7879_bus_ops {
int (*write)(struct device *dev, u8 reg, u16 val);
};
void ad7879_suspend(struct ad7879 *);
void ad7879_resume(struct ad7879 *);
extern const struct dev_pm_ops ad7879_pm_ops;
struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
const struct ad7879_bus_ops *bops);
void ad7879_remove(struct ad7879 *);
+5 -4
View File
@@ -602,10 +602,12 @@ static ssize_t ads7846_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct ads7846 *ts = dev_get_drvdata(dev);
unsigned long i;
unsigned int i;
int err;
if (strict_strtoul(buf, 10, &i))
return -EINVAL;
err = kstrtouint(buf, 10, &i);
if (err)
return err;
if (i)
ads7846_disable(ts);
@@ -1424,7 +1426,6 @@ static int __devexit ads7846_remove(struct spi_device *spi)
static struct spi_driver ads7846_driver = {
.driver = {
.name = "ads7846",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &ads7846_pm,
},
+1 -12
View File
@@ -429,18 +429,7 @@ static struct platform_driver atmel_wm97xx_driver = {
.suspend = atmel_wm97xx_suspend,
.resume = atmel_wm97xx_resume,
};
static int __init atmel_wm97xx_init(void)
{
return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe);
}
module_init(atmel_wm97xx_init);
static void __exit atmel_wm97xx_exit(void)
{
platform_driver_unregister(&atmel_wm97xx_driver);
}
module_exit(atmel_wm97xx_exit);
module_platform_driver(atmel_wm97xx_driver);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
+1 -14
View File
@@ -351,20 +351,7 @@ static struct platform_driver atmel_tsadcc_driver = {
.name = "atmel_tsadcc",
},
};
static int __init atmel_tsadcc_init(void)
{
return platform_driver_register(&atmel_tsadcc_driver);
}
static void __exit atmel_tsadcc_exit(void)
{
platform_driver_unregister(&atmel_tsadcc_driver);
}
module_init(atmel_tsadcc_init);
module_exit(atmel_tsadcc_exit);
module_platform_driver(atmel_tsadcc_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atmel TouchScreen Driver");
+652
View File
@@ -0,0 +1,652 @@
/*
* Driver for AUO in-cell touchscreens
*
* Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de>
*
* loosely based on auo_touch.c from Dell Streak vendor-kernel
*
* Copyright (c) 2008 QUALCOMM Incorporated.
* Copyright (c) 2008 QUALCOMM USA, INC.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/input/auo-pixcir-ts.h>
/*
* Coordinate calculation:
* X1 = X1_LSB + X1_MSB*256
* Y1 = Y1_LSB + Y1_MSB*256
* X2 = X2_LSB + X2_MSB*256
* Y2 = Y2_LSB + Y2_MSB*256
*/
#define AUO_PIXCIR_REG_X1_LSB 0x00
#define AUO_PIXCIR_REG_X1_MSB 0x01
#define AUO_PIXCIR_REG_Y1_LSB 0x02
#define AUO_PIXCIR_REG_Y1_MSB 0x03
#define AUO_PIXCIR_REG_X2_LSB 0x04
#define AUO_PIXCIR_REG_X2_MSB 0x05
#define AUO_PIXCIR_REG_Y2_LSB 0x06
#define AUO_PIXCIR_REG_Y2_MSB 0x07
#define AUO_PIXCIR_REG_STRENGTH 0x0d
#define AUO_PIXCIR_REG_STRENGTH_X1_LSB 0x0e
#define AUO_PIXCIR_REG_STRENGTH_X1_MSB 0x0f
#define AUO_PIXCIR_REG_RAW_DATA_X 0x2b
#define AUO_PIXCIR_REG_RAW_DATA_Y 0x4f
#define AUO_PIXCIR_REG_X_SENSITIVITY 0x6f
#define AUO_PIXCIR_REG_Y_SENSITIVITY 0x70
#define AUO_PIXCIR_REG_INT_SETTING 0x71
#define AUO_PIXCIR_REG_INT_WIDTH 0x72
#define AUO_PIXCIR_REG_POWER_MODE 0x73
#define AUO_PIXCIR_REG_VERSION 0x77
#define AUO_PIXCIR_REG_CALIBRATE 0x78
#define AUO_PIXCIR_REG_TOUCHAREA_X1 0x1e
#define AUO_PIXCIR_REG_TOUCHAREA_Y1 0x1f
#define AUO_PIXCIR_REG_TOUCHAREA_X2 0x20
#define AUO_PIXCIR_REG_TOUCHAREA_Y2 0x21
#define AUO_PIXCIR_REG_EEPROM_CALIB_X 0x42
#define AUO_PIXCIR_REG_EEPROM_CALIB_Y 0xad
#define AUO_PIXCIR_INT_TPNUM_MASK 0xe0
#define AUO_PIXCIR_INT_TPNUM_SHIFT 5
#define AUO_PIXCIR_INT_RELEASE (1 << 4)
#define AUO_PIXCIR_INT_ENABLE (1 << 3)
#define AUO_PIXCIR_INT_POL_HIGH (1 << 2)
#define AUO_PIXCIR_INT_MODE_MASK 0x03
/*
* Power modes:
* active: scan speed 60Hz
* sleep: scan speed 10Hz can be auto-activated, wakeup on 1st touch
* deep sleep: scan speed 1Hz can only be entered or left manually.
*/
#define AUO_PIXCIR_POWER_ACTIVE 0x00
#define AUO_PIXCIR_POWER_SLEEP 0x01
#define AUO_PIXCIR_POWER_DEEP_SLEEP 0x02
#define AUO_PIXCIR_POWER_MASK 0x03
#define AUO_PIXCIR_POWER_ALLOW_SLEEP (1 << 2)
#define AUO_PIXCIR_POWER_IDLE_TIME(ms) ((ms & 0xf) << 4)
#define AUO_PIXCIR_CALIBRATE 0x03
#define AUO_PIXCIR_EEPROM_CALIB_X_LEN 62
#define AUO_PIXCIR_EEPROM_CALIB_Y_LEN 36
#define AUO_PIXCIR_RAW_DATA_X_LEN 18
#define AUO_PIXCIR_RAW_DATA_Y_LEN 11
#define AUO_PIXCIR_STRENGTH_ENABLE (1 << 0)
/* Touchscreen absolute values */
#define AUO_PIXCIR_REPORT_POINTS 2
#define AUO_PIXCIR_MAX_AREA 0xff
#define AUO_PIXCIR_PENUP_TIMEOUT_MS 10
struct auo_pixcir_ts {
struct i2c_client *client;
struct input_dev *input;
char phys[32];
/* special handling for touch_indicate interupt mode */
bool touch_ind_mode;
wait_queue_head_t wait;
bool stopped;
};
struct auo_point_t {
int coord_x;
int coord_y;
int area_major;
int area_minor;
int orientation;
};
static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts,
struct auo_point_t *point)
{
struct i2c_client *client = ts->client;
const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
uint8_t raw_coord[8];
uint8_t raw_area[4];
int i, ret;
/* touch coordinates */
ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_X1_LSB,
8, raw_coord);
if (ret < 0) {
dev_err(&client->dev, "failed to read coordinate, %d\n", ret);
return ret;
}
/* touch area */
ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_TOUCHAREA_X1,
4, raw_area);
if (ret < 0) {
dev_err(&client->dev, "could not read touch area, %d\n", ret);
return ret;
}
for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
point[i].coord_x =
raw_coord[4 * i + 1] << 8 | raw_coord[4 * i];
point[i].coord_y =
raw_coord[4 * i + 3] << 8 | raw_coord[4 * i + 2];
if (point[i].coord_x > pdata->x_max ||
point[i].coord_y > pdata->y_max) {
dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
point[i].coord_x, point[i].coord_y);
point[i].coord_x = point[i].coord_y = 0;
}
/* determine touch major, minor and orientation */
point[i].area_major = max(raw_area[2 * i], raw_area[2 * i + 1]);
point[i].area_minor = min(raw_area[2 * i], raw_area[2 * i + 1]);
point[i].orientation = raw_area[2 * i] > raw_area[2 * i + 1];
}
return 0;
}
static irqreturn_t auo_pixcir_interrupt(int irq, void *dev_id)
{
struct auo_pixcir_ts *ts = dev_id;
struct i2c_client *client = ts->client;
const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
struct auo_point_t point[AUO_PIXCIR_REPORT_POINTS];
int i;
int ret;
int fingers = 0;
int abs = -1;
while (!ts->stopped) {
/* check for up event in touch touch_ind_mode */
if (ts->touch_ind_mode) {
if (gpio_get_value(pdata->gpio_int) == 0) {
input_mt_sync(ts->input);
input_report_key(ts->input, BTN_TOUCH, 0);
input_sync(ts->input);
break;
}
}
ret = auo_pixcir_collect_data(ts, point);
if (ret < 0) {
/* we want to loop only in touch_ind_mode */
if (!ts->touch_ind_mode)
break;
wait_event_timeout(ts->wait, ts->stopped,
msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
continue;
}
for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
if (point[i].coord_x > 0 || point[i].coord_y > 0) {
input_report_abs(ts->input, ABS_MT_POSITION_X,
point[i].coord_x);
input_report_abs(ts->input, ABS_MT_POSITION_Y,
point[i].coord_y);
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
point[i].area_major);
input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
point[i].area_minor);
input_report_abs(ts->input, ABS_MT_ORIENTATION,
point[i].orientation);
input_mt_sync(ts->input);
/* use first finger as source for singletouch */
if (fingers == 0)
abs = i;
/* number of touch points could also be queried
* via i2c but would require an additional call
*/
fingers++;
}
}
input_report_key(ts->input, BTN_TOUCH, fingers > 0);
if (abs > -1) {
input_report_abs(ts->input, ABS_X, point[abs].coord_x);
input_report_abs(ts->input, ABS_Y, point[abs].coord_y);
}
input_sync(ts->input);
/* we want to loop only in touch_ind_mode */
if (!ts->touch_ind_mode)
break;
wait_event_timeout(ts->wait, ts->stopped,
msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
}
return IRQ_HANDLED;
}
/*
* Set the power mode of the device.
* Valid modes are
* - AUO_PIXCIR_POWER_ACTIVE
* - AUO_PIXCIR_POWER_SLEEP - automatically left on first touch
* - AUO_PIXCIR_POWER_DEEP_SLEEP
*/
static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode)
{
struct i2c_client *client = ts->client;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_POWER_MODE);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_POWER_MODE, ret);
return ret;
}
ret &= ~AUO_PIXCIR_POWER_MASK;
ret |= mode;
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_POWER_MODE, ret);
if (ret) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_POWER_MODE, ret);
return ret;
}
return 0;
}
static __devinit int auo_pixcir_int_config(struct auo_pixcir_ts *ts,
int int_setting)
{
struct i2c_client *client = ts->client;
struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
ret &= ~AUO_PIXCIR_INT_MODE_MASK;
ret |= int_setting;
ret |= AUO_PIXCIR_INT_POL_HIGH; /* always use high for interrupts */
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
ret);
if (ret < 0) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
ts->touch_ind_mode = pdata->int_setting == AUO_PIXCIR_INT_TOUCH_IND;
return 0;
}
/* control the generation of interrupts on the device side */
static int auo_pixcir_int_toggle(struct auo_pixcir_ts *ts, bool enable)
{
struct i2c_client *client = ts->client;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
if (enable)
ret |= AUO_PIXCIR_INT_ENABLE;
else
ret &= ~AUO_PIXCIR_INT_ENABLE;
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
ret);
if (ret < 0) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
return 0;
}
static int auo_pixcir_start(struct auo_pixcir_ts *ts)
{
struct i2c_client *client = ts->client;
int ret;
ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_ACTIVE);
if (ret < 0) {
dev_err(&client->dev, "could not set power mode, %d\n",
ret);
return ret;
}
ts->stopped = false;
mb();
enable_irq(client->irq);
ret = auo_pixcir_int_toggle(ts, 1);
if (ret < 0) {
dev_err(&client->dev, "could not enable interrupt, %d\n",
ret);
disable_irq(client->irq);
return ret;
}
return 0;
}
static int auo_pixcir_stop(struct auo_pixcir_ts *ts)
{
struct i2c_client *client = ts->client;
int ret;
ret = auo_pixcir_int_toggle(ts, 0);
if (ret < 0) {
dev_err(&client->dev, "could not disable interrupt, %d\n",
ret);
return ret;
}
/* disable receiving of interrupts */
disable_irq(client->irq);
ts->stopped = true;
mb();
wake_up(&ts->wait);
return auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_DEEP_SLEEP);
}
static int auo_pixcir_input_open(struct input_dev *dev)
{
struct auo_pixcir_ts *ts = input_get_drvdata(dev);
int ret;
ret = auo_pixcir_start(ts);
if (ret)
return ret;
return 0;
}
static void auo_pixcir_input_close(struct input_dev *dev)
{
struct auo_pixcir_ts *ts = input_get_drvdata(dev);
auo_pixcir_stop(ts);
return;
}
#ifdef CONFIG_PM_SLEEP
static int auo_pixcir_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
/* when configured as wakeup source, device should always wake system
* therefore start device if necessary
*/
if (device_may_wakeup(&client->dev)) {
/* need to start device if not open, to be wakeup source */
if (!input->users) {
ret = auo_pixcir_start(ts);
if (ret)
goto unlock;
}
enable_irq_wake(client->irq);
ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP);
} else if (input->users) {
ret = auo_pixcir_stop(ts);
}
unlock:
mutex_unlock(&input->mutex);
return ret;
}
static int auo_pixcir_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq);
/* need to stop device if it was not open on suspend */
if (!input->users) {
ret = auo_pixcir_stop(ts);
if (ret)
goto unlock;
}
/* device wakes automatically from SLEEP */
} else if (input->users) {
ret = auo_pixcir_start(ts);
}
unlock:
mutex_unlock(&input->mutex);
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, auo_pixcir_suspend,
auo_pixcir_resume);
static int __devinit auo_pixcir_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
struct auo_pixcir_ts *ts;
struct input_dev *input_dev;
int ret;
if (!pdata)
return -EINVAL;
ts = kzalloc(sizeof(struct auo_pixcir_ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
ret = gpio_request(pdata->gpio_int, "auo_pixcir_ts_int");
if (ret) {
dev_err(&client->dev, "request of gpio %d failed, %d\n",
pdata->gpio_int, ret);
goto err_gpio_int;
}
if (pdata->init_hw)
pdata->init_hw(client);
ts->client = client;
ts->touch_ind_mode = 0;
init_waitqueue_head(&ts->wait);
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&client->dev, "could not allocate input device\n");
goto err_input_alloc;
}
ts->input = input_dev;
input_dev->name = "AUO-Pixcir touchscreen";
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->open = auo_pixcir_input_open;
input_dev->close = auo_pixcir_input_close;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
/* For single touch */
input_set_abs_params(input_dev, ABS_X, 0, pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, pdata->y_max, 0, 0);
/* For multi touch */
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
pdata->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
AUO_PIXCIR_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
AUO_PIXCIR_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION);
if (ret < 0)
goto err_fw_vers;
dev_info(&client->dev, "firmware version 0x%X\n", ret);
ret = auo_pixcir_int_config(ts, pdata->int_setting);
if (ret)
goto err_fw_vers;
input_set_drvdata(ts->input, ts);
ts->stopped = true;
ret = request_threaded_irq(client->irq, NULL, auo_pixcir_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
input_dev->name, ts);
if (ret) {
dev_err(&client->dev, "irq %d requested failed\n", client->irq);
goto err_fw_vers;
}
/* stop device and put it into deep sleep until it is opened */
ret = auo_pixcir_stop(ts);
if (ret < 0)
goto err_input_register;
ret = input_register_device(input_dev);
if (ret) {
dev_err(&client->dev, "could not register input device\n");
goto err_input_register;
}
i2c_set_clientdata(client, ts);
return 0;
err_input_register:
free_irq(client->irq, ts);
err_fw_vers:
input_free_device(input_dev);
err_input_alloc:
if (pdata->exit_hw)
pdata->exit_hw(client);
gpio_free(pdata->gpio_int);
err_gpio_int:
kfree(ts);
return ret;
}
static int __devexit auo_pixcir_remove(struct i2c_client *client)
{
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
free_irq(client->irq, ts);
input_unregister_device(ts->input);
if (pdata->exit_hw)
pdata->exit_hw(client);
gpio_free(pdata->gpio_int);
kfree(ts);
return 0;
}
static const struct i2c_device_id auo_pixcir_idtable[] = {
{ "auo_pixcir_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
static struct i2c_driver auo_pixcir_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "auo_pixcir_ts",
.pm = &auo_pixcir_pm_ops,
},
.probe = auo_pixcir_probe,
.remove = __devexit_p(auo_pixcir_remove),
.id_table = auo_pixcir_idtable,
};
static int __init auo_pixcir_init(void)
{
return i2c_add_driver(&auo_pixcir_driver);
}
module_init(auo_pixcir_init);
static void __exit auo_pixcir_exit(void)
{
i2c_del_driver(&auo_pixcir_driver);
}
module_exit(auo_pixcir_exit);
MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+1 -12
View File
@@ -379,18 +379,7 @@ static struct platform_driver da9034_touch_driver = {
.probe = da9034_touch_probe,
.remove = __devexit_p(da9034_touch_remove),
};
static int __init da9034_touch_init(void)
{
return platform_driver_register(&da9034_touch_driver);
}
module_init(da9034_touch_init);
static void __exit da9034_touch_exit(void)
{
platform_driver_unregister(&da9034_touch_driver);
}
module_exit(da9034_touch_exit);
module_platform_driver(da9034_touch_driver);
MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034");
MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>, Bin Yang <bin.yang@marvell.com>");
+303
View File
@@ -0,0 +1,303 @@
/*
* Driver for EETI eGalax Multiple Touch Controller
*
* Copyright (C) 2011 Freescale Semiconductor, Inc.
*
* based on max11801_ts.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* EETI eGalax serial touch screen controller is a I2C based multiple
* touch screen controller, it supports 5 point multiple touch. */
/* TODO:
- auto idle mode support
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/input/mt.h>
/*
* Mouse Mode: some panel may configure the controller to mouse mode,
* which can only report one point at a given time.
* This driver will ignore events in this mode.
*/
#define REPORT_MODE_MOUSE 0x1
/*
* Vendor Mode: this mode is used to transfer some vendor specific
* messages.
* This driver will ignore events in this mode.
*/
#define REPORT_MODE_VENDOR 0x3
/* Multiple Touch Mode */
#define REPORT_MODE_MTTOUCH 0x4
#define MAX_SUPPORT_POINTS 5
#define EVENT_VALID_OFFSET 7
#define EVENT_VALID_MASK (0x1 << EVENT_VALID_OFFSET)
#define EVENT_ID_OFFSET 2
#define EVENT_ID_MASK (0xf << EVENT_ID_OFFSET)
#define EVENT_IN_RANGE (0x1 << 1)
#define EVENT_DOWN_UP (0X1 << 0)
#define MAX_I2C_DATA_LEN 10
#define EGALAX_MAX_X 32760
#define EGALAX_MAX_Y 32760
#define EGALAX_MAX_TRIES 100
struct egalax_ts {
struct i2c_client *client;
struct input_dev *input_dev;
};
static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
{
struct egalax_ts *ts = dev_id;
struct input_dev *input_dev = ts->input_dev;
struct i2c_client *client = ts->client;
u8 buf[MAX_I2C_DATA_LEN];
int id, ret, x, y, z;
int tries = 0;
bool down, valid;
u8 state;
do {
ret = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN);
} while (ret == -EAGAIN && tries++ < EGALAX_MAX_TRIES);
if (ret < 0)
return IRQ_HANDLED;
if (buf[0] != REPORT_MODE_MTTOUCH) {
/* ignore mouse events and vendor events */
return IRQ_HANDLED;
}
state = buf[1];
x = (buf[3] << 8) | buf[2];
y = (buf[5] << 8) | buf[4];
z = (buf[7] << 8) | buf[6];
valid = state & EVENT_VALID_MASK;
id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET;
down = state & EVENT_DOWN_UP;
if (!valid || id > MAX_SUPPORT_POINTS) {
dev_dbg(&client->dev, "point invalid\n");
return IRQ_HANDLED;
}
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down);
dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d",
down ? "down" : "up", id, x, y, z);
if (down) {
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_PRESSURE, z);
}
input_mt_report_pointer_emulation(input_dev, true);
input_sync(input_dev);
return IRQ_HANDLED;
}
/* wake up controller by an falling edge of interrupt gpio. */
static int egalax_wake_up_device(struct i2c_client *client)
{
int gpio = irq_to_gpio(client->irq);
int ret;
ret = gpio_request(gpio, "egalax_irq");
if (ret < 0) {
dev_err(&client->dev,
"request gpio failed, cannot wake up controller: %d\n",
ret);
return ret;
}
/* wake up controller via an falling edge on IRQ gpio. */
gpio_direction_output(gpio, 0);
gpio_set_value(gpio, 1);
/* controller should be waken up, return irq. */
gpio_direction_input(gpio);
gpio_free(gpio);
return 0;
}
static int __devinit egalax_firmware_version(struct i2c_client *client)
{
static const u8 cmd[MAX_I2C_DATA_LEN] = { 0x03, 0x03, 0xa, 0x01, 0x41 };
int ret;
ret = i2c_master_send(client, cmd, MAX_I2C_DATA_LEN);
if (ret < 0)
return ret;
return 0;
}
static int __devinit egalax_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct egalax_ts *ts;
struct input_dev *input_dev;
int ret;
int error;
ts = kzalloc(sizeof(struct egalax_ts), GFP_KERNEL);
if (!ts) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
error = -ENOMEM;
goto err_free_ts;
}
ts->client = client;
ts->input_dev = input_dev;
/* controller may be in sleep, wake it up. */
egalax_wake_up_device(client);
ret = egalax_firmware_version(client);
if (ret < 0) {
dev_err(&client->dev, "Failed to read firmware version\n");
error = -EIO;
goto err_free_dev;
}
input_dev->name = "EETI eGalax Touch Screen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, EGALAX_MAX_Y, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0);
input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS);
input_set_drvdata(input_dev, ts);
error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"egalax_ts", ts);
if (error < 0) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_dev;
}
error = input_register_device(ts->input_dev);
if (error)
goto err_free_irq;
i2c_set_clientdata(client, ts);
return 0;
err_free_irq:
free_irq(client->irq, ts);
err_free_dev:
input_free_device(input_dev);
err_free_ts:
kfree(ts);
return error;
}
static __devexit int egalax_ts_remove(struct i2c_client *client)
{
struct egalax_ts *ts = i2c_get_clientdata(client);
free_irq(client->irq, ts);
input_unregister_device(ts->input_dev);
kfree(ts);
return 0;
}
static const struct i2c_device_id egalax_ts_id[] = {
{ "egalax_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, egalax_ts_id);
#ifdef CONFIG_PM_SLEEP
static int egalax_ts_suspend(struct device *dev)
{
static const u8 suspend_cmd[MAX_I2C_DATA_LEN] = {
0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0
};
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = i2c_master_send(client, suspend_cmd, MAX_I2C_DATA_LEN);
return ret > 0 ? 0 : ret;
}
static int egalax_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
return egalax_wake_up_device(client);
}
#endif
static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
static struct i2c_driver egalax_ts_driver = {
.driver = {
.name = "egalax_ts",
.owner = THIS_MODULE,
.pm = &egalax_ts_pm_ops,
},
.id_table = egalax_ts_id,
.probe = egalax_ts_probe,
.remove = __devexit_p(egalax_ts_remove),
};
static int __init egalax_ts_init(void)
{
return i2c_add_driver(&egalax_ts_driver);
}
static void __exit egalax_ts_exit(void)
{
i2c_del_driver(&egalax_ts_driver);
}
module_init(egalax_ts_init);
module_exit(egalax_ts_exit);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("Touchscreen driver for EETI eGalax touch controller");
MODULE_LICENSE("GPL");
+1 -6
View File
@@ -47,12 +47,6 @@ static int invert_y;
module_param(invert_y, bool, 0644);
MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted");
static struct pnp_device_id pnp_ids[] = {
{ .id = "PNP0cc0" },
{ .id = "" }
};
MODULE_DEVICE_TABLE(pnp, pnp_ids);
static irqreturn_t htcpen_interrupt(int irq, void *handle)
{
struct input_dev *htcpen_dev = handle;
@@ -237,6 +231,7 @@ static struct dmi_system_id __initdata htcshift_dmi_table[] = {
},
{ }
};
MODULE_DEVICE_TABLE(dmi, htcshift_dmi_table);
static int __init htcpen_isa_init(void)
{
+1 -12
View File
@@ -664,18 +664,7 @@ static struct platform_driver mrstouch_driver = {
.probe = mrstouch_probe,
.remove = __devexit_p(mrstouch_remove),
};
static int __init mrstouch_init(void)
{
return platform_driver_register(&mrstouch_driver);
}
module_init(mrstouch_init);
static void __exit mrstouch_exit(void)
{
platform_driver_unregister(&mrstouch_driver);
}
module_exit(mrstouch_exit);
module_platform_driver(mrstouch_driver);
MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
+1 -13
View File
@@ -172,16 +172,4 @@ static struct platform_driver jornada720_ts_driver = {
.owner = THIS_MODULE,
},
};
static int __init jornada720_ts_init(void)
{
return platform_driver_register(&jornada720_ts_driver);
}
static void __exit jornada720_ts_exit(void)
{
platform_driver_unregister(&jornada720_ts_driver);
}
module_init(jornada720_ts_init);
module_exit(jornada720_ts_exit);
module_platform_driver(jornada720_ts_driver);
+1 -12
View File
@@ -392,18 +392,7 @@ static struct platform_driver lpc32xx_ts_driver = {
.pm = LPC32XX_TS_PM_OPS,
},
};
static int __init lpc32xx_ts_init(void)
{
return platform_driver_register(&lpc32xx_ts_driver);
}
module_init(lpc32xx_ts_init);
static void __exit lpc32xx_ts_exit(void)
{
platform_driver_unregister(&lpc32xx_ts_driver);
}
module_exit(lpc32xx_ts_exit);
module_platform_driver(lpc32xx_ts_driver);
MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
MODULE_DESCRIPTION("LPC32XX TSC Driver");
+1 -13
View File
@@ -302,19 +302,7 @@ static struct platform_driver mainstone_wm97xx_driver = {
.name = "wm97xx-touch",
},
};
static int __init mainstone_wm97xx_init(void)
{
return platform_driver_register(&mainstone_wm97xx_driver);
}
static void __exit mainstone_wm97xx_exit(void)
{
platform_driver_unregister(&mainstone_wm97xx_driver);
}
module_init(mainstone_wm97xx_init);
module_exit(mainstone_wm97xx_exit);
module_platform_driver(mainstone_wm97xx_driver);
/* Module information */
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+1 -12
View File
@@ -240,18 +240,7 @@ static struct platform_driver mc13783_ts_driver = {
.name = MC13783_TS_NAME,
},
};
static int __init mc13783_ts_init(void)
{
return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe);
}
module_init(mc13783_ts_init);
static void __exit mc13783_ts_exit(void)
{
platform_driver_unregister(&mc13783_ts_driver);
}
module_exit(mc13783_ts_exit);
module_platform_driver(mc13783_ts_driver);
MODULE_DESCRIPTION("MC13783 input touchscreen driver");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+46 -71
View File
@@ -36,7 +36,6 @@
struct migor_ts_priv {
struct i2c_client *client;
struct input_dev *input;
struct delayed_work work;
int irq;
};
@@ -44,15 +43,24 @@ static const u_int8_t migor_ts_ena_seq[17] = { 0x33, 0x22, 0x11,
0x01, 0x06, 0x07, };
static const u_int8_t migor_ts_dis_seq[17] = { };
static void migor_ts_poscheck(struct work_struct *work)
static irqreturn_t migor_ts_isr(int irq, void *dev_id)
{
struct migor_ts_priv *priv = container_of(work,
struct migor_ts_priv,
work.work);
struct migor_ts_priv *priv = dev_id;
unsigned short xpos, ypos;
unsigned char event;
u_int8_t buf[16];
/*
* The touch screen controller chip is hooked up to the CPU
* using I2C and a single interrupt line. The interrupt line
* is pulled low whenever someone taps the screen. To deassert
* the interrupt line we need to acknowledge the interrupt by
* communicating with the controller over the slow i2c bus.
*
* Since I2C bus controller may sleep we are using threaded
* IRQ here.
*/
memset(buf, 0, sizeof(buf));
/* Set Index 0 */
@@ -72,41 +80,25 @@ static void migor_ts_poscheck(struct work_struct *work)
xpos = ((buf[11] & 0x03) << 8 | buf[10]);
event = buf[12];
if (event == EVENT_PENDOWN || event == EVENT_REPEAT) {
switch (event) {
case EVENT_PENDOWN:
case EVENT_REPEAT:
input_report_key(priv->input, BTN_TOUCH, 1);
input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/
input_report_abs(priv->input, ABS_Y, xpos);
input_sync(priv->input);
} else if (event == EVENT_PENUP) {
break;
case EVENT_PENUP:
input_report_key(priv->input, BTN_TOUCH, 0);
input_sync(priv->input);
break;
}
out:
enable_irq(priv->irq);
}
static irqreturn_t migor_ts_isr(int irq, void *dev_id)
{
struct migor_ts_priv *priv = dev_id;
/* the touch screen controller chip is hooked up to the cpu
* using i2c and a single interrupt line. the interrupt line
* is pulled low whenever someone taps the screen. to deassert
* the interrupt line we need to acknowledge the interrupt by
* communicating with the controller over the slow i2c bus.
*
* we can't acknowledge from interrupt context since the i2c
* bus controller may sleep, so we just disable the interrupt
* here and handle the acknowledge using delayed work.
*/
disable_irq_nosync(irq);
schedule_delayed_work(&priv->work, HZ / 20);
return IRQ_HANDLED;
}
static int migor_ts_open(struct input_dev *dev)
{
struct migor_ts_priv *priv = input_get_drvdata(dev);
@@ -131,15 +123,6 @@ static void migor_ts_close(struct input_dev *dev)
disable_irq(priv->irq);
/* cancel pending work and wait for migor_ts_poscheck() to finish */
if (cancel_delayed_work_sync(&priv->work)) {
/*
* if migor_ts_poscheck was canceled we need to enable IRQ
* here to balance disable done in migor_ts_isr.
*/
enable_irq(priv->irq);
}
/* disable controller */
i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq));
@@ -154,23 +137,20 @@ static int migor_ts_probe(struct i2c_client *client,
int error;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&client->dev, "failed to allocate driver data\n");
error = -ENOMEM;
goto err0;
}
dev_set_drvdata(&client->dev, priv);
input = input_allocate_device();
if (!input) {
dev_err(&client->dev, "Failed to allocate input device.\n");
if (!priv || !input) {
dev_err(&client->dev, "failed to allocate memory\n");
error = -ENOMEM;
goto err1;
goto err_free_mem;
}
priv->client = client;
priv->input = input;
priv->irq = client->irq;
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
__set_bit(BTN_TOUCH, input->keybit);
input_set_abs_params(input, ABS_X, 95, 955, 0, 0);
input_set_abs_params(input, ABS_Y, 85, 935, 0, 0);
@@ -184,39 +164,34 @@ static int migor_ts_probe(struct i2c_client *client,
input_set_drvdata(input, priv);
priv->client = client;
priv->input = input;
INIT_DELAYED_WORK(&priv->work, migor_ts_poscheck);
priv->irq = client->irq;
error = request_threaded_irq(priv->irq, NULL, migor_ts_isr,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, priv);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err_free_mem;
}
error = input_register_device(input);
if (error)
goto err1;
error = request_irq(priv->irq, migor_ts_isr, IRQF_TRIGGER_LOW,
client->name, priv);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err2;
}
goto err_free_irq;
i2c_set_clientdata(client, priv);
device_init_wakeup(&client->dev, 1);
return 0;
err2:
input_unregister_device(input);
input = NULL; /* so we dont try to free it below */
err1:
err_free_irq:
free_irq(priv->irq, priv);
err_free_mem:
input_free_device(input);
kfree(priv);
err0:
dev_set_drvdata(&client->dev, NULL);
return error;
}
static int migor_ts_remove(struct i2c_client *client)
{
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
free_irq(priv->irq, priv);
input_unregister_device(priv->input);
@@ -230,7 +205,7 @@ static int migor_ts_remove(struct i2c_client *client)
static int migor_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
enable_irq_wake(priv->irq);
@@ -241,7 +216,7 @@ static int migor_ts_suspend(struct device *dev)
static int migor_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
disable_irq_wake(priv->irq);
+1 -13
View File
@@ -252,19 +252,7 @@ static struct platform_driver pcap_ts_driver = {
.pm = PCAP_TS_PM_OPS,
},
};
static int __init pcap_ts_init(void)
{
return platform_driver_register(&pcap_ts_driver);
}
static void __exit pcap_ts_exit(void)
{
platform_driver_unregister(&pcap_ts_driver);
}
module_init(pcap_ts_init);
module_exit(pcap_ts_exit);
module_platform_driver(pcap_ts_driver);
MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver");
MODULE_AUTHOR("Daniel Ribeiro / Harald Welte");
+239
View File
@@ -0,0 +1,239 @@
/*
* Driver for Pixcir I2C touchscreen controllers.
*
* Copyright (C) 2010-2011 Pixcir, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/pixcir_ts.h>
struct pixcir_i2c_ts_data {
struct i2c_client *client;
struct input_dev *input;
const struct pixcir_ts_platform_data *chip;
bool exiting;
};
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
{
struct pixcir_i2c_ts_data *tsdata = data;
u8 rdbuf[10], wrbuf[1] = { 0 };
u8 touch;
int ret;
ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
if (ret != sizeof(wrbuf)) {
dev_err(&tsdata->client->dev,
"%s: i2c_master_send failed(), ret=%d\n",
__func__, ret);
return;
}
ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
if (ret != sizeof(rdbuf)) {
dev_err(&tsdata->client->dev,
"%s: i2c_master_recv failed(), ret=%d\n",
__func__, ret);
return;
}
touch = rdbuf[0];
if (touch) {
u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
input_report_key(tsdata->input, BTN_TOUCH, 1);
input_report_abs(tsdata->input, ABS_X, posx1);
input_report_abs(tsdata->input, ABS_Y, posy1);
input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
input_mt_sync(tsdata->input);
if (touch == 2) {
input_report_abs(tsdata->input,
ABS_MT_POSITION_X, posx2);
input_report_abs(tsdata->input,
ABS_MT_POSITION_Y, posy2);
input_mt_sync(tsdata->input);
}
} else {
input_report_key(tsdata->input, BTN_TOUCH, 0);
}
input_sync(tsdata->input);
}
static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
{
struct pixcir_i2c_ts_data *tsdata = dev_id;
while (!tsdata->exiting) {
pixcir_ts_poscheck(tsdata);
if (tsdata->chip->attb_read_val())
break;
msleep(20);
}
return IRQ_HANDLED;
}
#ifdef CONFIG_PM_SLEEP
static int pixcir_i2c_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
return 0;
}
static int pixcir_i2c_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
struct pixcir_i2c_ts_data *tsdata;
struct input_dev *input;
int error;
if (!pdata) {
dev_err(&client->dev, "platform data not defined\n");
return -EINVAL;
}
tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
input = input_allocate_device();
if (!tsdata || !input) {
dev_err(&client->dev, "Failed to allocate driver data!\n");
error = -ENOMEM;
goto err_free_mem;
}
tsdata->client = client;
tsdata->input = input;
tsdata->chip = pdata;
input->name = client->name;
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
__set_bit(EV_KEY, input->evbit);
__set_bit(EV_ABS, input->evbit);
__set_bit(BTN_TOUCH, input->keybit);
input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0);
input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
input_set_drvdata(input, tsdata);
error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
IRQF_TRIGGER_FALLING,
client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err_free_mem;
}
error = input_register_device(input);
if (error)
goto err_free_irq;
i2c_set_clientdata(client, tsdata);
device_init_wakeup(&client->dev, 1);
return 0;
err_free_irq:
free_irq(client->irq, tsdata);
err_free_mem:
input_free_device(input);
kfree(tsdata);
return error;
}
static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client)
{
struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
device_init_wakeup(&client->dev, 0);
tsdata->exiting = true;
mb();
free_irq(client->irq, tsdata);
input_unregister_device(tsdata->input);
kfree(tsdata);
return 0;
}
static const struct i2c_device_id pixcir_i2c_ts_id[] = {
{ "pixcir_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
static struct i2c_driver pixcir_i2c_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pixcir_ts",
.pm = &pixcir_dev_pm_ops,
},
.probe = pixcir_i2c_ts_probe,
.remove = __devexit_p(pixcir_i2c_ts_remove),
.id_table = pixcir_i2c_ts_id,
};
static int __init pixcir_i2c_ts_init(void)
{
return i2c_add_driver(&pixcir_i2c_ts_driver);
}
module_init(pixcir_i2c_ts_init);
static void __exit pixcir_i2c_ts_exit(void)
{
i2c_del_driver(&pixcir_i2c_ts_driver);
}
module_exit(pixcir_i2c_ts_exit);
MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>");
MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
MODULE_LICENSE("GPL");
+1 -13
View File
@@ -432,19 +432,7 @@ static struct platform_driver s3c_ts_driver = {
.probe = s3c2410ts_probe,
.remove = __devexit_p(s3c2410ts_remove),
};
static int __init s3c2410ts_init(void)
{
return platform_driver_register(&s3c_ts_driver);
}
static void __exit s3c2410ts_exit(void)
{
platform_driver_unregister(&s3c_ts_driver);
}
module_init(s3c2410ts_init);
module_exit(s3c2410ts_exit);
module_platform_driver(s3c_ts_driver);
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
"Ben Dooks <ben@simtec.co.uk>, "
+1 -14
View File
@@ -379,20 +379,7 @@ static struct platform_driver stmpe_ts_driver = {
.probe = stmpe_input_probe,
.remove = __devexit_p(stmpe_ts_remove),
};
static int __init stmpe_ts_init(void)
{
return platform_driver_register(&stmpe_ts_driver);
}
module_init(stmpe_ts_init);
static void __exit stmpe_ts_exit(void)
{
platform_driver_unregister(&stmpe_ts_driver);
}
module_exit(stmpe_ts_exit);
module_platform_driver(stmpe_ts_driver);
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
+1 -13
View File
@@ -378,19 +378,7 @@ static struct platform_driver tsc_driver = {
.driver.name = "tnetv107x-ts",
.driver.owner = THIS_MODULE,
};
static int __init tsc_init(void)
{
return platform_driver_register(&tsc_driver);
}
static void __exit tsc_exit(void)
{
platform_driver_unregister(&tsc_driver);
}
module_init(tsc_init);
module_exit(tsc_exit);
module_platform_driver(tsc_driver);
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
+1 -12
View File
@@ -371,18 +371,7 @@ static struct platform_driver tps6507x_ts_driver = {
.probe = tps6507x_ts_probe,
.remove = __devexit_p(tps6507x_ts_remove),
};
static int __init tps6507x_ts_init(void)
{
return platform_driver_register(&tps6507x_ts_driver);
}
module_init(tps6507x_ts_init);
static void __exit tps6507x_ts_exit(void)
{
platform_driver_unregister(&tps6507x_ts_driver);
}
module_exit(tps6507x_ts_exit);
module_platform_driver(tps6507x_ts_driver);
MODULE_AUTHOR("Todd Fischer <todd.fischer@ridgerun.com>");
MODULE_DESCRIPTION("TPS6507x - TouchScreen driver");
+133 -152
View File
@@ -20,24 +20,24 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/input.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/suspend.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/ucb1400.h>
#define UCB1400_TS_POLL_PERIOD 10 /* ms */
static int adcsync;
static int ts_delay = 55; /* us */
static int ts_delay_pressure; /* us */
/* Switch to interrupt mode. */
static inline void ucb1400_ts_mode_int(struct snd_ac97 *ac97)
static void ucb1400_ts_mode_int(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ac97, UCB_TS_CR,
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
UCB_TS_CR_MODE_INT);
@@ -47,13 +47,15 @@ static inline void ucb1400_ts_mode_int(struct snd_ac97 *ac97)
* Switch to pressure mode, and read pressure. We don't need to wait
* here, since both plates are being driven.
*/
static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
static unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
udelay(ts_delay_pressure);
return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync);
}
@@ -63,7 +65,7 @@ static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
* gives a faster response time. Even so, we need to wait about 55us
* for things to stabilise.
*/
static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
static unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
@@ -86,7 +88,7 @@ static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
* gives a faster response time. Even so, we need to wait about 55us
* for things to stabilise.
*/
static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
static int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
@@ -107,7 +109,7 @@ static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
* Switch to X plate resistance mode. Set MX to ground, PX to
* supply. Measure current.
*/
static inline unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
static unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
@@ -119,7 +121,7 @@ static inline unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
* Switch to Y plate resistance mode. Set MY to ground, PY to
* supply. Measure current.
*/
static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
static unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
@@ -127,26 +129,26 @@ static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
return ucb1400_adc_read(ucb->ac97, 0, adcsync);
}
static inline int ucb1400_ts_pen_up(struct snd_ac97 *ac97)
static int ucb1400_ts_pen_up(struct ucb1400_ts *ucb)
{
unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR);
unsigned short val = ucb1400_reg_read(ucb->ac97, UCB_TS_CR);
return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
}
static inline void ucb1400_ts_irq_enable(struct snd_ac97 *ac97)
static void ucb1400_ts_irq_enable(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ac97, UCB_IE_CLEAR, UCB_IE_TSPX);
ucb1400_reg_write(ac97, UCB_IE_CLEAR, 0);
ucb1400_reg_write(ac97, UCB_IE_FAL, UCB_IE_TSPX);
ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, UCB_IE_TSPX);
ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_TSPX);
}
static inline void ucb1400_ts_irq_disable(struct snd_ac97 *ac97)
static void ucb1400_ts_irq_disable(struct ucb1400_ts *ucb)
{
ucb1400_reg_write(ac97, UCB_IE_FAL, 0);
ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0);
}
static void ucb1400_ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16 y)
static void ucb1400_ts_report_event(struct input_dev *idev, u16 pressure, u16 x, u16 y)
{
input_report_abs(idev, ABS_X, x);
input_report_abs(idev, ABS_Y, y);
@@ -162,7 +164,7 @@ static void ucb1400_ts_event_release(struct input_dev *idev)
input_sync(idev);
}
static void ucb1400_handle_pending_irq(struct ucb1400_ts *ucb)
static void ucb1400_clear_pending_irq(struct ucb1400_ts *ucb)
{
unsigned int isr;
@@ -171,32 +173,34 @@ static void ucb1400_handle_pending_irq(struct ucb1400_ts *ucb)
ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
if (isr & UCB_IE_TSPX)
ucb1400_ts_irq_disable(ucb->ac97);
ucb1400_ts_irq_disable(ucb);
else
dev_dbg(&ucb->ts_idev->dev, "ucb1400: unexpected IE_STATUS = %#x\n", isr);
enable_irq(ucb->irq);
dev_dbg(&ucb->ts_idev->dev,
"ucb1400: unexpected IE_STATUS = %#x\n", isr);
}
static int ucb1400_ts_thread(void *_ucb)
/*
* A restriction with interrupts exists when using the ucb1400, as
* the codec read/write routines may sleep while waiting for codec
* access completion and uses semaphores for access control to the
* AC97 bus. Therefore the driver is forced to use threaded interrupt
* handler.
*/
static irqreturn_t ucb1400_irq(int irqnr, void *devid)
{
struct ucb1400_ts *ucb = _ucb;
struct task_struct *tsk = current;
int valid = 0;
struct sched_param param = { .sched_priority = 1 };
struct ucb1400_ts *ucb = devid;
unsigned int x, y, p;
bool penup;
sched_setscheduler(tsk, SCHED_FIFO, &param);
if (unlikely(irqnr != ucb->irq))
return IRQ_NONE;
set_freezable();
while (!kthread_should_stop()) {
unsigned int x, y, p;
long timeout;
ucb1400_clear_pending_irq(ucb);
ucb->ts_restart = 0;
/* Start with a small delay before checking pendown state */
msleep(UCB1400_TS_POLL_PERIOD);
if (ucb->irq_pending) {
ucb->irq_pending = 0;
ucb1400_handle_pending_irq(ucb);
}
while (!ucb->stopped && !(penup = ucb1400_ts_pen_up(ucb))) {
ucb1400_adc_enable(ucb->ac97);
x = ucb1400_ts_read_xpos(ucb);
@@ -204,91 +208,62 @@ static int ucb1400_ts_thread(void *_ucb)
p = ucb1400_ts_read_pressure(ucb);
ucb1400_adc_disable(ucb->ac97);
/* Switch back to interrupt mode. */
ucb1400_ts_mode_int(ucb->ac97);
ucb1400_ts_report_event(ucb->ts_idev, p, x, y);
msleep(10);
if (ucb1400_ts_pen_up(ucb->ac97)) {
ucb1400_ts_irq_enable(ucb->ac97);
/*
* If we spat out a valid sample set last time,
* spit out a "pen off" sample here.
*/
if (valid) {
ucb1400_ts_event_release(ucb->ts_idev);
valid = 0;
}
timeout = MAX_SCHEDULE_TIMEOUT;
} else {
valid = 1;
ucb1400_ts_evt_add(ucb->ts_idev, p, x, y);
timeout = msecs_to_jiffies(10);
}
wait_event_freezable_timeout(ucb->ts_wait,
ucb->irq_pending || ucb->ts_restart ||
kthread_should_stop(), timeout);
wait_event_timeout(ucb->ts_wait, ucb->stopped,
msecs_to_jiffies(UCB1400_TS_POLL_PERIOD));
}
/* Send the "pen off" if we are stopping with the pen still active */
if (valid)
ucb1400_ts_event_release(ucb->ts_idev);
ucb1400_ts_event_release(ucb->ts_idev);
ucb->ts_task = NULL;
return 0;
if (!ucb->stopped) {
/* Switch back to interrupt mode. */
ucb1400_ts_mode_int(ucb);
ucb1400_ts_irq_enable(ucb);
}
return IRQ_HANDLED;
}
/*
* A restriction with interrupts exists when using the ucb1400, as
* the codec read/write routines may sleep while waiting for codec
* access completion and uses semaphores for access control to the
* AC97 bus. A complete codec read cycle could take anywhere from
* 60 to 100uSec so we *definitely* don't want to spin inside the
* interrupt handler waiting for codec access. So, we handle the
* interrupt by scheduling a RT kernel thread to run in process
* context instead of interrupt context.
*/
static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid)
static void ucb1400_ts_stop(struct ucb1400_ts *ucb)
{
struct ucb1400_ts *ucb = devid;
/* Signal IRQ thread to stop polling and disable the handler. */
ucb->stopped = true;
mb();
wake_up(&ucb->ts_wait);
disable_irq(ucb->irq);
if (irqnr == ucb->irq) {
disable_irq_nosync(ucb->irq);
ucb->irq_pending = 1;
wake_up(&ucb->ts_wait);
return IRQ_HANDLED;
}
return IRQ_NONE;
ucb1400_ts_irq_disable(ucb);
ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0);
}
/* Must be called with ts->lock held */
static void ucb1400_ts_start(struct ucb1400_ts *ucb)
{
/* Tell IRQ thread that it may poll the device. */
ucb->stopped = false;
mb();
ucb1400_ts_mode_int(ucb);
ucb1400_ts_irq_enable(ucb);
enable_irq(ucb->irq);
}
static int ucb1400_ts_open(struct input_dev *idev)
{
struct ucb1400_ts *ucb = input_get_drvdata(idev);
int ret = 0;
BUG_ON(ucb->ts_task);
ucb1400_ts_start(ucb);
ucb->ts_task = kthread_run(ucb1400_ts_thread, ucb, "UCB1400_ts");
if (IS_ERR(ucb->ts_task)) {
ret = PTR_ERR(ucb->ts_task);
ucb->ts_task = NULL;
}
return ret;
return 0;
}
static void ucb1400_ts_close(struct input_dev *idev)
{
struct ucb1400_ts *ucb = input_get_drvdata(idev);
if (ucb->ts_task)
kthread_stop(ucb->ts_task);
ucb1400_ts_irq_disable(ucb->ac97);
ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0);
ucb1400_ts_stop(ucb);
}
#ifndef NO_IRQ
@@ -299,7 +274,8 @@ static void ucb1400_ts_close(struct input_dev *idev)
* Try to probe our interrupt, rather than relying on lots of
* hard-coded machine dependencies.
*/
static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb)
static int __devinit ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,
struct platform_device *pdev)
{
unsigned long mask, timeout;
@@ -321,7 +297,7 @@ static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb)
UCB_ADC_DAT_VALID)) {
cpu_relax();
if (time_after(jiffies, timeout)) {
printk(KERN_ERR "ucb1400: timed out in IRQ probe\n");
dev_err(&pdev->dev, "timed out in IRQ probe\n");
probe_irq_off(mask);
return -ENODEV;
}
@@ -342,11 +318,11 @@ static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb)
return 0;
}
static int ucb1400_ts_probe(struct platform_device *dev)
static int __devinit ucb1400_ts_probe(struct platform_device *pdev)
{
struct ucb1400_ts *ucb = pdev->dev.platform_data;
int error, x_res, y_res;
u16 fcsr;
struct ucb1400_ts *ucb = dev->dev.platform_data;
ucb->ts_idev = input_allocate_device();
if (!ucb->ts_idev) {
@@ -356,27 +332,19 @@ static int ucb1400_ts_probe(struct platform_device *dev)
/* Only in case the IRQ line wasn't supplied, try detecting it */
if (ucb->irq < 0) {
error = ucb1400_ts_detect_irq(ucb);
error = ucb1400_ts_detect_irq(ucb, pdev);
if (error) {
printk(KERN_ERR "UCB1400: IRQ probe failed\n");
dev_err(&pdev->dev, "IRQ probe failed\n");
goto err_free_devs;
}
}
dev_dbg(&pdev->dev, "found IRQ %d\n", ucb->irq);
init_waitqueue_head(&ucb->ts_wait);
error = request_irq(ucb->irq, ucb1400_hard_irq, IRQF_TRIGGER_RISING,
"UCB1400", ucb);
if (error) {
printk(KERN_ERR "ucb1400: unable to grab irq%d: %d\n",
ucb->irq, error);
goto err_free_devs;
}
printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
input_set_drvdata(ucb->ts_idev, ucb);
ucb->ts_idev->dev.parent = &dev->dev;
ucb->ts_idev->dev.parent = &pdev->dev;
ucb->ts_idev->name = "UCB1400 touchscreen interface";
ucb->ts_idev->id.vendor = ucb1400_reg_read(ucb->ac97,
AC97_VENDOR_ID1);
@@ -398,12 +366,23 @@ static int ucb1400_ts_probe(struct platform_device *dev)
x_res = ucb1400_ts_read_xres(ucb);
y_res = ucb1400_ts_read_yres(ucb);
ucb1400_adc_disable(ucb->ac97);
printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res);
dev_dbg(&pdev->dev, "x/y = %d/%d\n", x_res, y_res);
input_set_abs_params(ucb->ts_idev, ABS_X, 0, x_res, 0, 0);
input_set_abs_params(ucb->ts_idev, ABS_Y, 0, y_res, 0, 0);
input_set_abs_params(ucb->ts_idev, ABS_PRESSURE, 0, 0, 0, 0);
ucb1400_ts_stop(ucb);
error = request_threaded_irq(ucb->irq, NULL, ucb1400_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"UCB1400", ucb);
if (error) {
dev_err(&pdev->dev,
"unable to grab irq%d: %d\n", ucb->irq, error);
goto err_free_devs;
}
error = input_register_device(ucb->ts_idev);
if (error)
goto err_free_irq;
@@ -416,56 +395,61 @@ err_free_devs:
input_free_device(ucb->ts_idev);
err:
return error;
}
static int ucb1400_ts_remove(struct platform_device *dev)
static int __devexit ucb1400_ts_remove(struct platform_device *pdev)
{
struct ucb1400_ts *ucb = dev->dev.platform_data;
struct ucb1400_ts *ucb = pdev->dev.platform_data;
free_irq(ucb->irq, ucb);
input_unregister_device(ucb->ts_idev);
return 0;
}
#ifdef CONFIG_PM
static int ucb1400_ts_resume(struct platform_device *dev)
#ifdef CONFIG_PM_SLEEP
static int ucb1400_ts_suspend(struct device *dev)
{
struct ucb1400_ts *ucb = dev->dev.platform_data;
struct ucb1400_ts *ucb = dev->platform_data;
struct input_dev *idev = ucb->ts_idev;
if (ucb->ts_task) {
/*
* Restart the TS thread to ensure the
* TS interrupt mode is set up again
* after sleep.
*/
ucb->ts_restart = 1;
wake_up(&ucb->ts_wait);
}
mutex_lock(&idev->mutex);
if (idev->users)
ucb1400_ts_start(ucb);
mutex_unlock(&idev->mutex);
return 0;
}
static int ucb1400_ts_resume(struct device *dev)
{
struct ucb1400_ts *ucb = dev->platform_data;
struct input_dev *idev = ucb->ts_idev;
mutex_lock(&idev->mutex);
if (idev->users)
ucb1400_ts_stop(ucb);
mutex_unlock(&idev->mutex);
return 0;
}
#else
#define ucb1400_ts_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops,
ucb1400_ts_suspend, ucb1400_ts_resume);
static struct platform_driver ucb1400_ts_driver = {
.probe = ucb1400_ts_probe,
.remove = ucb1400_ts_remove,
.resume = ucb1400_ts_resume,
.remove = __devexit_p(ucb1400_ts_remove),
.driver = {
.name = "ucb1400_ts",
.owner = THIS_MODULE,
.pm = &ucb1400_ts_pm_ops,
},
};
static int __init ucb1400_ts_init(void)
{
return platform_driver_register(&ucb1400_ts_driver);
}
static void __exit ucb1400_ts_exit(void)
{
platform_driver_unregister(&ucb1400_ts_driver);
}
module_platform_driver(ucb1400_ts_driver);
module_param(adcsync, bool, 0444);
MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
@@ -479,8 +463,5 @@ MODULE_PARM_DESC(ts_delay_pressure,
"delay between panel setup and pressure read."
" Default = 0us.");
module_init(ucb1400_ts_init);
module_exit(ucb1400_ts_exit);
MODULE_DESCRIPTION("Philips UCB1400 touchscreen driver");
MODULE_LICENSE("GPL");
@@ -16,6 +16,7 @@
* - JASTEC USB touch controller/DigiTech DTR-02U
* - Zytronic capacitive touchscreen
* - NEXIO/iNexio
* - Elo TouchSystems 2700 IntelliTouch
*
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -138,6 +139,7 @@ enum {
DEVTYPE_ZYTRONIC,
DEVTYPE_TC45USB,
DEVTYPE_NEXIO,
DEVTYPE_ELO,
};
#define USB_DEVICE_HID_CLASS(vend, prod) \
@@ -239,6 +241,10 @@ static const struct usb_device_id usbtouch_devices[] = {
.driver_info = DEVTYPE_NEXIO},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_ELO
{USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
#endif
{}
};
@@ -944,6 +950,24 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
#endif
/*****************************************************************************
* ELO part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_ELO
static int elo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
dev->x = (pkt[3] << 8) | pkt[2];
dev->y = (pkt[5] << 8) | pkt[4];
dev->touch = pkt[6] > 0;
dev->press = pkt[6];
return 1;
}
#endif
/*****************************************************************************
* the different device descriptors
*/
@@ -953,6 +977,18 @@ static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
#endif
static struct usbtouch_device_info usbtouch_dev_info[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_ELO
[DEVTYPE_ELO] = {
.min_xc = 0x0,
.max_xc = 0x0fff,
.min_yc = 0x0,
.max_yc = 0x0fff,
.max_press = 0xff,
.rept_size = 8,
.read_data = elo_read_data,
},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
[DEVTYPE_EGALAX] = {
.min_xc = 0x0,
+1 -13
View File
@@ -331,19 +331,7 @@ static struct platform_driver w90x900ts_driver = {
.owner = THIS_MODULE,
},
};
static int __init w90x900ts_init(void)
{
return platform_driver_register(&w90x900ts_driver);
}
static void __exit w90x900ts_exit(void)
{
platform_driver_unregister(&w90x900ts_driver);
}
module_init(w90x900ts_init);
module_exit(w90x900ts_exit);
module_platform_driver(w90x900ts_driver);
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("w90p910 touch screen driver!");
+1 -12
View File
@@ -401,18 +401,7 @@ static struct platform_driver wm831x_ts_driver = {
.probe = wm831x_ts_probe,
.remove = __devexit_p(wm831x_ts_remove),
};
static int __init wm831x_ts_init(void)
{
return platform_driver_register(&wm831x_ts_driver);
}
module_init(wm831x_ts_init);
static void __exit wm831x_ts_exit(void)
{
platform_driver_unregister(&wm831x_ts_driver);
}
module_exit(wm831x_ts_exit);
module_platform_driver(wm831x_ts_driver);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+1 -13
View File
@@ -224,19 +224,7 @@ static struct platform_driver zylonite_wm97xx_driver = {
.name = "wm97xx-touch",
},
};
static int __init zylonite_wm97xx_init(void)
{
return platform_driver_register(&zylonite_wm97xx_driver);
}
static void __exit zylonite_wm97xx_exit(void)
{
platform_driver_unregister(&zylonite_wm97xx_driver);
}
module_init(zylonite_wm97xx_init);
module_exit(zylonite_wm97xx_exit);
module_platform_driver(zylonite_wm97xx_driver);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");