Commit 02744c8c authored by Sifan Naeem's avatar Sifan Naeem Committed by Mauro Carvalho Chehab
Browse files

[media] rc: img-ir: biphase enabled with workaround



Biphase decoding in the current img-ir has got a quirk, where multiple
Interrupts are generated when an incomplete IR code is received by the
decoder.

Patch adds a work around for the quirk and enables biphase decoding.

Signed-off-by: default avatarSifan Naeem <sifan.naeem@imgtec.com>
Acked-by: default avatarJames Hogan <james.hogan@imgtec.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 33e01833
Loading
Loading
Loading
Loading
+57 −3
Original line number Diff line number Diff line
@@ -52,6 +52,11 @@ static struct img_ir_decoder *img_ir_decoders[] = {

#define IMG_IR_QUIRK_CODE_BROKEN	0x1	/* Decode is broken */
#define IMG_IR_QUIRK_CODE_LEN_INCR	0x2	/* Bit length needs increment */
/*
 * The decoder generates rapid interrupts without actually having
 * received any new data after an incomplete IR code is decoded.
 */
#define IMG_IR_QUIRK_CODE_IRQ		0x4

/* functions for preprocessing timings, ensuring max is set */

@@ -542,6 +547,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
	 */
	spin_unlock_irq(&priv->lock);
	del_timer_sync(&hw->end_timer);
	del_timer_sync(&hw->suspend_timer);
	spin_lock_irq(&priv->lock);

	hw->stopping = false;
@@ -861,6 +867,29 @@ static void img_ir_end_timer(unsigned long arg)
	spin_unlock_irq(&priv->lock);
}

/*
 * Timer function to re-enable the current protocol after it had been
 * cleared when invalid interrupts were generated due to a quirk in the
 * img-ir decoder.
 */
static void img_ir_suspend_timer(unsigned long arg)
{
	struct img_ir_priv *priv = (struct img_ir_priv *)arg;

	spin_lock_irq(&priv->lock);
	/*
	 * Don't overwrite enabled valid/match IRQs if they have already been
	 * changed by e.g. a filter change.
	 */
	if ((priv->hw.quirk_suspend_irq & IMG_IR_IRQ_EDGE) ==
				img_ir_read(priv, IMG_IR_IRQ_ENABLE))
		img_ir_write(priv, IMG_IR_IRQ_ENABLE,
					priv->hw.quirk_suspend_irq);
	/* enable */
	img_ir_write(priv, IMG_IR_CONTROL, priv->hw.reg_timings.ctrl);
	spin_unlock_irq(&priv->lock);
}

#ifdef CONFIG_COMMON_CLK
static void img_ir_change_frequency(struct img_ir_priv *priv,
				    struct clk_notifier_data *change)
@@ -926,15 +955,38 @@ void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status)
	if (!hw->decoder)
		return;

	ct = hw->decoder->control.code_type;

	ir_status = img_ir_read(priv, IMG_IR_STATUS);
	if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2)))
	if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) {
		if (!(priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_IRQ) ||
				hw->stopping)
			return;
		/*
		 * The below functionality is added as a work around to stop
		 * multiple Interrupts generated when an incomplete IR code is
		 * received by the decoder.
		 * The decoder generates rapid interrupts without actually
		 * having received any new data. After a single interrupt it's
		 * expected to clear up, but instead multiple interrupts are
		 * rapidly generated. only way to get out of this loop is to
		 * reset the control register after a short delay.
		 */
		img_ir_write(priv, IMG_IR_CONTROL, 0);
		hw->quirk_suspend_irq = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
		img_ir_write(priv, IMG_IR_IRQ_ENABLE,
			     hw->quirk_suspend_irq & IMG_IR_IRQ_EDGE);

		/* Timer activated to re-enable the protocol. */
		mod_timer(&hw->suspend_timer,
			  jiffies + msecs_to_jiffies(5));
		return;
	}
	ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2);
	img_ir_write(priv, IMG_IR_STATUS, ir_status);

	len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT;
	/* some versions report wrong length for certain code types */
	ct = hw->decoder->control.code_type;
	if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR)
		++len;

@@ -976,7 +1028,7 @@ static void img_ir_probe_hw_caps(struct img_ir_priv *priv)
	hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN]
		|= IMG_IR_QUIRK_CODE_LEN_INCR;
	hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE]
		|= IMG_IR_QUIRK_CODE_BROKEN;
		|= IMG_IR_QUIRK_CODE_IRQ;
	hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS]
		|= IMG_IR_QUIRK_CODE_BROKEN;
}
@@ -995,6 +1047,8 @@ int img_ir_probe_hw(struct img_ir_priv *priv)

	/* Set up the end timer */
	setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv);
	setup_timer(&hw->suspend_timer, img_ir_suspend_timer,
				(unsigned long)priv);

	/* Register a clock notifier */
	if (!IS_ERR(priv->clk)) {
+4 −0
Original line number Diff line number Diff line
@@ -218,6 +218,7 @@ enum img_ir_mode {
 * @rdev:		Remote control device
 * @clk_nb:		Notifier block for clock notify events.
 * @end_timer:		Timer until repeat timeout.
 * @suspend_timer:	Timer to re-enable protocol.
 * @decoder:		Current decoder settings.
 * @enabled_protocols:	Currently enabled protocols.
 * @clk_hz:		Current core clock rate in Hz.
@@ -228,12 +229,14 @@ enum img_ir_mode {
 * @stopping:		Indicates that decoder is being taken down and timers
 *			should not be restarted.
 * @suspend_irqen:	Saved IRQ enable mask over suspend.
 * @quirk_suspend_irq:	Saved IRQ enable mask over quirk suspend timer.
 */
struct img_ir_priv_hw {
	unsigned int			ct_quirks[4];
	struct rc_dev			*rdev;
	struct notifier_block		clk_nb;
	struct timer_list		end_timer;
	struct timer_list		suspend_timer;
	const struct img_ir_decoder	*decoder;
	u64				enabled_protocols;
	unsigned long			clk_hz;
@@ -244,6 +247,7 @@ struct img_ir_priv_hw {
	enum img_ir_mode		mode;
	bool				stopping;
	u32				suspend_irqen;
	u32				quirk_suspend_irq;
};

static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw)