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: (52 commits) Input: bcm5974 - silence uninitialized variables warnings Input: wistron_btns - add keymap for AOpen 1557 Input: psmouse - use boolean type Input: i8042 - use platform_driver_probe Input: i8042 - use boolean type where it makes sense Input: i8042 - try disabling and re-enabling AUX port at close Input: pxa27x_keypad - allow modifying keymap from userspace Input: sunkbd - fix formatting Input: i8042 - bypass AUX IRQ delivery test on laptops Input: wacom_w8001 - simplify querying logic Input: atkbd - allow setting force-release bitmap via sysfs Input: w90p910_keypad - move a dereference below a NULL test Input: add twl4030_keypad driver Input: matrix-keypad - add function to build device keymap Input: tosakbd - fix cleaning up KEY_STROBEs after error Input: joydev - validate axis/button maps before clobbering current ones Input: xpad - add USB ID for the drumkit controller from Rock Band Input: w90p910_keypad - rename driver name to match platform Input: add new driver for Sentelic Finger Sensing Pad Input: psmouse - allow defining read-only attributes ...
This commit is contained in:
@@ -366,11 +366,11 @@ config TOUCHSCREEN_WM97XX_ATMEL
|
||||
be called atmel-wm97xx.
|
||||
|
||||
config TOUCHSCREEN_WM97XX_MAINSTONE
|
||||
tristate "WM97xx Mainstone accelerated touch"
|
||||
tristate "WM97xx Mainstone/Palm accelerated touch"
|
||||
depends on TOUCHSCREEN_WM97XX && ARCH_PXA
|
||||
help
|
||||
Say Y here for support for streaming mode with WM97xx touchscreens
|
||||
on Mainstone systems.
|
||||
on Mainstone, Palm Tungsten T5, TX and LifeDrive systems.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
@@ -406,6 +406,7 @@ config TOUCHSCREEN_USB_COMPOSITE
|
||||
- IRTOUCHSYSTEMS/UNITOP
|
||||
- IdealTEK URTC1000
|
||||
- GoTop Super_Q2/GogoPen/PenPower tablets
|
||||
- JASTEC USB Touch Controller/DigiTech DTR-02U
|
||||
|
||||
Have a look at <http://linux.chapter7.ch/touchkit/> for
|
||||
a usage description and the required user-space stuff.
|
||||
@@ -468,6 +469,16 @@ config TOUCHSCREEN_USB_GOTOP
|
||||
bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
config TOUCHSCREEN_USB_JASTEC
|
||||
default y
|
||||
bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
config TOUCHSCREEN_USB_E2I
|
||||
default y
|
||||
bool "e2i Touchscreen controller (e.g. from Mimo 740)"
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
config TOUCHSCREEN_TOUCHIT213
|
||||
tristate "Sahara TouchIT-213 touchscreen"
|
||||
select SERIO
|
||||
@@ -492,6 +503,7 @@ config TOUCHSCREEN_TSC2007
|
||||
|
||||
config TOUCHSCREEN_W90X900
|
||||
tristate "W90P910 touchscreen driver"
|
||||
depends on HAVE_CLK
|
||||
help
|
||||
Say Y here if you have a W90P910 based touchscreen.
|
||||
|
||||
|
@@ -204,14 +204,14 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
|
||||
goto err_free_dev;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
"atmel tsadcc regs")) {
|
||||
dev_err(&pdev->dev, "resources is unavailable.\n");
|
||||
err = -EBUSY;
|
||||
goto err_free_dev;
|
||||
}
|
||||
|
||||
tsc_base = ioremap(res->start, res->end - res->start + 1);
|
||||
tsc_base = ioremap(res->start, resource_size(res));
|
||||
if (!tsc_base) {
|
||||
dev_err(&pdev->dev, "failed to map registers.\n");
|
||||
err = -ENOMEM;
|
||||
@@ -286,7 +286,7 @@ err_free_irq:
|
||||
err_unmap_regs:
|
||||
iounmap(tsc_base);
|
||||
err_release_mem:
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err_free_dev:
|
||||
input_free_device(ts_dev->input);
|
||||
err_free_mem:
|
||||
@@ -305,7 +305,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
iounmap(tsc_base);
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
clk_disable(ts_dev->clk);
|
||||
clk_put(ts_dev->clk);
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/input/eeti_ts.h>
|
||||
|
||||
static int flip_x;
|
||||
module_param(flip_x, bool, 0644);
|
||||
@@ -46,7 +47,7 @@ struct eeti_ts_priv {
|
||||
struct input_dev *input;
|
||||
struct work_struct work;
|
||||
struct mutex mutex;
|
||||
int irq;
|
||||
int irq, irq_active_high;
|
||||
};
|
||||
|
||||
#define EETI_TS_BITDEPTH (11)
|
||||
@@ -58,6 +59,11 @@ struct eeti_ts_priv {
|
||||
#define REPORT_BIT_HAS_PRESSURE (1 << 6)
|
||||
#define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH)
|
||||
|
||||
static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
|
||||
{
|
||||
return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high;
|
||||
}
|
||||
|
||||
static void eeti_ts_read(struct work_struct *work)
|
||||
{
|
||||
char buf[6];
|
||||
@@ -67,7 +73,7 @@ static void eeti_ts_read(struct work_struct *work)
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to)
|
||||
while (eeti_ts_irq_active(priv) && --to)
|
||||
i2c_master_recv(priv->client, buf, sizeof(buf));
|
||||
|
||||
if (!to) {
|
||||
@@ -140,8 +146,10 @@ static void eeti_ts_close(struct input_dev *dev)
|
||||
static int __devinit eeti_ts_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *idp)
|
||||
{
|
||||
struct eeti_ts_platform_data *pdata;
|
||||
struct eeti_ts_priv *priv;
|
||||
struct input_dev *input;
|
||||
unsigned int irq_flags;
|
||||
int err = -ENOMEM;
|
||||
|
||||
/* In contrast to what's described in the datasheet, there seems
|
||||
@@ -180,6 +188,14 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
|
||||
priv->input = input;
|
||||
priv->irq = client->irq;
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
|
||||
if (pdata)
|
||||
priv->irq_active_high = pdata->irq_active_high;
|
||||
|
||||
irq_flags = priv->irq_active_high ?
|
||||
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
|
||||
|
||||
INIT_WORK(&priv->work, eeti_ts_read);
|
||||
i2c_set_clientdata(client, priv);
|
||||
input_set_drvdata(input, priv);
|
||||
@@ -188,7 +204,7 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING,
|
||||
err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
|
||||
client->name, priv);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
|
||||
|
@@ -148,9 +148,10 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
|
||||
struct h3600_dev *ts = input_get_drvdata(dev);
|
||||
|
||||
/* Must be in this order */
|
||||
ts->serio->write(ts->serio, 1);
|
||||
ts->serio->write(ts->serio, pwr);
|
||||
ts->serio->write(ts->serio, brightness);
|
||||
serio_write(ts->serio, 1);
|
||||
serio_write(ts->serio, pwr);
|
||||
serio_write(ts->serio, brightness);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -262,7 +263,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type,
|
||||
|
||||
switch (type) {
|
||||
case EV_LED: {
|
||||
// ts->serio->write(ts->serio, SOME_CMD);
|
||||
// serio_write(ts->serio, SOME_CMD);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -31,9 +31,11 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wm97xx.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/regs-ac97.h>
|
||||
|
||||
#define VERSION "0.13"
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
struct continuous {
|
||||
u16 id; /* codec id */
|
||||
@@ -62,6 +64,7 @@ static const struct continuous cinfo[] = {
|
||||
/* continuous speed index */
|
||||
static int sp_idx;
|
||||
static u16 last, tries;
|
||||
static int irq;
|
||||
|
||||
/*
|
||||
* Pen sampling frequency (Hz) in continuous mode.
|
||||
@@ -171,7 +174,7 @@ up:
|
||||
|
||||
static int wm97xx_acc_startup(struct wm97xx *wm)
|
||||
{
|
||||
int idx = 0;
|
||||
int idx = 0, ret = 0;
|
||||
|
||||
/* check we have a codec */
|
||||
if (wm->ac97 == NULL)
|
||||
@@ -191,18 +194,40 @@ static int wm97xx_acc_startup(struct wm97xx *wm)
|
||||
"mainstone accelerated touchscreen driver, %d samples/sec\n",
|
||||
cinfo[sp_idx].speed);
|
||||
|
||||
/* IRQ driven touchscreen is used on Palm hardware */
|
||||
if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) {
|
||||
pen_int = 1;
|
||||
irq = 27;
|
||||
/* There is some obscure mutant of WM9712 interbred with WM9713
|
||||
* used on Palm HW */
|
||||
wm->variant = WM97xx_WM1613;
|
||||
} else if (machine_is_mainstone() && pen_int)
|
||||
irq = 4;
|
||||
|
||||
if (irq) {
|
||||
ret = gpio_request(irq, "Touchscreen IRQ");
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = gpio_direction_input(irq);
|
||||
if (ret) {
|
||||
gpio_free(irq);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wm->pen_irq = gpio_to_irq(irq);
|
||||
set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
|
||||
} else /* pen irq not supported */
|
||||
pen_int = 0;
|
||||
|
||||
/* codec specific irq config */
|
||||
if (pen_int) {
|
||||
switch (wm->id) {
|
||||
case WM9705_ID2:
|
||||
wm->pen_irq = IRQ_GPIO(4);
|
||||
set_irq_type(IRQ_GPIO(4), IRQ_TYPE_EDGE_BOTH);
|
||||
break;
|
||||
case WM9712_ID2:
|
||||
case WM9713_ID2:
|
||||
/* enable pen down interrupt */
|
||||
/* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
|
||||
wm->pen_irq = MAINSTONE_AC97_IRQ;
|
||||
wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
|
||||
WM97XX_GPIO_POL_HIGH,
|
||||
WM97XX_GPIO_STICKY,
|
||||
@@ -220,23 +245,17 @@ static int wm97xx_acc_startup(struct wm97xx *wm)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wm97xx_acc_shutdown(struct wm97xx *wm)
|
||||
{
|
||||
/* codec specific deconfig */
|
||||
if (pen_int) {
|
||||
switch (wm->id & 0xffff) {
|
||||
case WM9705_ID2:
|
||||
wm->pen_irq = 0;
|
||||
break;
|
||||
case WM9712_ID2:
|
||||
case WM9713_ID2:
|
||||
/* disable interrupt */
|
||||
wm->pen_irq = 0;
|
||||
break;
|
||||
}
|
||||
if (irq)
|
||||
gpio_free(irq);
|
||||
wm->pen_irq = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -21,15 +21,14 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/tsc2007.h>
|
||||
|
||||
#define TS_POLL_DELAY (10 * 1000) /* ns delay before the first sample */
|
||||
#define TS_POLL_PERIOD (5 * 1000) /* ns delay between samples */
|
||||
#define TS_POLL_DELAY 1 /* ms delay between samples */
|
||||
#define TS_POLL_PERIOD 1 /* ms delay between samples */
|
||||
|
||||
#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
|
||||
#define TSC2007_MEASURE_AUX (0x2 << 4)
|
||||
@@ -70,17 +69,14 @@ struct ts_event {
|
||||
struct tsc2007 {
|
||||
struct input_dev *input;
|
||||
char phys[32];
|
||||
struct hrtimer timer;
|
||||
struct ts_event tc;
|
||||
struct delayed_work work;
|
||||
|
||||
struct i2c_client *client;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
u16 model;
|
||||
u16 x_plate_ohms;
|
||||
|
||||
unsigned pendown;
|
||||
bool pendown;
|
||||
int irq;
|
||||
|
||||
int (*get_pendown_state)(void);
|
||||
@@ -109,52 +105,96 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void tsc2007_send_event(void *tsc)
|
||||
static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
|
||||
{
|
||||
struct tsc2007 *ts = tsc;
|
||||
u32 rt;
|
||||
u16 x, y, z1, z2;
|
||||
/* y- still on; turn on only y+ (and ADC) */
|
||||
tc->y = tsc2007_xfer(tsc, READ_Y);
|
||||
|
||||
x = ts->tc.x;
|
||||
y = ts->tc.y;
|
||||
z1 = ts->tc.z1;
|
||||
z2 = ts->tc.z2;
|
||||
/* turn y- off, x+ on, then leave in lowpower */
|
||||
tc->x = tsc2007_xfer(tsc, READ_X);
|
||||
|
||||
/* turn y+ off, x- on; we'll use formula #1 */
|
||||
tc->z1 = tsc2007_xfer(tsc, READ_Z1);
|
||||
tc->z2 = tsc2007_xfer(tsc, READ_Z2);
|
||||
|
||||
/* Prepare for next touch reading - power down ADC, enable PENIRQ */
|
||||
tsc2007_xfer(tsc, PWRDOWN);
|
||||
}
|
||||
|
||||
static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
|
||||
{
|
||||
u32 rt = 0;
|
||||
|
||||
/* range filtering */
|
||||
if (x == MAX_12BIT)
|
||||
x = 0;
|
||||
if (tc->x == MAX_12BIT)
|
||||
tc->x = 0;
|
||||
|
||||
if (likely(x && z1)) {
|
||||
if (likely(tc->x && tc->z1)) {
|
||||
/* compute touch pressure resistance using equation #1 */
|
||||
rt = z2;
|
||||
rt -= z1;
|
||||
rt *= x;
|
||||
rt *= ts->x_plate_ohms;
|
||||
rt /= z1;
|
||||
rt = tc->z2 - tc->z1;
|
||||
rt *= tc->x;
|
||||
rt *= tsc->x_plate_ohms;
|
||||
rt /= tc->z1;
|
||||
rt = (rt + 2047) >> 12;
|
||||
} else
|
||||
rt = 0;
|
||||
|
||||
/* 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
|
||||
*/
|
||||
if (rt > MAX_12BIT) {
|
||||
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
|
||||
|
||||
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
|
||||
HRTIMER_MODE_REL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE: We can't rely on the pressure to determine the pen down
|
||||
* state, even this controller has a pressure sensor. The pressure
|
||||
* value can fluctuate for quite a while after lifting the pen and
|
||||
* in some cases may not even settle at the expected value.
|
||||
return rt;
|
||||
}
|
||||
|
||||
static void tsc2007_send_up_event(struct tsc2007 *tsc)
|
||||
{
|
||||
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);
|
||||
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.
|
||||
* The pressure value can fluctuate for quite a while after
|
||||
* lifting the pen and in some cases may not even settle at the
|
||||
* expected value.
|
||||
*
|
||||
* The only safe way to check for the pen up condition is in the
|
||||
* timer by reading the pen signal state (it's a GPIO _and_ IRQ).
|
||||
* 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.
|
||||
*/
|
||||
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");
|
||||
}
|
||||
|
||||
tsc2007_read_values(ts, &tc);
|
||||
|
||||
rt = tsc2007_calculate_pressure(ts, &tc);
|
||||
if (rt > MAX_12BIT) {
|
||||
/*
|
||||
* 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);
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
if (rt) {
|
||||
struct input_dev *input = ts->input;
|
||||
|
||||
@@ -162,102 +202,74 @@ static void tsc2007_send_event(void *tsc)
|
||||
dev_dbg(&ts->client->dev, "DOWN\n");
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 1);
|
||||
ts->pendown = 1;
|
||||
ts->pendown = true;
|
||||
}
|
||||
|
||||
input_report_abs(input, ABS_X, x);
|
||||
input_report_abs(input, ABS_Y, y);
|
||||
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",
|
||||
x, y, rt);
|
||||
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;
|
||||
}
|
||||
|
||||
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
static int tsc2007_read_values(struct tsc2007 *tsc)
|
||||
{
|
||||
/* y- still on; turn on only y+ (and ADC) */
|
||||
tsc->tc.y = tsc2007_xfer(tsc, READ_Y);
|
||||
|
||||
/* turn y- off, x+ on, then leave in lowpower */
|
||||
tsc->tc.x = tsc2007_xfer(tsc, READ_X);
|
||||
|
||||
/* turn y+ off, x- on; we'll use formula #1 */
|
||||
tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1);
|
||||
tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2);
|
||||
|
||||
/* power down */
|
||||
tsc2007_xfer(tsc, PWRDOWN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle)
|
||||
{
|
||||
struct tsc2007 *ts = container_of(handle, struct tsc2007, timer);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ts->lock, flags);
|
||||
|
||||
if (unlikely(!ts->get_pendown_state() && ts->pendown)) {
|
||||
struct input_dev *input = ts->input;
|
||||
|
||||
dev_dbg(&ts->client->dev, "UP\n");
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 0);
|
||||
input_report_abs(input, ABS_PRESSURE, 0);
|
||||
input_sync(input);
|
||||
|
||||
ts->pendown = 0;
|
||||
out:
|
||||
if (ts->pendown)
|
||||
schedule_delayed_work(&ts->work,
|
||||
msecs_to_jiffies(TS_POLL_PERIOD));
|
||||
else
|
||||
enable_irq(ts->irq);
|
||||
} else {
|
||||
/* pen is still down, continue with the measurement */
|
||||
dev_dbg(&ts->client->dev, "pen is still down\n");
|
||||
|
||||
tsc2007_read_values(ts);
|
||||
tsc2007_send_event(ts);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ts->lock, flags);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static irqreturn_t tsc2007_irq(int irq, void *handle)
|
||||
{
|
||||
struct tsc2007 *ts = handle;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ts->lock, flags);
|
||||
|
||||
if (likely(ts->get_pendown_state())) {
|
||||
if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
|
||||
disable_irq_nosync(ts->irq);
|
||||
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
|
||||
HRTIMER_MODE_REL);
|
||||
schedule_delayed_work(&ts->work,
|
||||
msecs_to_jiffies(TS_POLL_DELAY));
|
||||
}
|
||||
|
||||
if (ts->clear_penirq)
|
||||
ts->clear_penirq();
|
||||
|
||||
spin_unlock_irqrestore(&ts->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tsc2007_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static void tsc2007_free_irq(struct tsc2007 *ts)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit tsc2007_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tsc2007 *ts;
|
||||
struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
|
||||
struct input_dev *input_dev;
|
||||
int err;
|
||||
|
||||
if (!pdata || !pdata->get_pendown_state) {
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "platform data is required!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -274,22 +286,15 @@ static int tsc2007_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
ts->client = client;
|
||||
i2c_set_clientdata(client, ts);
|
||||
|
||||
ts->irq = client->irq;
|
||||
ts->input = input_dev;
|
||||
|
||||
hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
ts->timer.function = tsc2007_timer;
|
||||
|
||||
spin_lock_init(&ts->lock);
|
||||
INIT_DELAYED_WORK(&ts->work, tsc2007_work);
|
||||
|
||||
ts->model = pdata->model;
|
||||
ts->x_plate_ohms = pdata->x_plate_ohms;
|
||||
ts->get_pendown_state = pdata->get_pendown_state;
|
||||
ts->clear_penirq = pdata->clear_penirq;
|
||||
|
||||
pdata->init_platform_hw();
|
||||
|
||||
snprintf(ts->phys, sizeof(ts->phys),
|
||||
"%s/input0", dev_name(&client->dev));
|
||||
|
||||
@@ -304,9 +309,8 @@ static int tsc2007_probe(struct i2c_client *client,
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
|
||||
|
||||
tsc2007_read_values(ts);
|
||||
|
||||
ts->irq = client->irq;
|
||||
if (pdata->init_platform_hw)
|
||||
pdata->init_platform_hw();
|
||||
|
||||
err = request_irq(ts->irq, tsc2007_irq, 0,
|
||||
client->dev.driver->name, ts);
|
||||
@@ -315,33 +319,39 @@ static int tsc2007_probe(struct i2c_client *client,
|
||||
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;
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err)
|
||||
goto err_free_irq;
|
||||
|
||||
dev_info(&client->dev, "registered with irq (%d)\n", ts->irq);
|
||||
i2c_set_clientdata(client, ts);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(ts->irq, ts);
|
||||
hrtimer_cancel(&ts->timer);
|
||||
tsc2007_free_irq(ts);
|
||||
if (pdata->exit_platform_hw)
|
||||
pdata->exit_platform_hw();
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(ts);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tsc2007_remove(struct i2c_client *client)
|
||||
static int __devexit tsc2007_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tsc2007 *ts = i2c_get_clientdata(client);
|
||||
struct tsc2007_platform_data *pdata;
|
||||
struct tsc2007_platform_data *pdata = client->dev.platform_data;
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
pdata->exit_platform_hw();
|
||||
tsc2007_free_irq(ts);
|
||||
|
||||
if (pdata->exit_platform_hw)
|
||||
pdata->exit_platform_hw();
|
||||
|
||||
free_irq(ts->irq, ts);
|
||||
hrtimer_cancel(&ts->timer);
|
||||
input_unregister_device(ts->input);
|
||||
kfree(ts);
|
||||
|
||||
@@ -362,7 +372,7 @@ static struct i2c_driver tsc2007_driver = {
|
||||
},
|
||||
.id_table = tsc2007_idtable,
|
||||
.probe = tsc2007_probe,
|
||||
.remove = tsc2007_remove,
|
||||
.remove = __devexit_p(tsc2007_remove),
|
||||
};
|
||||
|
||||
static int __init tsc2007_init(void)
|
||||
|
@@ -128,9 +128,10 @@ 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_down(struct snd_ac97 *ac97)
|
||||
static inline int ucb1400_ts_pen_up(struct snd_ac97 *ac97)
|
||||
{
|
||||
unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR);
|
||||
|
||||
return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
|
||||
}
|
||||
|
||||
@@ -209,7 +210,7 @@ static int ucb1400_ts_thread(void *_ucb)
|
||||
|
||||
msleep(10);
|
||||
|
||||
if (ucb1400_ts_pen_down(ucb->ac97)) {
|
||||
if (ucb1400_ts_pen_up(ucb->ac97)) {
|
||||
ucb1400_ts_irq_enable(ucb->ac97);
|
||||
|
||||
/*
|
||||
|
@@ -13,6 +13,7 @@
|
||||
* - IdealTEK URTC1000
|
||||
* - General Touch
|
||||
* - GoTop Super_Q2/GogoPen/PenPower tablets
|
||||
* - JASTEC USB touch controller/DigiTech DTR-02U
|
||||
*
|
||||
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
|
||||
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
|
||||
@@ -118,6 +119,8 @@ enum {
|
||||
DEVTYPE_IDEALTEK,
|
||||
DEVTYPE_GENERAL_TOUCH,
|
||||
DEVTYPE_GOTOP,
|
||||
DEVTYPE_JASTEC,
|
||||
DEVTYPE_E2I,
|
||||
};
|
||||
|
||||
#define USB_DEVICE_HID_CLASS(vend, prod) \
|
||||
@@ -191,10 +194,50 @@ static struct usb_device_id usbtouch_devices[] = {
|
||||
{USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
|
||||
{USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_E2I
|
||||
{USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* e2i Part
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_E2I
|
||||
static int e2i_init(struct usbtouch_usb *usbtouch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
|
||||
0x01, 0x02, 0x0000, 0x0081,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
|
||||
dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||
{
|
||||
int tmp = (pkt[0] << 8) | pkt[1];
|
||||
dev->x = (pkt[2] << 8) | pkt[3];
|
||||
dev->y = (pkt[4] << 8) | pkt[5];
|
||||
|
||||
tmp = tmp - 0xA000;
|
||||
dev->touch = (tmp > 0);
|
||||
dev->press = (tmp > 0 ? tmp : 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* eGalax part
|
||||
*/
|
||||
@@ -559,6 +602,21 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||
dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
|
||||
dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
|
||||
dev->touch = pkt[0] & 0x01;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* JASTEC Part
|
||||
*/
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
|
||||
static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||
{
|
||||
dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f);
|
||||
dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f);
|
||||
dev->touch = (pkt[0] & 0x40) >> 6;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -702,6 +760,29 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
|
||||
.read_data = gotop_read_data,
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
|
||||
[DEVTYPE_JASTEC] = {
|
||||
.min_xc = 0x0,
|
||||
.max_xc = 0x0fff,
|
||||
.min_yc = 0x0,
|
||||
.max_yc = 0x0fff,
|
||||
.rept_size = 4,
|
||||
.read_data = jastec_read_data,
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_E2I
|
||||
[DEVTYPE_E2I] = {
|
||||
.min_xc = 0x0,
|
||||
.max_xc = 0x7fff,
|
||||
.min_yc = 0x0,
|
||||
.max_yc = 0x7fff,
|
||||
.rept_size = 6,
|
||||
.init = e2i_init,
|
||||
.read_data = e2i_read_data,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
@@ -47,8 +48,8 @@ enum ts_state {
|
||||
struct w90p910_ts {
|
||||
struct input_dev *input;
|
||||
struct timer_list timer;
|
||||
struct clk *clk;
|
||||
int irq_num;
|
||||
void __iomem *clocken;
|
||||
void __iomem *ts_reg;
|
||||
spinlock_t lock;
|
||||
enum ts_state state;
|
||||
@@ -166,8 +167,7 @@ static int w90p910_open(struct input_dev *dev)
|
||||
unsigned long val;
|
||||
|
||||
/* enable the ADC clock */
|
||||
val = __raw_readl(w90p910_ts->clocken);
|
||||
__raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken);
|
||||
clk_enable(w90p910_ts->clk);
|
||||
|
||||
__raw_writel(ADC_RST1, w90p910_ts->ts_reg);
|
||||
msleep(1);
|
||||
@@ -211,8 +211,7 @@ static void w90p910_close(struct input_dev *dev)
|
||||
del_timer_sync(&w90p910_ts->timer);
|
||||
|
||||
/* stop the ADC clock */
|
||||
val = __raw_readl(w90p910_ts->clocken);
|
||||
__raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken);
|
||||
clk_disable(w90p910_ts->clk);
|
||||
}
|
||||
|
||||
static int __devinit w90x900ts_probe(struct platform_device *pdev)
|
||||
@@ -241,26 +240,24 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
pdev->name)) {
|
||||
err = -EBUSY;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1);
|
||||
w90p910_ts->ts_reg = ioremap(res->start, resource_size(res));
|
||||
if (!w90p910_ts->ts_reg) {
|
||||
err = -ENOMEM;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
err = -ENXIO;
|
||||
w90p910_ts->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(w90p910_ts->clk)) {
|
||||
err = PTR_ERR(w90p910_ts->clk);
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
w90p910_ts->clocken = (void __iomem *)res->start;
|
||||
|
||||
input_dev->name = "W90P910 TouchScreen";
|
||||
input_dev->phys = "w90p910ts/event0";
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
@@ -283,20 +280,21 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
|
||||
if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
|
||||
IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
|
||||
err = -EBUSY;
|
||||
goto fail3;
|
||||
goto fail4;
|
||||
}
|
||||
|
||||
err = input_register_device(w90p910_ts->input);
|
||||
if (err)
|
||||
goto fail4;
|
||||
goto fail5;
|
||||
|
||||
platform_set_drvdata(pdev, w90p910_ts);
|
||||
|
||||
return 0;
|
||||
|
||||
fail4: free_irq(w90p910_ts->irq_num, w90p910_ts);
|
||||
fail5: free_irq(w90p910_ts->irq_num, w90p910_ts);
|
||||
fail4: clk_put(w90p910_ts->clk);
|
||||
fail3: iounmap(w90p910_ts->ts_reg);
|
||||
fail2: release_mem_region(res->start, res->end - res->start + 1);
|
||||
fail2: release_mem_region(res->start, resource_size(res));
|
||||
fail1: input_free_device(input_dev);
|
||||
kfree(w90p910_ts);
|
||||
return err;
|
||||
@@ -311,8 +309,10 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev)
|
||||
del_timer_sync(&w90p910_ts->timer);
|
||||
iounmap(w90p910_ts->ts_reg);
|
||||
|
||||
clk_put(w90p910_ts->clk);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
input_unregister_device(w90p910_ts->input);
|
||||
kfree(w90p910_ts);
|
||||
|
@@ -25,18 +25,16 @@ MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Definitions & global arrays.
|
||||
*/
|
||||
|
||||
#define W8001_MAX_LENGTH 11
|
||||
#define W8001_PACKET_LEN 11
|
||||
#define W8001_LEAD_MASK 0x80
|
||||
#define W8001_LEAD_BYTE 0x80
|
||||
#define W8001_TAB_MASK 0x40
|
||||
#define W8001_TAB_BYTE 0x40
|
||||
#define W8001_LEAD_MASK 0x80
|
||||
#define W8001_LEAD_BYTE 0x80
|
||||
#define W8001_TAB_MASK 0x40
|
||||
#define W8001_TAB_BYTE 0x40
|
||||
|
||||
#define W8001_QUERY_PACKET 0x20
|
||||
#define W8001_QUERY_PACKET 0x20
|
||||
|
||||
#define W8001_CMD_START '1'
|
||||
#define W8001_CMD_QUERY '*'
|
||||
|
||||
struct w8001_coord {
|
||||
u8 rdy;
|
||||
@@ -57,18 +55,19 @@ struct w8001_coord {
|
||||
struct w8001 {
|
||||
struct input_dev *dev;
|
||||
struct serio *serio;
|
||||
struct mutex cmd_mutex;
|
||||
struct completion cmd_done;
|
||||
int id;
|
||||
int idx;
|
||||
unsigned char expected_packet;
|
||||
unsigned char response_type;
|
||||
unsigned char response[W8001_MAX_LENGTH];
|
||||
unsigned char data[W8001_MAX_LENGTH];
|
||||
unsigned char response[W8001_PACKET_LEN];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static int parse_data(u8 *data, struct w8001_coord *coord)
|
||||
static void parse_data(u8 *data, struct w8001_coord *coord)
|
||||
{
|
||||
memset(coord, 0, sizeof(*coord));
|
||||
|
||||
coord->rdy = data[0] & 0x20;
|
||||
coord->tsw = data[0] & 0x01;
|
||||
coord->f1 = data[0] & 0x02;
|
||||
@@ -87,15 +86,15 @@ static int parse_data(u8 *data, struct w8001_coord *coord)
|
||||
|
||||
coord->tilt_x = data[7] & 0x7F;
|
||||
coord->tilt_y = data[8] & 0x7F;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void w8001_process_data(struct w8001 *w8001, unsigned char data)
|
||||
static irqreturn_t w8001_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct w8001 *w8001 = serio_get_drvdata(serio);
|
||||
struct input_dev *dev = w8001->dev;
|
||||
u8 tmp;
|
||||
struct w8001_coord coord;
|
||||
unsigned char tmp;
|
||||
|
||||
w8001->data[w8001->idx] = data;
|
||||
switch (w8001->idx++) {
|
||||
@@ -105,12 +104,13 @@ static void w8001_process_data(struct w8001 *w8001, unsigned char data)
|
||||
w8001->idx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
tmp = w8001->data[0] & W8001_TAB_MASK;
|
||||
if (unlikely(tmp == W8001_TAB_BYTE))
|
||||
break;
|
||||
|
||||
w8001->idx = 0;
|
||||
memset(&coord, 0, sizeof(coord));
|
||||
parse_data(w8001->data, &coord);
|
||||
input_report_abs(dev, ABS_X, coord.x);
|
||||
input_report_abs(dev, ABS_Y, coord.y);
|
||||
@@ -118,86 +118,48 @@ static void w8001_process_data(struct w8001 *w8001, unsigned char data)
|
||||
input_report_key(dev, BTN_TOUCH, coord.tsw);
|
||||
input_sync(dev);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
w8001->idx = 0;
|
||||
memcpy(w8001->response, &w8001->data, W8001_PACKET_LEN);
|
||||
w8001->expected_packet = W8001_QUERY_PACKET;
|
||||
memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH);
|
||||
w8001->response_type = W8001_QUERY_PACKET;
|
||||
complete(&w8001->cmd_done);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t w8001_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct w8001 *w8001 = serio_get_drvdata(serio);
|
||||
|
||||
w8001_process_data(w8001, data);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int w8001_async_command(struct w8001 *w8001, unsigned char *packet,
|
||||
int len)
|
||||
static int w8001_command(struct w8001 *w8001, unsigned char command,
|
||||
bool wait_response)
|
||||
{
|
||||
int rc = -1;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&w8001->cmd_mutex);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (serio_write(w8001->serio, packet[i]))
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&w8001->cmd_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int w8001_command(struct w8001 *w8001, unsigned char *packet, int len)
|
||||
{
|
||||
int rc = -1;
|
||||
int i;
|
||||
|
||||
mutex_lock(&w8001->cmd_mutex);
|
||||
|
||||
serio_pause_rx(w8001->serio);
|
||||
w8001->response_type = 0;
|
||||
init_completion(&w8001->cmd_done);
|
||||
serio_continue_rx(w8001->serio);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (serio_write(w8001->serio, packet[i]))
|
||||
goto out;
|
||||
rc = serio_write(w8001->serio, command);
|
||||
if (rc == 0 && wait_response) {
|
||||
|
||||
wait_for_completion_timeout(&w8001->cmd_done, HZ);
|
||||
if (w8001->response_type != W8001_QUERY_PACKET)
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
wait_for_completion_timeout(&w8001->cmd_done, HZ);
|
||||
|
||||
if (w8001->expected_packet == W8001_QUERY_PACKET) {
|
||||
/* We are back in reporting mode, the query was ACKed */
|
||||
memcpy(packet, w8001->response, W8001_PACKET_LEN);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&w8001->cmd_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int w8001_setup(struct w8001 *w8001)
|
||||
{
|
||||
struct w8001_coord coord;
|
||||
struct input_dev *dev = w8001->dev;
|
||||
unsigned char start[1] = { '1' };
|
||||
unsigned char query[11] = { '*' };
|
||||
struct w8001_coord coord;
|
||||
int error;
|
||||
|
||||
if (w8001_command(w8001, query, 1))
|
||||
return -1;
|
||||
error = w8001_command(w8001, W8001_CMD_QUERY, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
memset(&coord, 0, sizeof(coord));
|
||||
parse_data(query, &coord);
|
||||
parse_data(w8001->response, &coord);
|
||||
|
||||
input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
|
||||
input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
|
||||
@@ -205,10 +167,7 @@ static int w8001_setup(struct w8001 *w8001)
|
||||
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
|
||||
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
|
||||
|
||||
if (w8001_async_command(w8001, start, 1))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return w8001_command(w8001, W8001_CMD_START, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -249,7 +208,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
|
||||
w8001->serio = serio;
|
||||
w8001->id = serio->id.id;
|
||||
w8001->dev = input_dev;
|
||||
mutex_init(&w8001->cmd_mutex);
|
||||
init_completion(&w8001->cmd_done);
|
||||
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
|
||||
|
||||
@@ -269,7 +227,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
|
||||
if (err)
|
||||
goto fail2;
|
||||
|
||||
if (w8001_setup(w8001))
|
||||
err = w8001_setup(w8001);
|
||||
if (err)
|
||||
goto fail3;
|
||||
|
||||
err = input_register_device(w8001->dev);
|
||||
|
@@ -204,7 +204,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
|
||||
else
|
||||
reg &= ~gpio;
|
||||
|
||||
if (wm->id == WM9712_ID2)
|
||||
if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
|
||||
wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
|
||||
else
|
||||
wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
|
||||
@@ -307,7 +307,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work)
|
||||
WM97XX_GPIO_13);
|
||||
}
|
||||
|
||||
if (wm->id == WM9712_ID2)
|
||||
if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
|
||||
wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status &
|
||||
~WM97XX_GPIO_13) << 1);
|
||||
else
|
||||
@@ -582,6 +582,8 @@ static int wm97xx_probe(struct device *dev)
|
||||
|
||||
wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
|
||||
|
||||
wm->variant = WM97xx_GENERIC;
|
||||
|
||||
dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff);
|
||||
|
||||
switch (wm->id & 0xff) {
|
||||
|
Reference in New Issue
Block a user