static irqreturn_t img_ir_isr(int irq, void *dev_id) { struct img_ir_priv *priv = dev_id; u32 irq_status; spin_lock(&priv->lock); /* we have to clear irqs before reading */ irq_status = img_ir_read(priv, IMG_IR_IRQ_STATUS); img_ir_write(priv, IMG_IR_IRQ_CLEAR, irq_status); /* don't handle valid data irqs if we're only interested in matches */ irq_status &= img_ir_read(priv, IMG_IR_IRQ_ENABLE); /* hand off edge interrupts to raw decode handler */ if (irq_status & IMG_IR_IRQ_EDGE && img_ir_raw_enabled(&priv->raw)) img_ir_isr_raw(priv, irq_status); /* hand off hardware match interrupts to hardware decode handler */ if (irq_status & (IMG_IR_IRQ_DATA_MATCH | IMG_IR_IRQ_DATA_VALID | IMG_IR_IRQ_DATA2_VALID) && img_ir_hw_enabled(&priv->hw)) img_ir_isr_hw(priv, irq_status); spin_unlock(&priv->lock); return IRQ_HANDLED; }
/* must be called with priv->lock held */ static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status) { struct img_ir_priv_raw *raw = &priv->raw; struct rc_dev *rc_dev = priv->raw.rdev; int multiple; u32 ir_status; /* find whether both rise and fall was detected */ multiple = ((irq_status & IMG_IR_IRQ_EDGE) == IMG_IR_IRQ_EDGE); /* * If so, we need to see if the level has actually changed. * If it's just noise that we didn't have time to process, * there's no point reporting it. */ ir_status = img_ir_read(priv, IMG_IR_STATUS) & IMG_IR_IRRXD; if (multiple && ir_status == raw->last_status) return; raw->last_status = ir_status; /* report the edge to the IR raw decoders */ if (ir_status) /* low */ ir_raw_event_store_edge(rc_dev, IR_SPACE); else /* high */ ir_raw_event_store_edge(rc_dev, IR_PULSE); ir_raw_event_handle(rc_dev); }
static void img_ir_ident(struct img_ir_priv *priv) { u32 core_rev = img_ir_read(priv, IMG_IR_CORE_REV); dev_info(priv->dev, "IMG IR Decoder (%d.%d.%d.%d) probed successfully\n", (core_rev & IMG_IR_DESIGNER) >> IMG_IR_DESIGNER_SHIFT, (core_rev & IMG_IR_MAJOR_REV) >> IMG_IR_MAJOR_REV_SHIFT, (core_rev & IMG_IR_MINOR_REV) >> IMG_IR_MINOR_REV_SHIFT, (core_rev & IMG_IR_MAINT_REV) >> IMG_IR_MAINT_REV_SHIFT); dev_info(priv->dev, "Modes:%s%s\n", img_ir_hw_enabled(&priv->hw) ? " hardware" : "", img_ir_raw_enabled(&priv->raw) ? " raw" : ""); }
void img_ir_setup_raw(struct img_ir_priv *priv) { u32 irq_en; if (!priv->raw.rdev) return; /* clear and enable edge interrupts */ spin_lock_irq(&priv->lock); irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE); irq_en |= IMG_IR_IRQ_EDGE; img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE); img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en); spin_unlock_irq(&priv->lock); }
void img_ir_remove_raw(struct img_ir_priv *priv) { struct img_ir_priv_raw *raw = &priv->raw; struct rc_dev *rdev = raw->rdev; u32 irq_en; if (!rdev) return; /* switch off and disable raw (edge) interrupts */ spin_lock_irq(&priv->lock); raw->rdev = NULL; irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE); irq_en &= ~IMG_IR_IRQ_EDGE; img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en); img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE); spin_unlock_irq(&priv->lock); rc_unregister_device(rdev); del_timer_sync(&raw->timer); }