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:
Linus Torvalds
2009-09-14 17:56:51 -07:00
77 changed files with 4352 additions and 1577 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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");

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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);
/*

View File

@@ -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
};

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {