Пример #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);
}
Пример #2
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);
}
Пример #3
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;
}
Пример #4
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);
}
Пример #5
0
static void videobuf_done(struct omap1_cam_dev *pcdev,
		enum videobuf_state result)
{
	struct omap1_cam_buf *buf = pcdev->active;
	struct videobuf_buffer *vb;
	struct device *dev = pcdev->icd->dev.parent;

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

	if (result == VIDEOBUF_ERROR)
		suspend_capture(pcdev);

	vb = &buf->vb;
	if (waitqueue_active(&vb->done)) {
		if (!pcdev->ready && result != VIDEOBUF_ERROR) {
			/*
			 * No next buffer has been entered into the DMA
			 * programming register set on time (could be done only
			 * while the previous DMA interurpt was processed, not
			 * later), so the last DMA block, be it a whole buffer
			 * if in CONTIG or its last sgbuf if in SG mode, is
			 * about to be reused by the just autoreinitialized DMA
			 * engine, and overwritten with next frame data. Best we
			 * can do is stopping the capture as soon as possible,
			 * hopefully before the next frame start.
			 */
			suspend_capture(pcdev);
		}
		vb->state = result;
		do_gettimeofday(&vb->ts);
		if (result != VIDEOBUF_ERROR)
			vb->field_count++;
		wake_up(&vb->done);

		/* shift in next buffer */
		buf = pcdev->ready;
		pcdev->active = buf;
		pcdev->ready = NULL;

		if (!buf) {
			/*
			 * No next buffer was ready on time (see above), so
			 * indicate error condition to force capture restart or
			 * stop, depending on next buffer already queued or not.
			 */
			result = VIDEOBUF_ERROR;
			prepare_next_vb(pcdev);

			buf = pcdev->ready;
			pcdev->active = buf;
			pcdev->ready = NULL;
		}
	} else if (pcdev->ready) {
		/*
		 * In both CONTIG and SG mode, the DMA engine has possibly
		 * been already autoreinitialized with the preprogrammed
		 * pcdev->ready buffer.  We can either accept this fact
		 * and just swap the buffers, or provoke an error condition
		 * and restart capture.  The former seems less intrusive.
		 */
		dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n",
				__func__);
		pcdev->active = pcdev->ready;

		if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
			/*
			 * In SG mode, we have to make sure that the buffer we
			 * are putting back into the pcdev->ready is marked
			 * fresh.
			 */
			buf->sgbuf = NULL;
		}
		pcdev->ready = buf;

		buf = pcdev->active;
	} else {
		/*
		 * No next buffer has been entered into
		 * the DMA programming register set on time.
		 */
		if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
			/*
			 * In CONTIG mode, the DMA engine has already been
			 * reinitialized with the current buffer. Best we can do
			 * is not touching it.
			 */
			dev_dbg(dev,
				"%s: nobody waiting on videobuf, reuse it\n",
				__func__);
		} else {
			/*
			 * In SG mode, the DMA engine has just been
			 * autoreinitialized with the last sgbuf from the
			 * current list. Restart capture in order to transfer
			 * next frame start into the first sgbuf, not the last
			 * one.
			 */
			if (result != VIDEOBUF_ERROR) {
				suspend_capture(pcdev);
				result = VIDEOBUF_ERROR;
			}
		}
	}

	if (!buf) {
		dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__);
		disable_capture(pcdev);
		return;
	}

	if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
		/*
		 * In CONTIG mode, the current buffer parameters had already
		 * been entered into the DMA programming register set while the
		 * buffer was fetched with prepare_next_vb(), they may have also
		 * been transferred into the runtime set and already active if
		 * the DMA still running.
		 */
	} else {
		/* In SG mode, extra steps are required */
		if (result == VIDEOBUF_ERROR)
			/* make sure we (re)use sglist from start on error */
			buf->sgbuf = NULL;

		/*
		 * In any case, enter the next sgbuf parameters into the DMA
		 * programming register set.  They will be used either during
		 * nearest DMA autoreinitialization or, in case of an error,
		 * on DMA startup below.
		 */
		try_next_sgbuf(pcdev->dma_ch, buf);
	}

	if (result == VIDEOBUF_ERROR) {
		dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n",
				__func__);
		start_capture(pcdev);
		/*
		 * In SG mode, the above also resulted in the next sgbuf
		 * parameters being entered into the DMA programming register
		 * set, making them ready for next DMA autoreinitialization.
		 */
	}

	/*
	 * Finally, try fetching next buffer.
	 * In CONTIG mode, it will also enter it into the DMA programming
	 * register set, making it ready for next DMA autoreinitialization.
	 */
	prepare_next_vb(pcdev);
}