diff options
-rw-r--r-- | drivers/hwmon/lis3lv02d.c | 98 | ||||
-rw-r--r-- | drivers/hwmon/lis3lv02d.h | 1 | ||||
-rw-r--r-- | include/linux/lis3lv02d.h | 2 |
3 files changed, 88 insertions, 13 deletions
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index 3c06350bae3a..56a1d34d3670 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c | |||
@@ -121,11 +121,9 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) | |||
121 | int position[3]; | 121 | int position[3]; |
122 | int i; | 122 | int i; |
123 | 123 | ||
124 | mutex_lock(&lis3->mutex); | ||
125 | position[0] = lis3->read_data(lis3, OUTX); | 124 | position[0] = lis3->read_data(lis3, OUTX); |
126 | position[1] = lis3->read_data(lis3, OUTY); | 125 | position[1] = lis3->read_data(lis3, OUTY); |
127 | position[2] = lis3->read_data(lis3, OUTZ); | 126 | position[2] = lis3->read_data(lis3, OUTZ); |
128 | mutex_unlock(&lis3->mutex); | ||
129 | 127 | ||
130 | for (i = 0; i < 3; i++) | 128 | for (i = 0; i < 3; i++) |
131 | position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; | 129 | position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; |
@@ -249,6 +247,19 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3) | |||
249 | EXPORT_SYMBOL_GPL(lis3lv02d_poweron); | 247 | EXPORT_SYMBOL_GPL(lis3lv02d_poweron); |
250 | 248 | ||
251 | 249 | ||
250 | static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) | ||
251 | { | ||
252 | int x, y, z; | ||
253 | |||
254 | mutex_lock(&lis3_dev.mutex); | ||
255 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); | ||
256 | input_report_abs(pidev->input, ABS_X, x); | ||
257 | input_report_abs(pidev->input, ABS_Y, y); | ||
258 | input_report_abs(pidev->input, ABS_Z, z); | ||
259 | input_sync(pidev->input); | ||
260 | mutex_unlock(&lis3_dev.mutex); | ||
261 | } | ||
262 | |||
252 | static irqreturn_t lis302dl_interrupt(int irq, void *dummy) | 263 | static irqreturn_t lis302dl_interrupt(int irq, void *dummy) |
253 | { | 264 | { |
254 | if (!test_bit(0, &lis3_dev.misc_opened)) | 265 | if (!test_bit(0, &lis3_dev.misc_opened)) |
@@ -270,13 +281,71 @@ out: | |||
270 | return IRQ_HANDLED; | 281 | return IRQ_HANDLED; |
271 | } | 282 | } |
272 | 283 | ||
284 | static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3) | ||
285 | { | ||
286 | struct input_dev *dev = lis3->idev->input; | ||
287 | u8 click_src; | ||
288 | |||
289 | mutex_lock(&lis3->mutex); | ||
290 | lis3->read(lis3, CLICK_SRC, &click_src); | ||
291 | |||
292 | if (click_src & CLICK_SINGLE_X) { | ||
293 | input_report_key(dev, lis3->mapped_btns[0], 1); | ||
294 | input_report_key(dev, lis3->mapped_btns[0], 0); | ||
295 | } | ||
296 | |||
297 | if (click_src & CLICK_SINGLE_Y) { | ||
298 | input_report_key(dev, lis3->mapped_btns[1], 1); | ||
299 | input_report_key(dev, lis3->mapped_btns[1], 0); | ||
300 | } | ||
301 | |||
302 | if (click_src & CLICK_SINGLE_Z) { | ||
303 | input_report_key(dev, lis3->mapped_btns[2], 1); | ||
304 | input_report_key(dev, lis3->mapped_btns[2], 0); | ||
305 | } | ||
306 | input_sync(dev); | ||
307 | mutex_unlock(&lis3->mutex); | ||
308 | } | ||
309 | |||
310 | static void lis302dl_interrupt_handle_ff_wu(struct lis3lv02d *lis3) | ||
311 | { | ||
312 | u8 wu1_src; | ||
313 | u8 wu2_src; | ||
314 | |||
315 | lis3->read(lis3, FF_WU_SRC_1, &wu1_src); | ||
316 | lis3->read(lis3, FF_WU_SRC_2, &wu2_src); | ||
317 | |||
318 | wu1_src = wu1_src & FF_WU_SRC_IA ? wu1_src : 0; | ||
319 | wu2_src = wu2_src & FF_WU_SRC_IA ? wu2_src : 0; | ||
320 | |||
321 | /* joystick poll is internally protected by the lis3->mutex. */ | ||
322 | if (wu1_src || wu2_src) | ||
323 | lis3lv02d_joystick_poll(lis3_dev.idev); | ||
324 | } | ||
325 | |||
273 | static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) | 326 | static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) |
274 | { | 327 | { |
328 | |||
329 | struct lis3lv02d *lis3 = data; | ||
330 | |||
331 | if ((lis3->pdata->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK) | ||
332 | lis302dl_interrupt_handle_click(lis3); | ||
333 | else | ||
334 | lis302dl_interrupt_handle_ff_wu(lis3); | ||
335 | |||
275 | return IRQ_HANDLED; | 336 | return IRQ_HANDLED; |
276 | } | 337 | } |
277 | 338 | ||
278 | static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) | 339 | static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) |
279 | { | 340 | { |
341 | |||
342 | struct lis3lv02d *lis3 = data; | ||
343 | |||
344 | if ((lis3->pdata->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK) | ||
345 | lis302dl_interrupt_handle_click(lis3); | ||
346 | else | ||
347 | lis302dl_interrupt_handle_ff_wu(lis3); | ||
348 | |||
280 | return IRQ_HANDLED; | 349 | return IRQ_HANDLED; |
281 | } | 350 | } |
282 | 351 | ||
@@ -374,22 +443,12 @@ static struct miscdevice lis3lv02d_misc_device = { | |||
374 | .fops = &lis3lv02d_misc_fops, | 443 | .fops = &lis3lv02d_misc_fops, |
375 | }; | 444 | }; |
376 | 445 | ||
377 | static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) | ||
378 | { | ||
379 | int x, y, z; | ||
380 | |||
381 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); | ||
382 | input_report_abs(pidev->input, ABS_X, x); | ||
383 | input_report_abs(pidev->input, ABS_Y, y); | ||
384 | input_report_abs(pidev->input, ABS_Z, z); | ||
385 | input_sync(pidev->input); | ||
386 | } | ||
387 | |||
388 | int lis3lv02d_joystick_enable(void) | 446 | int lis3lv02d_joystick_enable(void) |
389 | { | 447 | { |
390 | struct input_dev *input_dev; | 448 | struct input_dev *input_dev; |
391 | int err; | 449 | int err; |
392 | int max_val, fuzz, flat; | 450 | int max_val, fuzz, flat; |
451 | int btns[] = {BTN_X, BTN_Y, BTN_Z}; | ||
393 | 452 | ||
394 | if (lis3_dev.idev) | 453 | if (lis3_dev.idev) |
395 | return -EINVAL; | 454 | return -EINVAL; |
@@ -416,6 +475,10 @@ int lis3lv02d_joystick_enable(void) | |||
416 | input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); | 475 | input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); |
417 | input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); | 476 | input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); |
418 | 477 | ||
478 | lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns); | ||
479 | lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns); | ||
480 | lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns); | ||
481 | |||
419 | err = input_register_polled_device(lis3_dev.idev); | 482 | err = input_register_polled_device(lis3_dev.idev); |
420 | if (err) { | 483 | if (err) { |
421 | input_free_polled_device(lis3_dev.idev); | 484 | input_free_polled_device(lis3_dev.idev); |
@@ -461,7 +524,9 @@ static ssize_t lis3lv02d_position_show(struct device *dev, | |||
461 | { | 524 | { |
462 | int x, y, z; | 525 | int x, y, z; |
463 | 526 | ||
527 | mutex_lock(&lis3_dev.mutex); | ||
464 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); | 528 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); |
529 | mutex_unlock(&lis3_dev.mutex); | ||
465 | return sprintf(buf, "(%d,%d,%d)\n", x, y, z); | 530 | return sprintf(buf, "(%d,%d,%d)\n", x, y, z); |
466 | } | 531 | } |
467 | 532 | ||
@@ -535,6 +600,13 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev, | |||
535 | dev->write(dev, CLICK_THSY_X, | 600 | dev->write(dev, CLICK_THSY_X, |
536 | (p->click_thresh_x & 0xf) | | 601 | (p->click_thresh_x & 0xf) | |
537 | (p->click_thresh_y << 4)); | 602 | (p->click_thresh_y << 4)); |
603 | |||
604 | if (dev->idev) { | ||
605 | struct input_dev *input_dev = lis3_dev.idev->input; | ||
606 | input_set_capability(input_dev, EV_KEY, BTN_X); | ||
607 | input_set_capability(input_dev, EV_KEY, BTN_Y); | ||
608 | input_set_capability(input_dev, EV_KEY, BTN_Z); | ||
609 | } | ||
538 | } | 610 | } |
539 | 611 | ||
540 | if (p->wakeup_flags) { | 612 | if (p->wakeup_flags) { |
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h index 692e2442ce08..854091380e33 100644 --- a/drivers/hwmon/lis3lv02d.h +++ b/drivers/hwmon/lis3lv02d.h | |||
@@ -233,6 +233,7 @@ struct lis3lv02d { | |||
233 | struct platform_device *pdev; /* platform device */ | 233 | struct platform_device *pdev; /* platform device */ |
234 | atomic_t count; /* interrupt count after last read */ | 234 | atomic_t count; /* interrupt count after last read */ |
235 | struct axis_conversion ac; /* hw -> logical axis */ | 235 | struct axis_conversion ac; /* hw -> logical axis */ |
236 | int mapped_btns[3]; | ||
236 | 237 | ||
237 | u32 irq; /* IRQ number */ | 238 | u32 irq; /* IRQ number */ |
238 | struct fasync_struct *async_queue; /* queue for the misc device */ | 239 | struct fasync_struct *async_queue; /* queue for the misc device */ |
diff --git a/include/linux/lis3lv02d.h b/include/linux/lis3lv02d.h index fd289b1e1ec1..0e8a346424bb 100644 --- a/include/linux/lis3lv02d.h +++ b/include/linux/lis3lv02d.h | |||
@@ -25,12 +25,14 @@ struct lis3lv02d_platform_data { | |||
25 | #define LIS3_IRQ1_FF_WU_12 (3 << 0) | 25 | #define LIS3_IRQ1_FF_WU_12 (3 << 0) |
26 | #define LIS3_IRQ1_DATA_READY (4 << 0) | 26 | #define LIS3_IRQ1_DATA_READY (4 << 0) |
27 | #define LIS3_IRQ1_CLICK (7 << 0) | 27 | #define LIS3_IRQ1_CLICK (7 << 0) |
28 | #define LIS3_IRQ1_MASK (7 << 0) | ||
28 | #define LIS3_IRQ2_DISABLE (0 << 3) | 29 | #define LIS3_IRQ2_DISABLE (0 << 3) |
29 | #define LIS3_IRQ2_FF_WU_1 (1 << 3) | 30 | #define LIS3_IRQ2_FF_WU_1 (1 << 3) |
30 | #define LIS3_IRQ2_FF_WU_2 (2 << 3) | 31 | #define LIS3_IRQ2_FF_WU_2 (2 << 3) |
31 | #define LIS3_IRQ2_FF_WU_12 (3 << 3) | 32 | #define LIS3_IRQ2_FF_WU_12 (3 << 3) |
32 | #define LIS3_IRQ2_DATA_READY (4 << 3) | 33 | #define LIS3_IRQ2_DATA_READY (4 << 3) |
33 | #define LIS3_IRQ2_CLICK (7 << 3) | 34 | #define LIS3_IRQ2_CLICK (7 << 3) |
35 | #define LIS3_IRQ2_MASK (7 << 3) | ||
34 | #define LIS3_IRQ_OPEN_DRAIN (1 << 6) | 36 | #define LIS3_IRQ_OPEN_DRAIN (1 << 6) |
35 | #define LIS3_IRQ_ACTIVE_LOW (1 << 7) | 37 | #define LIS3_IRQ_ACTIVE_LOW (1 << 7) |
36 | unsigned char irq_cfg; | 38 | unsigned char irq_cfg; |