diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-12-01 02:44:30 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-12-12 03:02:20 -0500 |
commit | 468792eb1e9fb2de855a1978c1228c55d9ed2753 (patch) | |
tree | 9bbf3cddf1af352f9e9b9be75984cdc1e70a3e79 /drivers | |
parent | e23ed600baf1df4819d5ba44240a3b7d555e6de2 (diff) |
Input: migor-ts - convert to a threaded IRQ
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/touchscreen/migor_ts.c | 65 |
1 files changed, 24 insertions, 41 deletions
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index 5803bd0c1cca..af746b793378 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c | |||
@@ -36,7 +36,6 @@ | |||
36 | struct migor_ts_priv { | 36 | struct migor_ts_priv { |
37 | struct i2c_client *client; | 37 | struct i2c_client *client; |
38 | struct input_dev *input; | 38 | struct input_dev *input; |
39 | struct delayed_work work; | ||
40 | int irq; | 39 | int irq; |
41 | }; | 40 | }; |
42 | 41 | ||
@@ -44,15 +43,24 @@ static const u_int8_t migor_ts_ena_seq[17] = { 0x33, 0x22, 0x11, | |||
44 | 0x01, 0x06, 0x07, }; | 43 | 0x01, 0x06, 0x07, }; |
45 | static const u_int8_t migor_ts_dis_seq[17] = { }; | 44 | static const u_int8_t migor_ts_dis_seq[17] = { }; |
46 | 45 | ||
47 | static void migor_ts_poscheck(struct work_struct *work) | 46 | static irqreturn_t migor_ts_isr(int irq, void *dev_id) |
48 | { | 47 | { |
49 | struct migor_ts_priv *priv = container_of(work, | 48 | struct migor_ts_priv *priv = dev_id; |
50 | struct migor_ts_priv, | ||
51 | work.work); | ||
52 | unsigned short xpos, ypos; | 49 | unsigned short xpos, ypos; |
53 | unsigned char event; | 50 | unsigned char event; |
54 | u_int8_t buf[16]; | 51 | u_int8_t buf[16]; |
55 | 52 | ||
53 | /* | ||
54 | * The touch screen controller chip is hooked up to the CPU | ||
55 | * using I2C and a single interrupt line. The interrupt line | ||
56 | * is pulled low whenever someone taps the screen. To deassert | ||
57 | * the interrupt line we need to acknowledge the interrupt by | ||
58 | * communicating with the controller over the slow i2c bus. | ||
59 | * | ||
60 | * Since I2C bus controller may sleep we are using threaded | ||
61 | * IRQ here. | ||
62 | */ | ||
63 | |||
56 | memset(buf, 0, sizeof(buf)); | 64 | memset(buf, 0, sizeof(buf)); |
57 | 65 | ||
58 | /* Set Index 0 */ | 66 | /* Set Index 0 */ |
@@ -72,41 +80,25 @@ static void migor_ts_poscheck(struct work_struct *work) | |||
72 | xpos = ((buf[11] & 0x03) << 8 | buf[10]); | 80 | xpos = ((buf[11] & 0x03) << 8 | buf[10]); |
73 | event = buf[12]; | 81 | event = buf[12]; |
74 | 82 | ||
75 | if (event == EVENT_PENDOWN || event == EVENT_REPEAT) { | 83 | switch (event) { |
84 | case EVENT_PENDOWN: | ||
85 | case EVENT_REPEAT: | ||
76 | input_report_key(priv->input, BTN_TOUCH, 1); | 86 | input_report_key(priv->input, BTN_TOUCH, 1); |
77 | input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/ | 87 | input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/ |
78 | input_report_abs(priv->input, ABS_Y, xpos); | 88 | input_report_abs(priv->input, ABS_Y, xpos); |
79 | input_sync(priv->input); | 89 | input_sync(priv->input); |
80 | } else if (event == EVENT_PENUP) { | 90 | break; |
91 | |||
92 | case EVENT_PENUP: | ||
81 | input_report_key(priv->input, BTN_TOUCH, 0); | 93 | input_report_key(priv->input, BTN_TOUCH, 0); |
82 | input_sync(priv->input); | 94 | input_sync(priv->input); |
95 | break; | ||
83 | } | 96 | } |
84 | out: | ||
85 | enable_irq(priv->irq); | ||
86 | } | ||
87 | |||
88 | static irqreturn_t migor_ts_isr(int irq, void *dev_id) | ||
89 | { | ||
90 | struct migor_ts_priv *priv = dev_id; | ||
91 | |||
92 | /* the touch screen controller chip is hooked up to the cpu | ||
93 | * using i2c and a single interrupt line. the interrupt line | ||
94 | * is pulled low whenever someone taps the screen. to deassert | ||
95 | * the interrupt line we need to acknowledge the interrupt by | ||
96 | * communicating with the controller over the slow i2c bus. | ||
97 | * | ||
98 | * we can't acknowledge from interrupt context since the i2c | ||
99 | * bus controller may sleep, so we just disable the interrupt | ||
100 | * here and handle the acknowledge using delayed work. | ||
101 | */ | ||
102 | |||
103 | disable_irq_nosync(irq); | ||
104 | schedule_delayed_work(&priv->work, HZ / 20); | ||
105 | 97 | ||
98 | out: | ||
106 | return IRQ_HANDLED; | 99 | return IRQ_HANDLED; |
107 | } | 100 | } |
108 | 101 | ||
109 | |||
110 | static int migor_ts_open(struct input_dev *dev) | 102 | static int migor_ts_open(struct input_dev *dev) |
111 | { | 103 | { |
112 | struct migor_ts_priv *priv = input_get_drvdata(dev); | 104 | struct migor_ts_priv *priv = input_get_drvdata(dev); |
@@ -131,15 +123,6 @@ static void migor_ts_close(struct input_dev *dev) | |||
131 | 123 | ||
132 | disable_irq(priv->irq); | 124 | disable_irq(priv->irq); |
133 | 125 | ||
134 | /* cancel pending work and wait for migor_ts_poscheck() to finish */ | ||
135 | if (cancel_delayed_work_sync(&priv->work)) { | ||
136 | /* | ||
137 | * if migor_ts_poscheck was canceled we need to enable IRQ | ||
138 | * here to balance disable done in migor_ts_isr. | ||
139 | */ | ||
140 | enable_irq(priv->irq); | ||
141 | } | ||
142 | |||
143 | /* disable controller */ | 126 | /* disable controller */ |
144 | i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq)); | 127 | i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq)); |
145 | 128 | ||
@@ -186,15 +169,15 @@ static int migor_ts_probe(struct i2c_client *client, | |||
186 | 169 | ||
187 | priv->client = client; | 170 | priv->client = client; |
188 | priv->input = input; | 171 | priv->input = input; |
189 | INIT_DELAYED_WORK(&priv->work, migor_ts_poscheck); | ||
190 | priv->irq = client->irq; | 172 | priv->irq = client->irq; |
191 | 173 | ||
192 | error = input_register_device(input); | 174 | error = input_register_device(input); |
193 | if (error) | 175 | if (error) |
194 | goto err1; | 176 | goto err1; |
195 | 177 | ||
196 | error = request_irq(priv->irq, migor_ts_isr, IRQF_TRIGGER_LOW, | 178 | error = request_threaded_irq(priv->irq, NULL, migor_ts_isr, |
197 | client->name, priv); | 179 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
180 | client->name, priv); | ||
198 | if (error) { | 181 | if (error) { |
199 | dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); | 182 | dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); |
200 | goto err2; | 183 | goto err2; |