Ejemplo n.º 1
0
static void omap1_cam_remove_device(struct soc_camera_device *icd)
{
	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
	struct omap1_cam_dev *pcdev = ici->priv;
	u32 ctrlclock;

	BUG_ON(icd != pcdev->icd);

	suspend_capture(pcdev);
	disable_capture(pcdev);

	sensor_reset(pcdev, true);

	/* disable and release system clocks */
	ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
	ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN);
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);

	ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz;
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN);

	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);

	clk_disable(pcdev->clk);

	pcdev->icd = NULL;

	dev_dbg(icd->dev.parent,
		"OMAP1 Camera driver detached from camera %d\n", icd->devnum);
}
Ejemplo n.º 2
0
static void suspend_capture(struct omap1_cam_dev *pcdev)
{
	u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);

	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
	omap_stop_dma(pcdev->dma_ch);
}
Ejemplo n.º 3
0
static void omap1_videobuf_queue(struct videobuf_queue *vq,
						struct videobuf_buffer *vb)
{
	struct soc_camera_device *icd = vq->priv_data;
	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
	struct omap1_cam_dev *pcdev = ici->priv;
	struct omap1_cam_buf *buf;
	u32 mode;

	list_add_tail(&vb->queue, &pcdev->capture);
	vb->state = VIDEOBUF_QUEUED;

	if (pcdev->active) {
		/*
		 * Capture in progress, so don't touch pcdev->ready even if
		 * empty. Since the transfer of the DMA programming register set
		 * content to the DMA working register set is done automatically
		 * by the DMA hardware, this can pretty well happen while we
		 * are keeping the lock here. Leave fetching it from the queue
		 * to be done when a next DMA interrupt occures instead.
		 */
		return;
	}

	WARN_ON(pcdev->ready);

	buf = prepare_next_vb(pcdev);
	if (WARN_ON(!buf))
		return;

	pcdev->active = buf;
	pcdev->ready = NULL;

	dev_dbg(icd->dev.parent,
		"%s: capture not active, setup FIFO, start DMA\n", __func__);
	mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK;
	mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT;
	CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA);

	if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
		/*
		 * In SG mode, the above prepare_next_vb() didn't actually
		 * put anything into the DMA programming register set,
		 * so we have to do it now, before activating DMA.
		 */
		try_next_sgbuf(pcdev->dma_ch, buf);
	}

	start_capture(pcdev);
}
Ejemplo n.º 4
0
static void start_capture(struct omap1_cam_dev *pcdev)
{
	struct omap1_cam_buf *buf = pcdev->active;
	u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
	u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN;

	if (WARN_ON(!buf))
		return;

	/*
	 * Enable start of frame interrupt, which we will use for activating
	 * our end of frame watchdog when capture actually starts.
	 */
	mode |= EN_V_UP;

	if (unlikely(ctrlclock & LCLK_EN))
		/* stop pixel clock before FIFO reset */
		CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
	/* reset FIFO */
	CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO);

	omap_start_dma(pcdev->dma_ch);

	if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
		/*
		 * In SG mode, it's a good moment for fetching next sgbuf
		 * from the current sglist and, if available, already putting
		 * its parameters into the DMA programming register set.
		 */
		try_next_sgbuf(pcdev->dma_ch, buf);
	}

	/* (re)enable pixel clock */
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN);
	/* release FIFO reset */
	CAM_WRITE(pcdev, MODE, mode);
}
Ejemplo n.º 5
0
static void omap1_cam_clock_stop(struct soc_camera_host *ici)
{
	struct omap1_cam_dev *pcdev = ici->priv;
	u32 ctrlclock;

	suspend_capture(pcdev);
	disable_capture(pcdev);

	sensor_reset(pcdev, true);

	/* disable and release system clocks */
	ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
	ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN);
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);

	ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz;
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN);

	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);

	clk_disable(pcdev->clk);
}
Ejemplo n.º 6
0
static irqreturn_t cam_isr(int irq, void *data)
{
	struct omap1_cam_dev *pcdev = data;
	struct device *dev = pcdev->icd->dev.parent;
	struct omap1_cam_buf *buf = pcdev->active;
	u32 it_status;
	unsigned long flags;

	it_status = CAM_READ(pcdev, IT_STATUS);
	if (!it_status)
		return IRQ_NONE;

	spin_lock_irqsave(&pcdev->lock, flags);

	if (WARN_ON(!buf)) {
		dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
			 __func__, it_status);
		suspend_capture(pcdev);
		disable_capture(pcdev);
		goto out;
	}

	if (unlikely(it_status & FIFO_FULL)) {
		dev_warn(dev, "%s: FIFO overflow\n", __func__);

	} else if (it_status & V_DOWN) {
		/* end of video frame watchdog */
		if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
			/*
			 * In CONTIG mode, the watchdog is disabled with
			 * successful DMA end of block interrupt, and reenabled
			 * on next frame start. If we get here, there is nothing
			 * to check, we must be out of sync.
			 */
		} else {
			if (buf->sgcount == 2) {
				/*
				 * If exactly 2 sgbufs from the next sglist have
				 * been programmed into the DMA engine (the
				 * first one already transferred into the DMA
				 * runtime register set, the second one still
				 * in the programming set), then we are in sync.
				 */
				goto out;
			}
		}
		dev_notice(dev, "%s: unexpected end of video frame\n",
				__func__);

	} else if (it_status & V_UP) {
		u32 mode;

		if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
			/*
			 * In CONTIG mode, we need this interrupt every frame
			 * in oredr to reenable our end of frame watchdog.
			 */
			mode = CAM_READ_CACHE(pcdev, MODE);
		} else {
			/*
			 * In SG mode, the below enabled end of frame watchdog
			 * is kept on permanently, so we can turn this one shot
			 * setup off.
			 */
			mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP;
		}

		if (!(mode & EN_V_DOWN)) {
			/* (re)enable end of frame watchdog interrupt */
			mode |= EN_V_DOWN;
		}
		CAM_WRITE(pcdev, MODE, mode);
		goto out;

	} else {
		dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
				__func__, it_status);
		goto out;
	}

	videobuf_done(pcdev, VIDEOBUF_ERROR);
out:
	spin_unlock_irqrestore(&pcdev->lock, flags);
	return IRQ_HANDLED;
}
Ejemplo n.º 7
0
static void dma_isr(int channel, unsigned short status, void *data)
{
	struct omap1_cam_dev *pcdev = data;
	struct omap1_cam_buf *buf = pcdev->active;
	unsigned long flags;

	spin_lock_irqsave(&pcdev->lock, flags);

	if (WARN_ON(!buf)) {
		suspend_capture(pcdev);
		disable_capture(pcdev);
		goto out;
	}

	if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
		/*
		 * In CONTIG mode, assume we have just managed to collect the
		 * whole frame, hopefully before our end of frame watchdog is
		 * triggered. Then, all we have to do is disabling the watchdog
		 * for this frame, and calling videobuf_done() with success
		 * indicated.
		 */
		CAM_WRITE(pcdev, MODE,
				CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN);
		videobuf_done(pcdev, VIDEOBUF_DONE);
	} else {
		/*
		 * In SG mode, we have to process every sgbuf from the current
		 * sglist, one after another.
		 */
		if (buf->sgbuf) {
			/*
			 * Current sglist not completed yet, try fetching next
			 * sgbuf, hopefully putting it into the DMA programming
			 * register set, making it ready for next DMA
			 * autoreinitialization.
			 */
			try_next_sgbuf(pcdev->dma_ch, buf);
			if (buf->sgbuf)
				goto out;

			/*
			 * No more sgbufs left in the current sglist. This
			 * doesn't mean that the whole videobuffer is already
			 * complete, but only that the last sgbuf from the
			 * current sglist is about to be filled. It will be
			 * ready on next DMA interrupt, signalled with the
			 * buf->sgbuf set back to NULL.
			 */
			if (buf->result != VIDEOBUF_ERROR) {
				/*
				 * Video frame collected without errors so far,
				 * we can prepare for collecting a next one
				 * as soon as DMA gets autoreinitialized
				 * after the current (last) sgbuf is completed.
				 */
				buf = prepare_next_vb(pcdev);
				if (!buf)
					goto out;

				try_next_sgbuf(pcdev->dma_ch, buf);
				goto out;
			}
		}
		/* end of videobuf */
		videobuf_done(pcdev, buf->result);
	}

out:
	spin_unlock_irqrestore(&pcdev->lock, flags);
}
Ejemplo n.º 8
0
static void disable_capture(struct omap1_cam_dev *pcdev)
{
	u32 mode = CAM_READ_CACHE(pcdev, MODE);

	CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA));
}
Ejemplo n.º 9
0
static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
		__u32 pixfmt)
{
	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
	struct omap1_cam_dev *pcdev = ici->priv;
	struct device *dev = icd->dev.parent;
	const struct soc_camera_format_xlate *xlate;
	const struct soc_mbus_pixelfmt *fmt;
	unsigned long camera_flags, common_flags;
	u32 ctrlclock, mode;
	int ret;

	camera_flags = icd->ops->query_bus_param(icd);

	common_flags = soc_camera_bus_param_compatible(camera_flags,
			SOCAM_BUS_FLAGS);
	if (!common_flags)
		return -EINVAL;

	/* Make choices, possibly based on platform configuration */
	if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
			(common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
		if (!pcdev->pdata ||
				pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING)
			common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
		else
			common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
	}

	ret = icd->ops->set_bus_param(icd, common_flags);
	if (ret < 0)
		return ret;

	ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
	if (ctrlclock & LCLK_EN)
		CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);

	if (common_flags & SOCAM_PCLK_SAMPLE_RISING) {
		dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n");
		ctrlclock |= POLCLK;
	} else {
		dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n");
		ctrlclock &= ~POLCLK;
	}
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);

	if (ctrlclock & LCLK_EN)
		CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);

	/* select bus endianess */
	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
	fmt = xlate->host_fmt;

	mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA);
	if (fmt->order == SOC_MBUS_ORDER_LE) {
		dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n");
		CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD);
	} else {
		dev_dbg(dev, "MODE_REG |= ORDERCAMD\n");
		CAM_WRITE(pcdev, MODE, mode | ORDERCAMD);
	}

	return 0;
}
Ejemplo n.º 10
0
static int omap1_cam_set_bus_param(struct soc_camera_device *icd)
{
	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
	struct device *dev = icd->parent;
	struct soc_camera_host *ici = to_soc_camera_host(dev);
	struct omap1_cam_dev *pcdev = ici->priv;
	u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
	const struct soc_camera_format_xlate *xlate;
	const struct soc_mbus_pixelfmt *fmt;
	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
	unsigned long common_flags;
	u32 ctrlclock, mode;
	int ret;

	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
	if (!ret) {
		common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS);
		if (!common_flags) {
			dev_warn(dev,
				 "Flags incompatible: camera 0x%x, host 0x%x\n",
				 cfg.flags, SOCAM_BUS_FLAGS);
			return -EINVAL;
		}
	} else if (ret != -ENOIOCTLCMD) {
		return ret;
	} else {
		common_flags = SOCAM_BUS_FLAGS;
	}

	/* Make choices, possibly based on platform configuration */
	if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
			(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
		if (!pcdev->pdata ||
				pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING)
			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
		else
			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
	}

	cfg.flags = common_flags;
	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
	if (ret < 0 && ret != -ENOIOCTLCMD) {
		dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n",
			common_flags, ret);
		return ret;
	}

	ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
	if (ctrlclock & LCLK_EN)
		CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);

	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) {
		dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n");
		ctrlclock |= POLCLK;
	} else {
		dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n");
		ctrlclock &= ~POLCLK;
	}
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);

	if (ctrlclock & LCLK_EN)
		CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);

	/* select bus endianness */
	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
	fmt = xlate->host_fmt;

	mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA);
	if (fmt->order == SOC_MBUS_ORDER_LE) {
		dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n");
		CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD);
	} else {
		dev_dbg(dev, "MODE_REG |= ORDERCAMD\n");
		CAM_WRITE(pcdev, MODE, mode | ORDERCAMD);
	}

	return 0;
}