示例#1
0
/*
 * The following two functions absolutely depend on the fact, that
 * there can be only one camera on OMAP1 camera sensor interface
 */
static int omap1_cam_add_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;

	if (pcdev->icd)
		return -EBUSY;

	clk_enable(pcdev->clk);

	/* setup sensor clock */
	ctrlclock = CAM_READ(pcdev, CTRLCLOCK);
	ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN);
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);

	ctrlclock &= ~FOSCMOD_MASK;
	switch (pcdev->camexclk) {
	case 6000000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz;
		break;
	case 8000000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN;
		break;
	case 9600000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN;
		break;
	case 12000000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz;
		break;
	case 24000000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN;
	default:
		break;
	}
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN);

	/* enable internal clock */
	ctrlclock |= MCLK_EN;
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);

	sensor_reset(pcdev, false);

	pcdev->icd = icd;

	dev_dbg(icd->dev.parent, "OMAP1 Camera driver attached to camera %d\n",
			icd->devnum);
	return 0;
}
示例#2
0
/*
 * The following two functions absolutely depend on the fact, that
 * there can be only one camera on OMAP1 camera sensor interface
 */
static int omap1_cam_clock_start(struct soc_camera_host *ici)
{
	struct omap1_cam_dev *pcdev = ici->priv;
	u32 ctrlclock;

	clk_enable(pcdev->clk);

	/* setup sensor clock */
	ctrlclock = CAM_READ(pcdev, CTRLCLOCK);
	ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN);
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);

	ctrlclock &= ~FOSCMOD_MASK;
	switch (pcdev->camexclk) {
	case 6000000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz;
		break;
	case 8000000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN;
		break;
	case 9600000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN;
		break;
	case 12000000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz;
		break;
	case 24000000:
		ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN;
	default:
		break;
	}
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN);

	/* enable internal clock */
	ctrlclock |= MCLK_EN;
	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);

	sensor_reset(pcdev, false);

	return 0;
}
示例#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 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;
}
示例#5
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;
}