[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: Sifan Naeem <sifan.naeem@imgtec.com>
Acked-by: James Hogan <james.hogan@imgtec.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
Sifan Naeem 2014-12-11 17:06:24 -03:00 committed by Mauro Carvalho Chehab
parent 33e0183326
commit 02744c8c9a
2 changed files with 61 additions and 3 deletions

View File

@ -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)) {

View File

@ -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)