static void eof_cb(struct work_struct *work) { struct pv_dev *dev = container_of(work, struct pv_dev, eof_work); if (PV_STOPPED == dev->state) pv_clk_disable(dev); if (dev->eof_cb) dev->eof_cb(); }
static void eof_cb(struct work_struct *work) { struct pv_dev *dev = container_of(work, struct pv_dev, eof_work); if (PV_STOPPED == dev->state) { u32 pv_base = dev->base_addr; writel(0, pv_base + REG_PV_INTEN); writel(readl(pv_base + REG_PV_C) & ~PVEN, pv_base + REG_PV_C); pv_clk_disable(dev); } if (dev->eof_cb) dev->eof_cb(); }
int pv_change_state(int event, struct pv_config_t *vid_config) { u32 pv_base; struct pv_dev *dev; int ret = -EINVAL; if (!vid_config) return -EINVAL; dev = container_of(vid_config, struct pv_dev, vid_config); pv_base = dev->base_addr; switch (event) { case PV_VID_CONFIG: #if 0 int cnt = 100; while ((PV_STOPPING == dev->state) && cnt-- ) { if (readl(pv_base + REG_PV_STAT) & VID_IDLE_STAT) dev->state = PV_STOPPED; else usleep_range(1000, 1100); } #endif if ((PV_STOPPED == dev->state) || (PV_INIT_DONE == dev->state)) { pv_clk_enable(dev); ret = pv_vid_config(vid_config); pv_clk_disable(dev); dev->state = PV_CONFIGURED; ret = 0; } else { return -EBUSY; } break; case PV_START: if ((PV_STOPPED == dev->state) || (PV_CONFIGURED == dev->state)) { pv_clk_enable(dev); writel((readl(pv_base + REG_PV_INTEN) & ~VFP_END), pv_base + REG_PV_INTEN); #ifdef INT_4_LONG_PKT writel(VFP_START, (dev->base_addr + REG_PV_INTEN));//workaround 1 #endif writel(readl(pv_base + REG_PV_C) | PVEN, pv_base + REG_PV_C); writel(readl(pv_base + REG_PV_VC) | VIDEN, pv_base + REG_PV_VC); //enable_irq(dev->irq); if (!vid_config->cont) { printk("single shot enabled!!!\n"); writel((readl(pv_base + REG_PV_INTEN) | VFP_END), pv_base + REG_PV_INTEN); dev->state = PV_STOPPING; } else { dev->state = PV_ENABLED; } ret = 0; } else { return -EBUSY; } break; case PV_STOP_EOF: if (PV_ENABLED == dev->state) { unsigned long flags; if (vid_config->cont) { spin_lock_irqsave(&lock, flags); writel(readl(pv_base + REG_PV_VC) & ~VIDEN, pv_base + REG_PV_VC); writel((readl(pv_base + REG_PV_INTEN) | VFP_END), pv_base + REG_PV_INTEN); dev->state = PV_STOPPING; spin_unlock_irqrestore(&lock, flags); } else { spin_lock_irqsave(&lock, flags); /* Stop after the currrent frame is txferd. Need to find out if there would be an interrupt at VFP_END in single-shot/cmd mode. + VFP_END will be enabled for !cont mode.*/ writel((readl(pv_base + REG_PV_INTEN) | VFP_END), pv_base + REG_PV_INTEN); dev->state = PV_STOPPING; spin_unlock_irqrestore(&lock, flags); } ret = 0; } else { return -EBUSY; } break; case PV_STOP_IMM: if ((PV_STOPPING == dev->state) || (PV_ENABLED == dev->state)) { unsigned long flags; spin_lock_irqsave(&lock, flags); writel(readl(pv_base + REG_PV_VC) & ~VIDEN, pv_base + REG_PV_VC); writel(readl(pv_base + REG_PV_C) & ~PVEN, pv_base + REG_PV_C); /* Todo: Clear FIFO? */ //disable_irq(dev->irq); pv_clk_disable(dev); dev->state = PV_STOPPED; spin_unlock_irqrestore(&lock, flags); ret = 0; } else { return -EBUSY; } break; case PV_RESET: /* Need to reset the PV block and take it to hardware reset state*/ break; default: pv_info("Invalid option %d\n", dev->state); break; } return ret; }