You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next' into for-linus
This commit is contained in:
@@ -651,6 +651,18 @@ config TOUCHSCREEN_TOUCHIT213
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called touchit213.
|
||||
|
||||
config TOUCHSCREEN_TSC_SERIO
|
||||
tristate "TSC-10/25/40 serial touchscreen support"
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a TSC-10, 25 or 40 serial touchscreen connected
|
||||
to your system.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tsc40.
|
||||
|
||||
config TOUCHSCREEN_TSC2005
|
||||
tristate "TSC2005 based touchscreens"
|
||||
depends on SPI_MASTER && GENERIC_HARDIRQS
|
||||
|
||||
@@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int ad7879_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
@@ -36,9 +36,9 @@ static int ad7879_i2c_resume(struct device *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume);
|
||||
#endif
|
||||
|
||||
/* All registers are word-sized.
|
||||
* AD7879 uses a high-byte first convention.
|
||||
@@ -119,9 +119,7 @@ static struct i2c_driver ad7879_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad7879",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &ad7879_i2c_pm,
|
||||
#endif
|
||||
},
|
||||
.probe = ad7879_i2c_probe,
|
||||
.remove = __devexit_p(ad7879_i2c_remove),
|
||||
|
||||
@@ -910,12 +910,17 @@ static ssize_t mxt_object_show(struct device *dev,
|
||||
for (i = 0; i < data->info.object_num; i++) {
|
||||
object = data->object_table + i;
|
||||
|
||||
count += sprintf(buf + count,
|
||||
"Object Table Element %d(Type %d)\n",
|
||||
count += snprintf(buf + count, PAGE_SIZE - count,
|
||||
"Object[%d] (Type %d)\n",
|
||||
i + 1, object->type);
|
||||
if (count >= PAGE_SIZE)
|
||||
return PAGE_SIZE - 1;
|
||||
|
||||
if (!mxt_object_readable(object->type)) {
|
||||
count += sprintf(buf + count, "\n");
|
||||
count += snprintf(buf + count, PAGE_SIZE - count,
|
||||
"\n");
|
||||
if (count >= PAGE_SIZE)
|
||||
return PAGE_SIZE - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -925,11 +930,15 @@ static ssize_t mxt_object_show(struct device *dev,
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
count += sprintf(buf + count,
|
||||
" Byte %d: 0x%x (%d)\n", j, val, val);
|
||||
count += snprintf(buf + count, PAGE_SIZE - count,
|
||||
"\t[%2d]: %02x (%d)\n", j, val, val);
|
||||
if (count >= PAGE_SIZE)
|
||||
return PAGE_SIZE - 1;
|
||||
}
|
||||
|
||||
count += sprintf(buf + count, "\n");
|
||||
count += snprintf(buf + count, PAGE_SIZE - count, "\n");
|
||||
if (count >= PAGE_SIZE)
|
||||
return PAGE_SIZE - 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
@@ -229,7 +229,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
|
||||
goto err_release_mem;
|
||||
}
|
||||
|
||||
err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, IRQF_DISABLED,
|
||||
err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0,
|
||||
pdev->dev.driver->name, ts_dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to allocate irq.\n");
|
||||
|
||||
@@ -396,14 +396,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
|
||||
set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
|
||||
|
||||
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
|
||||
IRQF_SHARED | IRQF_DISABLED, "h3600_action", ts->dev)) {
|
||||
IRQF_SHARED, "h3600_action", ts->dev)) {
|
||||
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
|
||||
err = -EBUSY;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
|
||||
IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", ts->dev)) {
|
||||
IRQF_SHARED, "h3600_suspend", ts->dev)) {
|
||||
printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
|
||||
err = -EBUSY;
|
||||
goto fail2;
|
||||
|
||||
@@ -93,7 +93,7 @@ static int __init hp680_ts_init(void)
|
||||
hp680_ts_dev->phys = "hp680_ts/input0";
|
||||
|
||||
if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
|
||||
IRQF_DISABLED, MODNAME, 0) < 0) {
|
||||
0, MODNAME, 0) < 0) {
|
||||
printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
|
||||
HP680_TS_IRQ);
|
||||
err = -EBUSY;
|
||||
|
||||
@@ -127,7 +127,7 @@ static int __devinit jornada720_ts_probe(struct platform_device *pdev)
|
||||
|
||||
error = request_irq(IRQ_GPIO9,
|
||||
jornada720_ts_interrupt,
|
||||
IRQF_DISABLED | IRQF_TRIGGER_RISING,
|
||||
IRQF_TRIGGER_RISING,
|
||||
"HP7XX Touchscreen driver", pdev);
|
||||
if (error) {
|
||||
printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");
|
||||
|
||||
@@ -276,7 +276,7 @@ static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)
|
||||
input_set_drvdata(input, tsc);
|
||||
|
||||
error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
|
||||
IRQF_DISABLED, pdev->name, tsc);
|
||||
0, pdev->name, tsc);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed requesting interrupt\n");
|
||||
goto err_put_clock;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Penmount serial touchscreen driver
|
||||
*
|
||||
* Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
|
||||
* Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
|
||||
*
|
||||
* Based on ELO driver (drivers/input/touchscreen/elo.c)
|
||||
* Copyright (c) 2004 Vojtech Pavlik
|
||||
@@ -18,12 +19,14 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DRIVER_DESC "Penmount serial touchscreen driver"
|
||||
#define DRIVER_DESC "PenMount serial touchscreen driver"
|
||||
|
||||
MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
|
||||
MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -31,7 +34,19 @@ MODULE_LICENSE("GPL");
|
||||
* Definitions & global arrays.
|
||||
*/
|
||||
|
||||
#define PM_MAX_LENGTH 5
|
||||
#define PM_MAX_LENGTH 6
|
||||
#define PM_MAX_MTSLOT 16
|
||||
#define PM_3000_MTSLOT 2
|
||||
#define PM_6250_MTSLOT 12
|
||||
|
||||
/*
|
||||
* Multi-touch slot
|
||||
*/
|
||||
|
||||
struct mt_slot {
|
||||
unsigned short x, y;
|
||||
bool active; /* is the touch valid? */
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-touchscreen data.
|
||||
@@ -43,25 +58,119 @@ struct pm {
|
||||
int idx;
|
||||
unsigned char data[PM_MAX_LENGTH];
|
||||
char phys[32];
|
||||
unsigned char packetsize;
|
||||
unsigned char maxcontacts;
|
||||
struct mt_slot slots[PM_MAX_MTSLOT];
|
||||
void (*parse_packet)(struct pm *);
|
||||
};
|
||||
|
||||
/*
|
||||
* pm_mtevent() sends mt events and also emulates pointer movement
|
||||
*/
|
||||
|
||||
static void pm_mtevent(struct pm *pm, struct input_dev *input)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pm->maxcontacts; ++i) {
|
||||
input_mt_slot(input, i);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER,
|
||||
pm->slots[i].active);
|
||||
if (pm->slots[i].active) {
|
||||
input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x);
|
||||
input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y);
|
||||
}
|
||||
}
|
||||
|
||||
input_mt_report_pointer_emulation(input, true);
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
/*
|
||||
* pm_checkpacket() checks if data packet is valid
|
||||
*/
|
||||
|
||||
static bool pm_checkpacket(unsigned char *packet)
|
||||
{
|
||||
int total = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
total += packet[i];
|
||||
|
||||
return packet[5] == (unsigned char)~(total & 0xff);
|
||||
}
|
||||
|
||||
static void pm_parse_9000(struct pm *pm)
|
||||
{
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
if ((pm->data[0] & 0x80) && pm->packetsize == ++pm->idx) {
|
||||
input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]);
|
||||
input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]);
|
||||
input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
|
||||
input_sync(dev);
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_parse_6000(struct pm *pm)
|
||||
{
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
if ((pm->data[0] & 0xbf) == 0x30 && pm->packetsize == ++pm->idx) {
|
||||
if (pm_checkpacket(pm->data)) {
|
||||
input_report_abs(dev, ABS_X,
|
||||
pm->data[2] * 256 + pm->data[1]);
|
||||
input_report_abs(dev, ABS_Y,
|
||||
pm->data[4] * 256 + pm->data[3]);
|
||||
input_report_key(dev, BTN_TOUCH, pm->data[0] & 0x40);
|
||||
input_sync(dev);
|
||||
}
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_parse_3000(struct pm *pm)
|
||||
{
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
if ((pm->data[0] & 0xce) == 0x40 && pm->packetsize == ++pm->idx) {
|
||||
if (pm_checkpacket(pm->data)) {
|
||||
int slotnum = pm->data[0] & 0x0f;
|
||||
pm->slots[slotnum].active = pm->data[0] & 0x30;
|
||||
pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
|
||||
pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
|
||||
pm_mtevent(pm, dev);
|
||||
}
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_parse_6250(struct pm *pm)
|
||||
{
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
if ((pm->data[0] & 0xb0) == 0x30 && pm->packetsize == ++pm->idx) {
|
||||
if (pm_checkpacket(pm->data)) {
|
||||
int slotnum = pm->data[0] & 0x0f;
|
||||
pm->slots[slotnum].active = pm->data[0] & 0x40;
|
||||
pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
|
||||
pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
|
||||
pm_mtevent(pm, dev);
|
||||
}
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t pm_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct pm *pm = serio_get_drvdata(serio);
|
||||
struct input_dev *dev = pm->dev;
|
||||
|
||||
pm->data[pm->idx] = data;
|
||||
|
||||
if (pm->data[0] & 0x80) {
|
||||
if (PM_MAX_LENGTH == ++pm->idx) {
|
||||
input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]);
|
||||
input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]);
|
||||
input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
|
||||
input_sync(dev);
|
||||
pm->idx = 0;
|
||||
}
|
||||
}
|
||||
pm->parse_packet(pm);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -74,17 +183,17 @@ static void pm_disconnect(struct serio *serio)
|
||||
{
|
||||
struct pm *pm = serio_get_drvdata(serio);
|
||||
|
||||
input_get_device(pm->dev);
|
||||
input_unregister_device(pm->dev);
|
||||
serio_close(serio);
|
||||
serio_set_drvdata(serio, NULL);
|
||||
input_put_device(pm->dev);
|
||||
|
||||
input_unregister_device(pm->dev);
|
||||
kfree(pm);
|
||||
|
||||
serio_set_drvdata(serio, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* pm_connect() is the routine that is called when someone adds a
|
||||
* new serio device that supports Gunze protocol and registers it as
|
||||
* new serio device that supports PenMount protocol and registers it as
|
||||
* an input device.
|
||||
*/
|
||||
|
||||
@@ -92,6 +201,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct pm *pm;
|
||||
struct input_dev *input_dev;
|
||||
int max_x, max_y;
|
||||
int err;
|
||||
|
||||
pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
|
||||
@@ -104,8 +214,9 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
|
||||
pm->serio = serio;
|
||||
pm->dev = input_dev;
|
||||
snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
|
||||
pm->maxcontacts = 1;
|
||||
|
||||
input_dev->name = "Penmount Serial TouchScreen";
|
||||
input_dev->name = "PenMount Serial TouchScreen";
|
||||
input_dev->phys = pm->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_PENMOUNT;
|
||||
@@ -113,10 +224,52 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0);
|
||||
input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0);
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
|
||||
switch (serio->id.id) {
|
||||
default:
|
||||
case 0:
|
||||
pm->packetsize = 5;
|
||||
pm->parse_packet = pm_parse_9000;
|
||||
input_dev->id.product = 0x9000;
|
||||
max_x = max_y = 0x3ff;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pm->packetsize = 6;
|
||||
pm->parse_packet = pm_parse_6000;
|
||||
input_dev->id.product = 0x6000;
|
||||
max_x = max_y = 0x3ff;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
pm->packetsize = 6;
|
||||
pm->parse_packet = pm_parse_3000;
|
||||
input_dev->id.product = 0x3000;
|
||||
max_x = max_y = 0x7ff;
|
||||
pm->maxcontacts = PM_3000_MTSLOT;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
pm->packetsize = 6;
|
||||
pm->parse_packet = pm_parse_6250;
|
||||
input_dev->id.product = 0x6250;
|
||||
max_x = max_y = 0x3ff;
|
||||
pm->maxcontacts = PM_6250_MTSLOT;
|
||||
break;
|
||||
}
|
||||
|
||||
input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0);
|
||||
input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
|
||||
|
||||
if (pm->maxcontacts > 1) {
|
||||
input_mt_init_slots(pm->dev, pm->maxcontacts);
|
||||
input_set_abs_params(pm->dev,
|
||||
ABS_MT_POSITION_X, 0, max_x, 0, 0);
|
||||
input_set_abs_params(pm->dev,
|
||||
ABS_MT_POSITION_Y, 0, max_y, 0, 0);
|
||||
}
|
||||
|
||||
serio_set_drvdata(serio, pm);
|
||||
|
||||
@@ -155,7 +308,7 @@ MODULE_DEVICE_TABLE(serio, pm_serio_ids);
|
||||
|
||||
static struct serio_driver pm_drv = {
|
||||
.driver = {
|
||||
.name = "penmountlpc",
|
||||
.name = "serio-penmount",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.id_table = pm_serio_ids,
|
||||
|
||||
@@ -328,7 +328,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
|
||||
ts.shift = info->oversampling_shift;
|
||||
ts.features = platform_get_device_id(pdev)->driver_data;
|
||||
|
||||
ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED,
|
||||
ret = request_irq(ts.irq_tc, stylus_irq, 0,
|
||||
"s3c2410_ts_pen", ts.input);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot get TC interrupt\n");
|
||||
|
||||
+120
-102
@@ -66,7 +66,6 @@ struct ts_event {
|
||||
struct tsc2007 {
|
||||
struct input_dev *input;
|
||||
char phys[32];
|
||||
struct delayed_work work;
|
||||
|
||||
struct i2c_client *client;
|
||||
|
||||
@@ -76,9 +75,11 @@ struct tsc2007 {
|
||||
unsigned long poll_delay;
|
||||
unsigned long poll_period;
|
||||
|
||||
bool pendown;
|
||||
int irq;
|
||||
|
||||
wait_queue_head_t wait;
|
||||
bool stopped;
|
||||
|
||||
int (*get_pendown_state)(void);
|
||||
void (*clear_penirq)(void);
|
||||
};
|
||||
@@ -141,25 +142,8 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
|
||||
return rt;
|
||||
}
|
||||
|
||||
static void tsc2007_send_up_event(struct tsc2007 *tsc)
|
||||
static bool tsc2007_is_pen_down(struct tsc2007 *ts)
|
||||
{
|
||||
struct input_dev *input = tsc->input;
|
||||
|
||||
dev_dbg(&tsc->client->dev, "UP\n");
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 0);
|
||||
input_report_abs(input, ABS_PRESSURE, 0);
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
static void tsc2007_work(struct work_struct *work)
|
||||
{
|
||||
struct tsc2007 *ts =
|
||||
container_of(to_delayed_work(work), struct tsc2007, work);
|
||||
bool debounced = false;
|
||||
struct ts_event tc;
|
||||
u32 rt;
|
||||
|
||||
/*
|
||||
* NOTE: We can't rely on the pressure to determine the pen down
|
||||
* state, even though this controller has a pressure sensor.
|
||||
@@ -170,97 +154,123 @@ static void tsc2007_work(struct work_struct *work)
|
||||
* The only safe way to check for the pen up condition is in the
|
||||
* work function by reading the pen signal state (it's a GPIO
|
||||
* and IRQ). Unfortunately such callback is not always available,
|
||||
* in that case we have rely on the pressure anyway.
|
||||
* in that case we assume that the pen is down and expect caller
|
||||
* to fall back on the pressure reading.
|
||||
*/
|
||||
if (ts->get_pendown_state) {
|
||||
if (unlikely(!ts->get_pendown_state())) {
|
||||
tsc2007_send_up_event(ts);
|
||||
ts->pendown = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(&ts->client->dev, "pen is still down\n");
|
||||
}
|
||||
if (!ts->get_pendown_state)
|
||||
return true;
|
||||
|
||||
tsc2007_read_values(ts, &tc);
|
||||
|
||||
rt = tsc2007_calculate_pressure(ts, &tc);
|
||||
if (rt > ts->max_rt) {
|
||||
/*
|
||||
* Sample found inconsistent by debouncing or pressure is
|
||||
* beyond the maximum. Don't report it to user space,
|
||||
* repeat at least once more the measurement.
|
||||
*/
|
||||
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
|
||||
debounced = true;
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
if (rt) {
|
||||
struct input_dev *input = ts->input;
|
||||
|
||||
if (!ts->pendown) {
|
||||
dev_dbg(&ts->client->dev, "DOWN\n");
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 1);
|
||||
ts->pendown = true;
|
||||
}
|
||||
|
||||
input_report_abs(input, ABS_X, tc.x);
|
||||
input_report_abs(input, ABS_Y, tc.y);
|
||||
input_report_abs(input, ABS_PRESSURE, rt);
|
||||
|
||||
input_sync(input);
|
||||
|
||||
dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
|
||||
tc.x, tc.y, rt);
|
||||
|
||||
} else if (!ts->get_pendown_state && ts->pendown) {
|
||||
/*
|
||||
* We don't have callback to check pendown state, so we
|
||||
* have to assume that since pressure reported is 0 the
|
||||
* pen was lifted up.
|
||||
*/
|
||||
tsc2007_send_up_event(ts);
|
||||
ts->pendown = false;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ts->pendown || debounced)
|
||||
schedule_delayed_work(&ts->work,
|
||||
msecs_to_jiffies(ts->poll_period));
|
||||
else
|
||||
enable_irq(ts->irq);
|
||||
return ts->get_pendown_state();
|
||||
}
|
||||
|
||||
static irqreturn_t tsc2007_irq(int irq, void *handle)
|
||||
static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
|
||||
{
|
||||
struct tsc2007 *ts = handle;
|
||||
struct input_dev *input = ts->input;
|
||||
struct ts_event tc;
|
||||
u32 rt;
|
||||
|
||||
if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
|
||||
disable_irq_nosync(ts->irq);
|
||||
schedule_delayed_work(&ts->work,
|
||||
msecs_to_jiffies(ts->poll_delay));
|
||||
while (!ts->stopped && tsc2007_is_pen_down(ts)) {
|
||||
|
||||
/* pen is down, continue with the measurement */
|
||||
tsc2007_read_values(ts, &tc);
|
||||
|
||||
rt = tsc2007_calculate_pressure(ts, &tc);
|
||||
|
||||
if (rt == 0 && !ts->get_pendown_state) {
|
||||
/*
|
||||
* If pressure reported is 0 and we don't have
|
||||
* callback to check pendown state, we have to
|
||||
* assume that pen was lifted up.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
if (rt <= ts->max_rt) {
|
||||
dev_dbg(&ts->client->dev,
|
||||
"DOWN point(%4d,%4d), pressure (%4u)\n",
|
||||
tc.x, tc.y, rt);
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 1);
|
||||
input_report_abs(input, ABS_X, tc.x);
|
||||
input_report_abs(input, ABS_Y, tc.y);
|
||||
input_report_abs(input, ABS_PRESSURE, rt);
|
||||
|
||||
input_sync(input);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Sample found inconsistent by debouncing or pressure is
|
||||
* beyond the maximum. Don't report it to user space,
|
||||
* repeat at least once more the measurement.
|
||||
*/
|
||||
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
|
||||
}
|
||||
|
||||
wait_event_timeout(ts->wait, ts->stopped,
|
||||
msecs_to_jiffies(ts->poll_period));
|
||||
}
|
||||
|
||||
dev_dbg(&ts->client->dev, "UP\n");
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 0);
|
||||
input_report_abs(input, ABS_PRESSURE, 0);
|
||||
input_sync(input);
|
||||
|
||||
if (ts->clear_penirq)
|
||||
ts->clear_penirq();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void tsc2007_free_irq(struct tsc2007 *ts)
|
||||
static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
|
||||
{
|
||||
free_irq(ts->irq, ts);
|
||||
if (cancel_delayed_work_sync(&ts->work)) {
|
||||
/*
|
||||
* Work was pending, therefore we need to enable
|
||||
* IRQ here to balance the disable_irq() done in the
|
||||
* interrupt handler.
|
||||
*/
|
||||
enable_irq(ts->irq);
|
||||
struct tsc2007 *ts = handle;
|
||||
|
||||
if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
if (ts->clear_penirq)
|
||||
ts->clear_penirq();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void tsc2007_stop(struct tsc2007 *ts)
|
||||
{
|
||||
ts->stopped = true;
|
||||
mb();
|
||||
wake_up(&ts->wait);
|
||||
|
||||
disable_irq(ts->irq);
|
||||
}
|
||||
|
||||
static int tsc2007_open(struct input_dev *input_dev)
|
||||
{
|
||||
struct tsc2007 *ts = input_get_drvdata(input_dev);
|
||||
int err;
|
||||
|
||||
ts->stopped = false;
|
||||
mb();
|
||||
|
||||
enable_irq(ts->irq);
|
||||
|
||||
/* Prepare for touch readings - power down ADC and enable PENIRQ */
|
||||
err = tsc2007_xfer(ts, PWRDOWN);
|
||||
if (err < 0) {
|
||||
tsc2007_stop(ts);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tsc2007_close(struct input_dev *input_dev)
|
||||
{
|
||||
struct tsc2007 *ts = input_get_drvdata(input_dev);
|
||||
|
||||
tsc2007_stop(ts);
|
||||
}
|
||||
|
||||
static int __devinit tsc2007_probe(struct i2c_client *client,
|
||||
@@ -290,7 +300,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
||||
ts->client = client;
|
||||
ts->irq = client->irq;
|
||||
ts->input = input_dev;
|
||||
INIT_DELAYED_WORK(&ts->work, tsc2007_work);
|
||||
init_waitqueue_head(&ts->wait);
|
||||
|
||||
ts->model = pdata->model;
|
||||
ts->x_plate_ohms = pdata->x_plate_ohms;
|
||||
@@ -300,6 +310,12 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
||||
ts->get_pendown_state = pdata->get_pendown_state;
|
||||
ts->clear_penirq = pdata->clear_penirq;
|
||||
|
||||
if (pdata->x_plate_ohms == 0) {
|
||||
dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
|
||||
err = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
snprintf(ts->phys, sizeof(ts->phys),
|
||||
"%s/input0", dev_name(&client->dev));
|
||||
|
||||
@@ -307,6 +323,11 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
||||
input_dev->phys = ts->phys;
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
|
||||
input_dev->open = tsc2007_open;
|
||||
input_dev->close = tsc2007_close;
|
||||
|
||||
input_set_drvdata(input_dev, ts);
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
|
||||
@@ -318,17 +339,14 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
||||
if (pdata->init_platform_hw)
|
||||
pdata->init_platform_hw();
|
||||
|
||||
err = request_irq(ts->irq, tsc2007_irq, 0,
|
||||
client->dev.driver->name, ts);
|
||||
err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq,
|
||||
IRQF_ONESHOT, client->dev.driver->name, ts);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "irq %d busy?\n", ts->irq);
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
/* Prepare for touch readings - power down ADC and enable PENIRQ */
|
||||
err = tsc2007_xfer(ts, PWRDOWN);
|
||||
if (err < 0)
|
||||
goto err_free_irq;
|
||||
tsc2007_stop(ts);
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err)
|
||||
@@ -339,7 +357,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
tsc2007_free_irq(ts);
|
||||
free_irq(ts->irq, ts);
|
||||
if (pdata->exit_platform_hw)
|
||||
pdata->exit_platform_hw();
|
||||
err_free_mem:
|
||||
@@ -353,7 +371,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
|
||||
struct tsc2007 *ts = i2c_get_clientdata(client);
|
||||
struct tsc2007_platform_data *pdata = client->dev.platform_data;
|
||||
|
||||
tsc2007_free_irq(ts);
|
||||
free_irq(ts->irq, ts);
|
||||
|
||||
if (pdata->exit_platform_hw)
|
||||
pdata->exit_platform_hw();
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* TSC-40 serial touchscreen driver. It should be compatible with
|
||||
* TSC-10 and 25.
|
||||
*
|
||||
* Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
* License: GPLv2 as published by the FSF.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define PACKET_LENGTH 5
|
||||
struct tsc_ser {
|
||||
struct input_dev *dev;
|
||||
struct serio *serio;
|
||||
u32 idx;
|
||||
unsigned char data[PACKET_LENGTH];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static void tsc_process_data(struct tsc_ser *ptsc)
|
||||
{
|
||||
struct input_dev *dev = ptsc->dev;
|
||||
u8 *data = ptsc->data;
|
||||
u32 x;
|
||||
u32 y;
|
||||
|
||||
x = ((data[1] & 0x03) << 8) | data[2];
|
||||
y = ((data[3] & 0x03) << 8) | data[4];
|
||||
|
||||
input_report_abs(dev, ABS_X, x);
|
||||
input_report_abs(dev, ABS_Y, y);
|
||||
input_report_key(dev, BTN_TOUCH, 1);
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
static irqreturn_t tsc_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct tsc_ser *ptsc = serio_get_drvdata(serio);
|
||||
struct input_dev *dev = ptsc->dev;
|
||||
|
||||
ptsc->data[ptsc->idx] = data;
|
||||
switch (ptsc->idx++) {
|
||||
case 0:
|
||||
if (unlikely((data & 0x3e) != 0x10)) {
|
||||
dev_dbg(&serio->dev,
|
||||
"unsynchronized packet start (0x%02x)\n", data);
|
||||
ptsc->idx = 0;
|
||||
} else if (!(data & 0x01)) {
|
||||
input_report_key(dev, BTN_TOUCH, 0);
|
||||
input_sync(dev);
|
||||
ptsc->idx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 3:
|
||||
if (unlikely(data & 0xfc)) {
|
||||
dev_dbg(&serio->dev,
|
||||
"unsynchronized data 0x%02x at offset %d\n",
|
||||
data, ptsc->idx - 1);
|
||||
ptsc->idx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
tsc_process_data(ptsc);
|
||||
ptsc->idx = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tsc_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct tsc_ser *ptsc;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
|
||||
ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!ptsc || !input_dev) {
|
||||
error = -ENOMEM;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
ptsc->serio = serio;
|
||||
ptsc->dev = input_dev;
|
||||
snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
|
||||
|
||||
input_dev->name = "TSC-10/25/40 Serial TouchScreen";
|
||||
input_dev->phys = ptsc->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_TSC40;
|
||||
input_dev->id.product = 40;
|
||||
input_dev->id.version = 0x0001;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
__set_bit(BTN_TOUCH, input_dev->keybit);
|
||||
input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0);
|
||||
input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0);
|
||||
input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 0, 0);
|
||||
|
||||
serio_set_drvdata(serio, ptsc);
|
||||
|
||||
error = serio_open(serio, drv);
|
||||
if (error)
|
||||
goto fail2;
|
||||
|
||||
error = input_register_device(ptsc->dev);
|
||||
if (error)
|
||||
goto fail3;
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
serio_close(serio);
|
||||
fail2:
|
||||
serio_set_drvdata(serio, NULL);
|
||||
fail1:
|
||||
input_free_device(input_dev);
|
||||
kfree(ptsc);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void tsc_disconnect(struct serio *serio)
|
||||
{
|
||||
struct tsc_ser *ptsc = serio_get_drvdata(serio);
|
||||
|
||||
serio_close(serio);
|
||||
|
||||
input_unregister_device(ptsc->dev);
|
||||
kfree(ptsc);
|
||||
|
||||
serio_set_drvdata(serio, NULL);
|
||||
}
|
||||
|
||||
static struct serio_device_id tsc_serio_ids[] = {
|
||||
{
|
||||
.type = SERIO_RS232,
|
||||
.proto = SERIO_TSC40,
|
||||
.id = SERIO_ANY,
|
||||
.extra = SERIO_ANY,
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(serio, tsc_serio_ids);
|
||||
|
||||
#define DRIVER_DESC "TSC-10/25/40 serial touchscreen driver"
|
||||
|
||||
static struct serio_driver tsc_drv = {
|
||||
.driver = {
|
||||
.name = "tsc40",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.id_table = tsc_serio_ids,
|
||||
.interrupt = tsc_interrupt,
|
||||
.connect = tsc_connect,
|
||||
.disconnect = tsc_disconnect,
|
||||
};
|
||||
|
||||
static int __init tsc_ser_init(void)
|
||||
{
|
||||
return serio_register_driver(&tsc_drv);
|
||||
}
|
||||
module_init(tsc_ser_init);
|
||||
|
||||
static void __exit tsc_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&tsc_drv);
|
||||
}
|
||||
module_exit(tsc_exit);
|
||||
|
||||
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -279,7 +279,7 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
|
||||
|
||||
w90p910_ts->irq_num = platform_get_irq(pdev, 0);
|
||||
if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
|
||||
IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
|
||||
0, "w90p910ts", w90p910_ts)) {
|
||||
err = -EBUSY;
|
||||
goto fail4;
|
||||
}
|
||||
|
||||
@@ -367,6 +367,20 @@ static int w8001_command(struct w8001 *w8001, unsigned char command,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int w8001_open(struct input_dev *dev)
|
||||
{
|
||||
struct w8001 *w8001 = input_get_drvdata(dev);
|
||||
|
||||
return w8001_command(w8001, W8001_CMD_START, false);
|
||||
}
|
||||
|
||||
static void w8001_close(struct input_dev *dev)
|
||||
{
|
||||
struct w8001 *w8001 = input_get_drvdata(dev);
|
||||
|
||||
w8001_command(w8001, W8001_CMD_STOP, false);
|
||||
}
|
||||
|
||||
static int w8001_setup(struct w8001 *w8001)
|
||||
{
|
||||
struct input_dev *dev = w8001->dev;
|
||||
@@ -476,7 +490,7 @@ static int w8001_setup(struct w8001 *w8001)
|
||||
|
||||
strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
|
||||
|
||||
return w8001_command(w8001, W8001_CMD_START, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -487,12 +501,12 @@ static void w8001_disconnect(struct serio *serio)
|
||||
{
|
||||
struct w8001 *w8001 = serio_get_drvdata(serio);
|
||||
|
||||
input_get_device(w8001->dev);
|
||||
input_unregister_device(w8001->dev);
|
||||
serio_close(serio);
|
||||
serio_set_drvdata(serio, NULL);
|
||||
input_put_device(w8001->dev);
|
||||
|
||||
input_unregister_device(w8001->dev);
|
||||
kfree(w8001);
|
||||
|
||||
serio_set_drvdata(serio, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -536,6 +550,11 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->open = w8001_open;
|
||||
input_dev->close = w8001_close;
|
||||
|
||||
input_set_drvdata(input_dev, w8001);
|
||||
|
||||
err = input_register_device(w8001->dev);
|
||||
if (err)
|
||||
goto fail3;
|
||||
|
||||
Reference in New Issue
Block a user