⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pxa_camera.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
			   the currently running chain */			pcdev->sg_tail[i]->ddadr = buf_dma->sg_dma;			pcdev->sg_tail[i] = buf_dma->sg_cpu + buf_dma->sglen - 1;			/* Setup a dummy descriptor with the DMA engines current			 * state			 */			buf_dma->sg_cpu[nents].dsadr =				pcdev->res->start + 0x28 + i*8; /* CIBRx */			buf_dma->sg_cpu[nents].dtadr =				DTADR(pcdev->dma_chans[i]);			buf_dma->sg_cpu[nents].dcmd =				DCMD(pcdev->dma_chans[i]);			if (DDADR(pcdev->dma_chans[i]) == DDADR_STOP) {				/* The DMA engine is on the last				   descriptor, set the next descriptors				   address to the descriptors we just				   initialized */				buf_dma->sg_cpu[nents].ddadr = buf_dma->sg_dma;			} else {				buf_dma->sg_cpu[nents].ddadr =					DDADR(pcdev->dma_chans[i]);			}			/* The next descriptor is the dummy descriptor */			DDADR(pcdev->dma_chans[i]) = buf_dma->sg_dma + nents *				sizeof(struct pxa_dma_desc);			DCSR(pcdev->dma_chans[i]) = DCSR_RUN;		}	}	spin_unlock_irqrestore(&pcdev->lock, flags);}static void pxa_videobuf_release(struct videobuf_queue *vq,				 struct videobuf_buffer *vb){	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);#ifdef DEBUG	struct soc_camera_device *icd = vq->priv_data;	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,		vb, vb->baddr, vb->bsize);	switch (vb->state) {	case VIDEOBUF_ACTIVE:		dev_dbg(&icd->dev, "%s (active)\n", __func__);		break;	case VIDEOBUF_QUEUED:		dev_dbg(&icd->dev, "%s (queued)\n", __func__);		break;	case VIDEOBUF_PREPARED:		dev_dbg(&icd->dev, "%s (prepared)\n", __func__);		break;	default:		dev_dbg(&icd->dev, "%s (unknown)\n", __func__);		break;	}#endif	free_buffer(vq, buf);}static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,			      struct videobuf_buffer *vb,			      struct pxa_buffer *buf){	/* _init is used to debug races, see comment in pxa_camera_reqbufs() */	list_del_init(&vb->queue);	vb->state = VIDEOBUF_DONE;	do_gettimeofday(&vb->ts);	vb->field_count++;	wake_up(&vb->done);	if (list_empty(&pcdev->capture)) {		pcdev->active = NULL;		DCSR(pcdev->dma_chans[0]) = 0;		DCSR(pcdev->dma_chans[1]) = 0;		DCSR(pcdev->dma_chans[2]) = 0;		CICR0 &= ~CICR0_ENB;		return;	}	pcdev->active = list_entry(pcdev->capture.next,				   struct pxa_buffer, vb.queue);}static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,			       enum pxa_camera_active_dma act_dma){	struct pxa_buffer *buf;	unsigned long flags;	u32 status, camera_status, overrun;	struct videobuf_buffer *vb;	spin_lock_irqsave(&pcdev->lock, flags);	status = DCSR(channel);	DCSR(channel) = status | DCSR_ENDINTR;	if (status & DCSR_BUSERR) {		dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");		goto out;	}	if (!(status & DCSR_ENDINTR)) {		dev_err(pcdev->dev, "Unknown DMA IRQ source, "			"status: 0x%08x\n", status);		goto out;	}	if (!pcdev->active) {		dev_err(pcdev->dev, "DMA End IRQ with no active buffer!\n");		goto out;	}	camera_status = CISR;	overrun = CISR_IFO_0;	if (pcdev->channels == 3)		overrun |= CISR_IFO_1 | CISR_IFO_2;	if (camera_status & overrun) {		dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);		/* Stop the Capture Interface */		CICR0 &= ~CICR0_ENB;		/* Stop DMA */		DCSR(channel) = 0;		/* Reset the FIFOs */		CIFR |= CIFR_RESET_F;		/* Enable End-Of-Frame Interrupt */		CICR0 &= ~CICR0_EOFM;		/* Restart the Capture Interface */		CICR0 |= CICR0_ENB;		goto out;	}	vb = &pcdev->active->vb;	buf = container_of(vb, struct pxa_buffer, vb);	WARN_ON(buf->inwork || list_empty(&vb->queue));	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,		vb, vb->baddr, vb->bsize);	buf->active_dma &= ~act_dma;	if (!buf->active_dma)		pxa_camera_wakeup(pcdev, vb, buf);out:	spin_unlock_irqrestore(&pcdev->lock, flags);}static void pxa_camera_dma_irq_y(int channel, void *data){	struct pxa_camera_dev *pcdev = data;	pxa_camera_dma_irq(channel, pcdev, DMA_Y);}static void pxa_camera_dma_irq_u(int channel, void *data){	struct pxa_camera_dev *pcdev = data;	pxa_camera_dma_irq(channel, pcdev, DMA_U);}static void pxa_camera_dma_irq_v(int channel, void *data){	struct pxa_camera_dev *pcdev = data;	pxa_camera_dma_irq(channel, pcdev, DMA_V);}static struct videobuf_queue_ops pxa_videobuf_ops = {	.buf_setup      = pxa_videobuf_setup,	.buf_prepare    = pxa_videobuf_prepare,	.buf_queue      = pxa_videobuf_queue,	.buf_release    = pxa_videobuf_release,};static void pxa_camera_init_videobuf(struct videobuf_queue *q,			      struct soc_camera_device *icd){	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct pxa_camera_dev *pcdev = ici->priv;	/* We must pass NULL as dev pointer, then all pci_* dma operations	 * transform to normal dma_* ones. */	videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock,				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,				sizeof(struct pxa_buffer), icd);}static int mclk_get_divisor(struct pxa_camera_dev *pcdev){	unsigned int mclk_10khz = pcdev->platform_mclk_10khz;	unsigned long div;	unsigned long lcdclk;	lcdclk = clk_get_rate(pcdev->clk) / 10000;	/* We verify platform_mclk_10khz != 0, so if anyone breaks it, here	 * they get a nice Oops */	div = (lcdclk + 2 * mclk_10khz - 1) / (2 * mclk_10khz) - 1;	dev_dbg(pcdev->dev, "LCD clock %lukHz, target freq %dkHz, "		"divisor %lu\n", lcdclk * 10, mclk_10khz * 10, div);	return div;}static void pxa_camera_activate(struct pxa_camera_dev *pcdev){	struct pxacamera_platform_data *pdata = pcdev->pdata;	u32 cicr4 = 0;	dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n",		pcdev, pdata);	if (pdata && pdata->init) {		dev_dbg(pcdev->dev, "%s: Init gpios\n", __func__);		pdata->init(pcdev->dev);	}	CICR0 = 0x3FF;   /* disable all interrupts */	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)		cicr4 |= CICR4_PCLK_EN;	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)		cicr4 |= CICR4_MCLK_EN;	if (pcdev->platform_flags & PXA_CAMERA_PCP)		cicr4 |= CICR4_PCP;	if (pcdev->platform_flags & PXA_CAMERA_HSP)		cicr4 |= CICR4_HSP;	if (pcdev->platform_flags & PXA_CAMERA_VSP)		cicr4 |= CICR4_VSP;	CICR4 = mclk_get_divisor(pcdev) | cicr4;	clk_enable(pcdev->clk);}static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev){	clk_disable(pcdev->clk);}static irqreturn_t pxa_camera_irq(int irq, void *data){	struct pxa_camera_dev *pcdev = data;	unsigned int status = CISR;	dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);	if (!status)		return IRQ_NONE;	CISR = status;	if (status & CISR_EOF) {		int i;		for (i = 0; i < pcdev->channels; i++) {			DDADR(pcdev->dma_chans[i]) =				pcdev->active->dmas[i].sg_dma;			DCSR(pcdev->dma_chans[i]) = DCSR_RUN;		}		CICR0 |= CICR0_EOFM;	}	return IRQ_HANDLED;}/* The following two functions absolutely depend on the fact, that * there can be only one camera on PXA quick capture interface */static int pxa_camera_add_device(struct soc_camera_device *icd){	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct pxa_camera_dev *pcdev = ici->priv;	int ret;	mutex_lock(&camera_lock);	if (pcdev->icd) {		ret = -EBUSY;		goto ebusy;	}	dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",		 icd->devnum);	pxa_camera_activate(pcdev);	ret = icd->ops->init(icd);	if (!ret)		pcdev->icd = icd;ebusy:	mutex_unlock(&camera_lock);	return ret;}static void pxa_camera_remove_device(struct soc_camera_device *icd){	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct pxa_camera_dev *pcdev = ici->priv;	BUG_ON(icd != pcdev->icd);	dev_info(&icd->dev, "PXA Camera driver detached from camera %d\n",		 icd->devnum);	/* disable capture, disable interrupts */	CICR0 = 0x3ff;	/* Stop DMA engine */	DCSR(pcdev->dma_chans[0]) = 0;	DCSR(pcdev->dma_chans[1]) = 0;	DCSR(pcdev->dma_chans[2]) = 0;	icd->ops->release(icd);	pxa_camera_deactivate(pcdev);	pcdev->icd = NULL;}static int test_platform_param(struct pxa_camera_dev *pcdev,			       unsigned char buswidth, unsigned long *flags){	/*	 * Platform specified synchronization and pixel clock polarities are	 * only a recommendation and are only used during probing. The PXA270	 * quick capture interface supports both.	 */	*flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?		  SOCAM_MASTER : SOCAM_SLAVE) |		SOCAM_HSYNC_ACTIVE_HIGH |		SOCAM_HSYNC_ACTIVE_LOW |		SOCAM_VSYNC_ACTIVE_HIGH |		SOCAM_VSYNC_ACTIVE_LOW |		SOCAM_PCLK_SAMPLE_RISING |		SOCAM_PCLK_SAMPLE_FALLING;	/* If requested data width is supported by the platform, use it */	switch (buswidth) {	case 10:		if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10))			return -EINVAL;		*flags |= SOCAM_DATAWIDTH_10;		break;	case 9:		if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9))			return -EINVAL;		*flags |= SOCAM_DATAWIDTH_9;		break;	case 8:		if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))			return -EINVAL;		*flags |= SOCAM_DATAWIDTH_8;	}	return 0;}static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt){	struct soc_camera_host *ici =		to_soc_camera_host(icd->dev.parent);	struct pxa_camera_dev *pcdev = ici->priv;	unsigned long dw, bpp, bus_flags, camera_flags, common_flags;	u32 cicr0, cicr1, cicr4 = 0;	int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);	if (ret < 0)		return ret;	camera_flags = icd->ops->query_bus_param(icd);	common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);	if (!common_flags)		return -EINVAL;	pcdev->channels = 1;	/* Make choises, based on platform preferences */	if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&	    (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {		if (pcdev->platform_flags & PXA_CAMERA_HSP)			common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;		else			common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;	}	if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&	    (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {		if (pcdev->platform_flags & PXA_CAMERA_VSP)			common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;		else			common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;	}	if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&	    (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {		if (pcdev->platform_flags & PXA_CAMERA_PCP)			common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;		else			common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;	}	ret = icd->ops->set_bus_param(icd, common_flags);	if (ret < 0)		return ret;	/* Datawidth is now guaranteed to be equal to one of the three values.	 * We fix bit-per-pixel equal to data-width... */	switch (common_flags & SOCAM_DATAWIDTH_MASK) {	case SOCAM_DATAWIDTH_10:		icd->buswidth = 10;		dw = 4;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -