Commit a2ef9261 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Arnd Bergmann
Browse files

Input: wm97xx - switch to using threaded IRQ



Instead of manually disabling and enabling interrupts and scheduling work
to access the device, let's use threaded oneshot interrupt handler. It
simplifies things.

Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parent e217b085
Loading
Loading
Loading
Loading
+7 −35
Original line number Diff line number Diff line
@@ -285,11 +285,12 @@ void wm97xx_set_suspend_mode(struct wm97xx *wm, u16 mode)
EXPORT_SYMBOL_GPL(wm97xx_set_suspend_mode);

/*
 * Handle a pen down interrupt.
 * Codec PENDOWN irq handler
 *
 */
static void wm97xx_pen_irq_worker(struct work_struct *work)
static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
{
	struct wm97xx *wm = container_of(work, struct wm97xx, pen_event_work);
	struct wm97xx *wm = dev_id;
	int pen_was_down = wm->pen_is_down;

	/* do we need to enable the touch panel reader */
@@ -343,27 +344,6 @@ static void wm97xx_pen_irq_worker(struct work_struct *work)
	if (!wm->pen_is_down && wm->mach_ops->acc_enabled)
		wm->mach_ops->acc_pen_up(wm);

	wm->mach_ops->irq_enable(wm, 1);
}

/*
 * Codec PENDOWN irq handler
 *
 * We have to disable the codec interrupt in the handler because it
 * can take up to 1ms to clear the interrupt source. We schedule a task
 * in a work queue to do the actual interaction with the chip.  The
 * interrupt is then enabled again in the slow handler when the source
 * has been cleared.
 */
static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
{
	struct wm97xx *wm = dev_id;

	if (!work_pending(&wm->pen_event_work)) {
		wm->mach_ops->irq_enable(wm, 0);
		queue_work(wm->ts_workq, &wm->pen_event_work);
	}

	return IRQ_HANDLED;
}

@@ -374,11 +354,8 @@ static int wm97xx_init_pen_irq(struct wm97xx *wm)
{
	u16 reg;

	/* If an interrupt is supplied an IRQ enable operation must also be
	 * provided. */
	BUG_ON(!wm->mach_ops->irq_enable);

	if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED,
	if (request_threaded_irq(wm->pen_irq, NULL, wm97xx_pen_interrupt,
				 IRQF_SHARED | IRQF_ONESHOT,
				 "wm97xx-pen", wm)) {
		dev_err(wm->dev,
			"Failed to register pen down interrupt, polling");
@@ -509,7 +486,6 @@ static int wm97xx_ts_input_open(struct input_dev *idev)
	wm->codec->dig_enable(wm, 1);

	INIT_DELAYED_WORK(&wm->ts_reader, wm97xx_ts_reader);
	INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker);

	wm->ts_reader_min_interval = HZ >= 100 ? HZ / 100 : 1;
	if (wm->ts_reader_min_interval < 1)
@@ -560,10 +536,6 @@ static void wm97xx_ts_input_close(struct input_dev *idev)

	wm->pen_is_down = 0;

	/* Balance out interrupt disables/enables */
	if (cancel_work_sync(&wm->pen_event_work))
		wm->mach_ops->irq_enable(wm, 1);

	/* ts_reader rearms itself so we need to explicitly stop it
	 * before we destroy the workqueue.
	 */
+0 −1
Original line number Diff line number Diff line
@@ -281,7 +281,6 @@ struct wm97xx {
	unsigned long ts_reader_min_interval; /* Minimum interval */
	unsigned int pen_irq;		/* Pen IRQ number in use */
	struct workqueue_struct *ts_workq;
	struct work_struct pen_event_work;
	u16 acc_slot;			/* AC97 slot used for acc touch data */
	u16 acc_rate;			/* acc touch data rate */
	unsigned pen_is_down:1;		/* Pen is down */