Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: eeti_ts - switch to using threaded interrupt

Instead of having standard interrupt handler and manually firing work item
to perform I2C reads, let's switch to threaded interrupts, which were
designed specifically for this purpose.

Reviewed-by: Daniel Mack <daniel@zonque.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

+36 -43
+36 -43
drivers/input/touchscreen/eeti_ts.c
··· 47 47 struct eeti_ts { 48 48 struct i2c_client *client; 49 49 struct input_dev *input; 50 - struct work_struct work; 51 - struct mutex mutex; 52 50 int irq_gpio, irq_active_high; 51 + bool running; 53 52 }; 54 53 55 54 #define EETI_TS_BITDEPTH (11) ··· 65 66 return gpio_get_value_cansleep(eeti->irq_gpio) == eeti->irq_active_high; 66 67 } 67 68 68 - static void eeti_ts_read(struct work_struct *work) 69 + static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) 69 70 { 70 - char buf[6]; 71 - unsigned int x, y, res, pressed, to = 100; 72 - struct eeti_ts *eeti = 73 - container_of(work, struct eeti_ts, work); 71 + unsigned int res; 72 + u16 x, y; 74 73 75 - mutex_lock(&eeti->mutex); 76 - 77 - while (eeti_ts_irq_active(eeti) && --to) 78 - i2c_master_recv(eeti->client, buf, sizeof(buf)); 79 - 80 - if (!to) { 81 - dev_err(&eeti->client->dev, 82 - "unable to clear IRQ - line stuck?\n"); 83 - goto out; 84 - } 85 - 86 - /* drop non-report packets */ 87 - if (!(buf[0] & 0x80)) 88 - goto out; 89 - 90 - pressed = buf[0] & REPORT_BIT_PRESSED; 91 74 res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); 92 75 93 76 x = get_unaligned_be16(&buf[1]); ··· 90 109 91 110 input_report_abs(eeti->input, ABS_X, x); 92 111 input_report_abs(eeti->input, ABS_Y, y); 93 - input_report_key(eeti->input, BTN_TOUCH, !!pressed); 112 + input_report_key(eeti->input, BTN_TOUCH, buf[0] & REPORT_BIT_PRESSED); 94 113 input_sync(eeti->input); 95 - 96 - out: 97 - mutex_unlock(&eeti->mutex); 98 114 } 99 115 100 116 static irqreturn_t eeti_ts_isr(int irq, void *dev_id) 101 117 { 102 118 struct eeti_ts *eeti = dev_id; 119 + int len; 120 + int error; 121 + char buf[6]; 103 122 104 - /* postpone I2C transactions as we are atomic */ 105 - schedule_work(&eeti->work); 123 + do { 124 + len = i2c_master_recv(eeti->client, buf, sizeof(buf)); 125 + if (len != sizeof(buf)) { 126 + error = len < 0 ? len : -EIO; 127 + dev_err(&eeti->client->dev, 128 + "failed to read touchscreen data: %d\n", 129 + error); 130 + break; 131 + } 132 + 133 + if (buf[0] & 0x80) { 134 + /* Motion packet */ 135 + eeti_ts_report_event(eeti, buf); 136 + } 137 + } while (eeti->running && eeti_ts_irq_active(eeti)); 106 138 107 139 return IRQ_HANDLED; 108 140 } 109 141 110 142 static void eeti_ts_start(struct eeti_ts *eeti) 111 143 { 144 + eeti->running = true; 145 + wmb(); 112 146 enable_irq(eeti->client->irq); 113 - 114 - /* Read the events once to arm the IRQ */ 115 - eeti_ts_read(&eeti->work); 116 147 } 117 148 118 149 static void eeti_ts_stop(struct eeti_ts *eeti) 119 150 { 151 + eeti->running = false; 152 + wmb(); 120 153 disable_irq(eeti->client->irq); 121 - cancel_work_sync(&eeti->work); 122 154 } 123 155 124 156 static int eeti_ts_open(struct input_dev *dev) ··· 173 179 return -ENOMEM; 174 180 } 175 181 176 - mutex_init(&eeti->mutex); 177 - 178 182 input = devm_input_allocate_device(dev); 179 183 if (!input) { 180 184 dev_err(dev, "Failed to allocate input device.\n"); ··· 202 210 eeti->irq_active_high = pdata->irq_active_high; 203 211 204 212 irq_flags = eeti->irq_active_high ? 205 - IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; 213 + IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW; 206 214 207 - INIT_WORK(&eeti->work, eeti_ts_read); 208 215 i2c_set_clientdata(client, eeti); 209 216 input_set_drvdata(input, eeti); 210 217 211 - error = input_register_device(input); 212 - if (error) 213 - return error; 214 - 215 - error = devm_request_irq(dev, client->irq, eeti_ts_isr, irq_flags, 216 - client->name, eeti); 218 + error = devm_request_threaded_irq(dev, client->irq, 219 + NULL, eeti_ts_isr, 220 + irq_flags | IRQF_ONESHOT, 221 + client->name, eeti); 217 222 if (error) { 218 223 dev_err(dev, "Unable to request touchscreen IRQ: %d\n", 219 224 error); ··· 222 233 * input device is opened. 223 234 */ 224 235 eeti_ts_stop(eeti); 236 + 237 + error = input_register_device(input); 238 + if (error) 239 + return error; 225 240 226 241 return 0; 227 242 }