Skip to content

Commit 6d94d40

Browse files
Samu Onkalotorvalds
authored andcommitted
lis3: interrupt handlers for 8bit wakeup and click events
Content for the 8bit device threaded interrupt handlers. Depending on the interrupt line and chip configuration, either click or wakeup / freefall handler is called. In case of click, BTN_ event is sent via input device. In case of wakeup or freefall, input device ABS_ events are updated immediatelly. It is still possible to configure interrupt line 1 for fast freefall detection and use the second line either for click or threshold based interrupts. Or both lines can be used for click / threshold interrupts. Polled input device can be set to stopped state and still get coordinate updates via input device using interrupt based method. Polled mode and interrupt mode can also be used parallel. BTN_ events are remapped based on existing axis remapping information. Signed-off-by: Samu Onkalo <samu.p.onkalo@nokia.com> Acked-by: Eric Piel <eric.piel@tremplin-utc.net> Cc: Daniel Mack <daniel@caiaq.de> Cc: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 92ba4fe commit 6d94d40

File tree

3 files changed

+88
-13
lines changed

3 files changed

+88
-13
lines changed

drivers/hwmon/lis3lv02d.c

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,9 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
121121
int position[3];
122122
int i;
123123

124-
mutex_lock(&lis3->mutex);
125124
position[0] = lis3->read_data(lis3, OUTX);
126125
position[1] = lis3->read_data(lis3, OUTY);
127126
position[2] = lis3->read_data(lis3, OUTZ);
128-
mutex_unlock(&lis3->mutex);
129127

130128
for (i = 0; i < 3; i++)
131129
position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
@@ -249,6 +247,19 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
249247
EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
250248

251249

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+
252263
static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
253264
{
254265
if (!test_bit(0, &lis3_dev.misc_opened))
@@ -270,13 +281,71 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
270281
return IRQ_HANDLED;
271282
}
272283

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+
273326
static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
274327
{
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+
275336
return IRQ_HANDLED;
276337
}
277338

278339
static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
279340
{
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+
280349
return IRQ_HANDLED;
281350
}
282351

@@ -374,22 +443,12 @@ static struct miscdevice lis3lv02d_misc_device = {
374443
.fops = &lis3lv02d_misc_fops,
375444
};
376445

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-
388446
int lis3lv02d_joystick_enable(void)
389447
{
390448
struct input_dev *input_dev;
391449
int err;
392450
int max_val, fuzz, flat;
451+
int btns[] = {BTN_X, BTN_Y, BTN_Z};
393452

394453
if (lis3_dev.idev)
395454
return -EINVAL;
@@ -416,6 +475,10 @@ int lis3lv02d_joystick_enable(void)
416475
input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
417476
input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
418477

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+
419482
err = input_register_polled_device(lis3_dev.idev);
420483
if (err) {
421484
input_free_polled_device(lis3_dev.idev);
@@ -461,7 +524,9 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
461524
{
462525
int x, y, z;
463526

527+
mutex_lock(&lis3_dev.mutex);
464528
lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
529+
mutex_unlock(&lis3_dev.mutex);
465530
return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
466531
}
467532

@@ -535,6 +600,13 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
535600
dev->write(dev, CLICK_THSY_X,
536601
(p->click_thresh_x & 0xf) |
537602
(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+
}
538610
}
539611

540612
if (p->wakeup_flags) {

drivers/hwmon/lis3lv02d.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ struct lis3lv02d {
233233
struct platform_device *pdev; /* platform device */
234234
atomic_t count; /* interrupt count after last read */
235235
struct axis_conversion ac; /* hw -> logical axis */
236+
int mapped_btns[3];
236237

237238
u32 irq; /* IRQ number */
238239
struct fasync_struct *async_queue; /* queue for the misc device */

include/linux/lis3lv02d.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ struct lis3lv02d_platform_data {
2525
#define LIS3_IRQ1_FF_WU_12 (3 << 0)
2626
#define LIS3_IRQ1_DATA_READY (4 << 0)
2727
#define LIS3_IRQ1_CLICK (7 << 0)
28+
#define LIS3_IRQ1_MASK (7 << 0)
2829
#define LIS3_IRQ2_DISABLE (0 << 3)
2930
#define LIS3_IRQ2_FF_WU_1 (1 << 3)
3031
#define LIS3_IRQ2_FF_WU_2 (2 << 3)
3132
#define LIS3_IRQ2_FF_WU_12 (3 << 3)
3233
#define LIS3_IRQ2_DATA_READY (4 << 3)
3334
#define LIS3_IRQ2_CLICK (7 << 3)
35+
#define LIS3_IRQ2_MASK (7 << 3)
3436
#define LIS3_IRQ_OPEN_DRAIN (1 << 6)
3537
#define LIS3_IRQ_ACTIVE_LOW (1 << 7)
3638
unsigned char irq_cfg;

0 commit comments

Comments
 (0)