Ejemplo n.º 1
0
static inline void pv_clk_enable(struct pv_dev *dev)
{
	if (clk_enable(dev->apb_clk))
		pv_err("failed to enable apb clk\n");
	if (clk_enable(dev->pix_clk))
		pv_err("failed to enable pix clk\n");
}
Ejemplo n.º 2
0
int check_pv_state(int event, struct pv_config_t *config)
{
	u32 pv_base, stat, istat, ien;
	struct pv_dev *dev;

	if (!config)
		return -EINVAL;

	dev = container_of(config, struct pv_dev, vid_config);
	pv_base = dev->base_addr;
	istat = readl(pv_base + REG_PV_INTSTAT);
	stat = readl(pv_base + REG_PV_STAT);
	ien = readl(pv_base + REG_PV_INTEN);
	pv_err("event=%d state=%d istat=0x%x stat=0x%x ien=0x%x\n",
		event, dev->state, istat, stat, ien);

	if (istat & ien) {
		writel(istat, pv_base + REG_PV_INTSTAT);
		return 0;
	} else {
		return -1;
	}
}
Ejemplo n.º 3
0
int pv_init(struct pv_init_t *init, struct pv_config_t **config)
{
	struct pv_dev *dev;
	int ret;

	if (!init || (init->id >= MAX_PV_INST) || !init->irq
#ifdef PV_HAS_CLK
		|| !init->apb_clk_name || !init->pix_clk_name
#endif
		|| !init->base_addr || !init->err_cb || !init->eof_cb) {
		pv_err("Invalid input parameters\n");
		ret = -EINVAL;
		goto done;
	}
	if (g_pv_init[init->id]) {
		pv_err("All instances of PV have already been initialised\n");
		ret = -EPERM;
		goto done;
	}

	dev = kzalloc(sizeof(struct pv_dev), GFP_KERNEL);
	if (!dev) {
		pv_err("couldn't allocate memory for pv_data\n");
		ret = -ENOMEM;
		goto done;
	}
	ret = request_irq(init->irq, pv_isr, IRQF_TRIGGER_HIGH, "PV", dev);
	if (ret < 0) {
		pv_err("failed to get irq\n");
		goto fail;
	}
	irq_set_affinity(init->irq, cpumask_of(1));
#ifdef PV_HAS_CLK
	dev->apb_clk = clk_get(NULL, init->apb_clk_name);
	if (IS_ERR(dev->apb_clk)) {
		pv_err("failed to get %s\n", init->apb_clk_name);
		ret = PTR_ERR(dev->apb_clk);
		goto fail;
	}

	dev->pix_clk = clk_get(NULL, init->pix_clk_name);
	if (IS_ERR(dev->pix_clk)) {
		pv_err("failed to get %s\n", init->pix_clk_name);
		ret = PTR_ERR(dev->pix_clk);
		goto fail;
	}
#endif
	dev->id = init->id;
	dev->irq = init->irq;
	dev->base_addr = init->base_addr;
	dev->err_cb = init->err_cb;
	dev->eof_cb = init->eof_cb;
	INIT_WORK(&dev->err_work, err_cb);
	INIT_WORK(&dev->eof_work, eof_cb);
	dev->state = PV_INIT_DONE;
	if (!g_display_enabled) {
		printk("%s:%d\n", __func__, __LINE__);
		dev->state = PV_INIT_DONE;
	} else {
		pv_clk_enable(dev);
		printk("enabling pv isr in init\n");
#ifdef INT_4_LONG_PKT
		writel(VFP_START, dev->base_addr + REG_PV_INTEN); //workaround1
#endif
		dev->state = PV_ENABLED;
	}
	g_pv_init[init->id] = true;
	*config = &dev->vid_config;
	ret = 0;
	goto done;

fail:
	free_irq(init->irq, NULL);
	kfree(dev);
done:
	return ret;
}
Ejemplo n.º 4
0
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);
			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) {
				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_RESUME_STREAM:
		if (PV_STOPPED == dev->state) {
			writel((readl(pv_base + REG_PV_INTEN)
				& ~VFP_END), pv_base + REG_PV_INTEN);
			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);
			if (!vid_config->cont) {
				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_PAUSE_STREAM_SYNC:
		if (PV_ENABLED == dev->state) {
			unsigned long flags;
			if (vid_config->cont) {
				writel(readl(pv_base + REG_PV_VC) & ~VIDEN,
					pv_base + REG_PV_VC);
				spin_lock_irqsave(&lock, flags);
				dev->state = PV_STOPPING;
				spin_unlock_irqrestore(&lock, flags);
			}
		}

		/* In case of !cont mode, PV would be in stopping state */
		if (PV_STOPPING == dev->state) {
			unsigned long flags;
			int retry = 1000; /*50ms */
			while (retry > 0) {
				if (readl(pv_base + REG_PV_STAT)
					& VID_IDLE_STAT)
					break;
				usleep_range(50, 60);
				retry--;
			}
			if (retry <= 0)
				pv_err("PV_PAUSE_STREAM_SYNC fail in PV_STOPPING\n");

			spin_lock_irqsave(&lock, flags);
			dev->state = PV_STOPPED;
			spin_unlock_irqrestore(&lock, flags);
		}
		ret = 0;
		break;
	case PV_STOP_EOF_ASYNC:
		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;
}