static irqreturn_t ab3100_irq_handler(int irq, void *data) { struct ab3100 *ab3100 = data; u8 event_regs[3]; u32 fatevent; int err; err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, event_regs, 3); if (err) goto err_event; fatevent = (event_regs[0] << 16) | (event_regs[1] << 8) | event_regs[2]; if (!ab3100->startup_events_read) { ab3100->startup_events[0] = event_regs[0]; ab3100->startup_events[1] = event_regs[1]; ab3100->startup_events[2] = event_regs[2]; ab3100->startup_events_read = true; } blocking_notifier_call_chain(&ab3100->event_subscribers, fatevent, NULL); dev_dbg(ab3100->dev, "IRQ Event: 0x%08x\n", fatevent); return IRQ_HANDLED; err_event: dev_dbg(ab3100->dev, "error reading event status\n"); return IRQ_HANDLED; }
static int get_register_page_interruptible(struct device *dev, u8 bank, u8 first_reg, u8 *regvals, u8 numregs) { struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); return ab3100_get_register_page_interruptible(ab3100, first_reg, regvals, numregs); }
/* Interrupt handling worker */ static void ab3100_work(struct work_struct *work) { struct ab3100 *ab3100 = container_of(work, struct ab3100, work); u8 event_regs[3]; u32 fatevent; int err; err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, event_regs, 3); if (err) goto err_event_wq; fatevent = (event_regs[0] << 16) | (event_regs[1] << 8) | event_regs[2]; if (!ab3100->startup_events_read) { ab3100->startup_events = fatevent; ab3100->startup_events_read = true; } /* * The notified parties will have to mask out the events * they're interested in and react to them. They will be * notified on all events, then they use the fatevent value * to determine if they're interested. */ blocking_notifier_call_chain(&ab3100->event_subscribers, fatevent, NULL); dev_dbg(ab3100->dev, "IRQ Event: 0x%08x\n", fatevent); /* By now the IRQ should be acked and deasserted so enable it again */ enable_irq(ab3100->i2c_client->irq); return; err_event_wq: dev_dbg(ab3100->dev, "error in event workqueue\n"); /* Enable the IRQ anyway, what choice do we have? */ enable_irq(ab3100->i2c_client->irq); return; }
/* * This is a threaded interrupt handler so we can make some * I2C calls etc. */ static irqreturn_t ab3100_irq_handler(int irq, void *data) { struct ab3100 *ab3100 = data; u8 event_regs[3]; u32 fatevent; int err; add_interrupt_randomness(irq); err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, event_regs, 3); if (err) goto err_event; fatevent = (event_regs[0] << 16) | (event_regs[1] << 8) | event_regs[2]; if (!ab3100->startup_events_read) { ab3100->startup_events[0] = event_regs[0]; ab3100->startup_events[1] = event_regs[1]; ab3100->startup_events[2] = event_regs[2]; ab3100->startup_events_read = true; } /* * The notified parties will have to mask out the events * they're interested in and react to them. They will be * notified on all events, then they use the fatevent value * to determine if they're interested. */ blocking_notifier_call_chain(&ab3100->event_subscribers, fatevent, NULL); dev_dbg(ab3100->dev, "IRQ Event: 0x%08x\n", fatevent); return IRQ_HANDLED; err_event: dev_dbg(ab3100->dev, "error reading event status\n"); return IRQ_HANDLED; }
static void ab3100_work(struct work_struct *work) { struct ab3100 *ab3100 = container_of(work, struct ab3100, work); u8 event_regs[3]; u32 fatevent; int err; err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, event_regs, 3); if (err) goto err_event_wq; fatevent = (event_regs[0] << 16) | (event_regs[1] << 8) | event_regs[2]; if (!ab3100->startup_events_read) { ab3100->startup_events = fatevent; ab3100->startup_events_read = true; } blocking_notifier_call_chain(&ab3100->event_subscribers, fatevent, NULL); dev_dbg(ab3100->dev, "IRQ Event: 0x%08x\n", fatevent); enable_irq(ab3100->i2c_client->irq); return; err_event_wq: dev_dbg(ab3100->dev, "error in event workqueue\n"); enable_irq(ab3100->i2c_client->irq); return; }