Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 269459
b: refs/heads/master
c: 377dc55
h: refs/heads/master
i:
  269457: 78ff515
  269455: 8fcfb6f
v: v3
  • Loading branch information
Dmitry Torokhov committed Aug 27, 2011
1 parent 41419da commit fc1343c
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 85 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6a20baa9a40116715ebc99afe5b79b92f637ec23
refs/heads/master: 377dc5538c43052d2ee9bc89577cb07fe18f2520
150 changes: 66 additions & 84 deletions trunk/drivers/input/touchscreen/tsc2007.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ struct ts_event {
struct tsc2007 {
struct input_dev *input;
char phys[32];
struct delayed_work work;

struct i2c_client *client;

Expand All @@ -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);
};
Expand Down Expand Up @@ -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)
{
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)
static bool tsc2007_is_pen_down(struct tsc2007 *ts)
{
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.
Expand All @@ -170,79 +154,82 @@ 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);
return ts->get_pendown_state();
}

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

}
while (!ts->stopped && tsc2007_is_pen_down(ts)) {

/* pen is down, continue with the measurement */
tsc2007_read_values(ts, &tc);

if (rt) {
struct input_dev *input = ts->input;
rt = tsc2007_calculate_pressure(ts, &tc);

if (!ts->pendown) {
dev_dbg(&ts->client->dev, "DOWN\n");
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);
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);

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

input_report_abs(input, ABS_X, tc.x);
input_report_abs(input, ABS_Y, tc.y);
input_report_abs(input, ABS_PRESSURE, rt);
wait_event_timeout(ts->wait, ts->stopped,
msecs_to_jiffies(ts->poll_period));
}

input_sync(input);
dev_dbg(&ts->client->dev, "UP\n");

dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
tc.x, tc.y, rt);
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);

} 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;
}
if (ts->clear_penirq)
ts->clear_penirq();

out:
if (ts->pendown || debounced)
schedule_delayed_work(&ts->work,
msecs_to_jiffies(ts->poll_period));
else
enable_irq(ts->irq);
return IRQ_HANDLED;
}

static irqreturn_t tsc2007_irq(int irq, void *handle)
static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
{
struct tsc2007 *ts = handle;

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));
}
if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
return IRQ_WAKE_THREAD;

if (ts->clear_penirq)
ts->clear_penirq();
Expand All @@ -252,15 +239,10 @@ static irqreturn_t tsc2007_irq(int irq, void *handle)

static void tsc2007_free_irq(struct tsc2007 *ts)
{
ts->stopped = true;
mb();
wake_up(&ts->wait);
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,
Expand Down Expand Up @@ -290,7 +272,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;
Expand Down Expand Up @@ -318,8 +300,8 @@ 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;
Expand Down

0 comments on commit fc1343c

Please sign in to comment.