diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/ab3100-core.c | 43 |
1 files changed, 13 insertions, 30 deletions
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index fd42a80e7bf9..aa3824a1b4f2 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c | |||
@@ -365,10 +365,13 @@ int ab3100_event_registers_startup_state_get(struct ab3100 *ab3100, | |||
365 | } | 365 | } |
366 | EXPORT_SYMBOL(ab3100_event_registers_startup_state_get); | 366 | EXPORT_SYMBOL(ab3100_event_registers_startup_state_get); |
367 | 367 | ||
368 | /* Interrupt handling worker */ | 368 | /* |
369 | static void ab3100_work(struct work_struct *work) | 369 | * This is a threaded interrupt handler so we can make some |
370 | * I2C calls etc. | ||
371 | */ | ||
372 | static irqreturn_t ab3100_irq_handler(int irq, void *data) | ||
370 | { | 373 | { |
371 | struct ab3100 *ab3100 = container_of(work, struct ab3100, work); | 374 | struct ab3100 *ab3100 = data; |
372 | u8 event_regs[3]; | 375 | u8 event_regs[3]; |
373 | u32 fatevent; | 376 | u32 fatevent; |
374 | int err; | 377 | int err; |
@@ -376,7 +379,7 @@ static void ab3100_work(struct work_struct *work) | |||
376 | err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, | 379 | err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, |
377 | event_regs, 3); | 380 | event_regs, 3); |
378 | if (err) | 381 | if (err) |
379 | goto err_event_wq; | 382 | goto err_event; |
380 | 383 | ||
381 | fatevent = (event_regs[0] << 16) | | 384 | fatevent = (event_regs[0] << 16) | |
382 | (event_regs[1] << 8) | | 385 | (event_regs[1] << 8) | |
@@ -398,29 +401,11 @@ static void ab3100_work(struct work_struct *work) | |||
398 | dev_dbg(ab3100->dev, | 401 | dev_dbg(ab3100->dev, |
399 | "IRQ Event: 0x%08x\n", fatevent); | 402 | "IRQ Event: 0x%08x\n", fatevent); |
400 | 403 | ||
401 | /* By now the IRQ should be acked and deasserted so enable it again */ | 404 | return IRQ_HANDLED; |
402 | enable_irq(ab3100->i2c_client->irq); | ||
403 | return; | ||
404 | 405 | ||
405 | err_event_wq: | 406 | err_event: |
406 | dev_dbg(ab3100->dev, | 407 | dev_dbg(ab3100->dev, |
407 | "error in event workqueue\n"); | 408 | "error reading event status\n"); |
408 | /* Enable the IRQ anyway, what choice do we have? */ | ||
409 | enable_irq(ab3100->i2c_client->irq); | ||
410 | return; | ||
411 | } | ||
412 | |||
413 | static irqreturn_t ab3100_irq_handler(int irq, void *data) | ||
414 | { | ||
415 | struct ab3100 *ab3100 = data; | ||
416 | /* | ||
417 | * Disable the IRQ and dispatch a worker to handle the | ||
418 | * event. Since the chip resides on I2C this is slow | ||
419 | * stuff and we will re-enable the interrupts once th | ||
420 | * worker has finished. | ||
421 | */ | ||
422 | disable_irq_nosync(irq); | ||
423 | schedule_work(&ab3100->work); | ||
424 | return IRQ_HANDLED; | 409 | return IRQ_HANDLED; |
425 | } | 410 | } |
426 | 411 | ||
@@ -904,12 +889,10 @@ static int __init ab3100_probe(struct i2c_client *client, | |||
904 | if (err) | 889 | if (err) |
905 | goto exit_no_setup; | 890 | goto exit_no_setup; |
906 | 891 | ||
907 | INIT_WORK(&ab3100->work, ab3100_work); | ||
908 | |||
909 | /* This real unpredictable IRQ is of course sampled for entropy */ | 892 | /* This real unpredictable IRQ is of course sampled for entropy */ |
910 | err = request_irq(client->irq, ab3100_irq_handler, | 893 | err = request_threaded_irq(client->irq, NULL, ab3100_irq_handler, |
911 | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, | 894 | IRQF_ONESHOT, |
912 | "AB3100 IRQ", ab3100); | 895 | "ab3100-core", ab3100); |
913 | if (err) | 896 | if (err) |
914 | goto exit_no_irq; | 897 | goto exit_no_irq; |
915 | 898 | ||