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

📄 omap24xxcam.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* stop any DMA transfers in progress */	omap24xxcam_dma_stop(cam, csr);	spin_lock_irqsave(&cam->sg_lock, irqflags);	if (cam->free_sgdma < NUM_SG_DMA) {		sgslot = (cam->next_sgdma + cam->free_sgdma) % NUM_SG_DMA;		sgdma = cam->sgdma + sgslot;		if (sgdma->next_sglist != 0) {			/* This DMA transfer was in progress, so abort it. */			dma_callback_t callback = sgdma->callback;			void *arg = sgdma->arg;			cam->free_sgdma++;			if (callback) {				/* leave interrupts masked */				spin_unlock(&cam->sg_lock);				(*callback)(cam, csr, arg);				spin_lock(&cam->sg_lock);			}		}	}	spin_unlock_irqrestore(&cam->sg_lock, irqflags);}/* This routine is not needed at the moment, but we'll keep it around just in  * case. */#if 0/* Stop the DMA controller, aborting any DMA transfers in progress.  Any queued  * scatter-gather DMA transactions are cancelled.  The DMA controller will be  * idle after this routine completes, and the scatter-gather DMA queue will  * be empty.  csr is the completion status passed to the completion routines  * for any DMA transfers that are aborted.  It should have at least one error  * bit set. */static voidomap24xxcam_sg_dma_stop(struct omap24xxcam_device *cam, unsigned long csr){	unsigned long irqflags;	int queued_sgdma, sgslot;	struct sgdma_state *sgdma;	dma_callback_t callback;	void *arg;	/* stop any DMA transfers in progress */	omap24xxcam_dma_stop(cam, csr);	spin_lock_irqsave(&cam->sg_lock, irqflags);	queued_sgdma = NUM_SG_DMA - cam->free_sgdma;	sgslot = (cam->next_sgdma + cam->free_sgdma) % NUM_SG_DMA;	while (queued_sgdma > 0) {		sgdma = cam->sgdma + sgslot;		callback = sgdma->callback;		arg = sgdma->arg;		cam->free_sgdma++;		sgdma->queued_sglist = 0;		if (callback) {			/* leave interrupts masked */			spin_unlock(&cam->sg_lock);			(*callback)(cam, csr, arg);			spin_lock(&cam->sg_lock);		}		queued_sgdma--;		sgslot = (sgslot + 1) % NUM_SG_DMA;	}	spin_unlock_irqrestore(&cam->sg_lock, irqflags);}#endif	/* if 0 *//* Register a routine to be called once immediately after a DMA transfer is  * started.  The purpose of this is to allow the camera interface to be  * started only after a DMA transaction has been queued in order to avoid  * DMA overruns.  The registered callback routine will only be called one  * time and then discarded.  Only one callback routine may be registered at a  * time. * Returns zero if successful, or a non-zero error code if a different callback  * routine has already been registered. */static intomap24xxcam_dma_notify(struct omap24xxcam_device *cam, 	void (*callback)(struct omap24xxcam_device *cam)){	unsigned long irqflags;	spin_lock_irqsave(&cam->dma_lock, irqflags);	if (cam->dma_notify && (cam->dma_notify != callback)) {		spin_unlock_irqrestore(&cam->dma_lock, irqflags);		return -EBUSY;	}	cam->dma_notify = callback;	spin_unlock_irqrestore(&cam->dma_lock, irqflags);	return 0;	}/* Camera DMA interrupt service routine. */static voidomap24xxcam_dma_isr(struct omap24xxcam_device *cam){	int dmach, i;	dma_callback_t callback;	void *arg;	unsigned long csr;	const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR 		| CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR 		| CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;	spin_lock(&cam->dma_lock);	if (cam->free_dmach == NUM_CAMDMA_CHANNELS) {		/* A camera DMA interrupt occurred while all channels are idle, 		 * so we'll acknowledge the interrupt in the IRQSTATUS register 		 * and exit.		 */#ifdef CONFIG_OMAP24XX_VIRTIO		printk("m");#endif		for ( i = 0; i< 4; ++i) {			csr = camdma_reg_in(cam, CAMDMA_CSR(i));			/* ack interrupt in CSR */			camdma_reg_out(cam, CAMDMA_CSR(i), csr);		}		camdma_reg_out(cam, CAMDMA_IRQSTATUS_L0, 0xffffffff);		spin_unlock(&cam->dma_lock);		return;	}	while (cam->free_dmach < NUM_CAMDMA_CHANNELS) {		//udelay(2);#ifdef CONFIG_OMAP24XX_VIRTIO		printk("k");#endif		dmach = (cam->next_dmach + cam->free_dmach) 			% NUM_CAMDMA_CHANNELS;		if (camdma_reg_in(cam, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE) {			/* This buffer hasn't finished yet, so we're done. */			break;		}		csr = camdma_reg_in(cam, CAMDMA_CSR(dmach));		/* ack interrupt in CSR */		camdma_reg_out(cam, CAMDMA_CSR(dmach), csr);		/* ack interrupt in IRQSTATUS */		camdma_reg_out(cam, CAMDMA_IRQSTATUS_L0, (1 << dmach));		if (csr & csr_error) {			/* A DMA error occurred, so stop all DMA transfers in 			 * progress.			 */			spin_unlock(&cam->dma_lock);			omap24xxcam_dma_stop(cam, csr);			return;		}		else {			callback = cam->camdma[dmach].callback;			arg = cam->camdma[dmach].arg;			cam->free_dmach++;			if (callback) {				spin_unlock(&cam->dma_lock);				(*callback)(cam, csr, arg);				spin_lock(&cam->dma_lock);			}		}	}	spin_unlock(&cam->dma_lock);	omap24xxcam_sg_dma_process(cam);}/* Shutdown the camera DMA driver and controller. */static voidomap24xxcam_dma_exit(struct omap24xxcam_device *cam){	int ch;	/* Mask all DMA interrupts */	camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);	/* disable all DMA channels */	for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++)		camdma_reg_out(cam, CAMDMA_CCR(ch), 0);}/* Initialize the camera DMA driver. */static voidomap24xxcam_dma_init(struct omap24xxcam_device *cam){	int ch, sg;	/* group all channels on DMA IRQ0 and unmask irq */	camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0xffffffff);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);	spin_lock_init(&cam->dma_lock);	cam->free_dmach = NUM_CAMDMA_CHANNELS;	cam->next_dmach = 0;	for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {		cam->camdma[ch].callback = NULL;		cam->camdma[ch].arg = NULL;	}	spin_lock_init(&cam->sg_lock);	cam->free_sgdma = NUM_SG_DMA;	cam->next_sgdma = 0;	for (sg = 0; sg < NUM_SG_DMA; sg++) {		cam->sgdma[sg].sglen = 0;		cam->sgdma[sg].next_sglist = 0;		cam->sgdma[sg].queued_sglist = 0;		cam->sgdma[sg].csr = 0;		cam->sgdma[sg].callback = NULL;		cam->sgdma[sg].arg = NULL;	}}/* -------------------------------------------------------------------------- *//* Callback routine for overlay DMA completion.  We just start another DMA  * transfer unless overlay has been turned off. */static voidomap24xxcam_overlay_callback(struct omap24xxcam_device *cam, unsigned long csr, 	void *arg){	int err;	unsigned long irqflags;	const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR 		| CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR 		| CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;	spin_lock_irqsave(&cam->overlay_lock, irqflags);		if (cam->overlay_cnt > 0)		--cam->overlay_cnt;	if (!cam->previewing || (csr & csr_error)) {		spin_unlock_irqrestore(&cam->overlay_lock, irqflags);		return;	}	sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;	sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;	while (cam->overlay_cnt < 2) {		err = omap24xxcam_sg_dma_queue(cam, &cam->overlay_sglist, 1, 			omap24xxcam_overlay_callback, NULL);		if (err)			break;		++cam->overlay_cnt;	}	spin_unlock_irqrestore(&cam->overlay_lock, irqflags);}/* Begin DMA'ing into the camera overlay framebuffer.  We queue up two DMA  * transfers so that all frames will be captured. */static voidomap24xxcam_start_overlay_dma(struct omap24xxcam_device *cam){	int err;	unsigned long irqflags;	if (!cam->previewing)		return;	if (cam->pix.sizeimage > cam->overlay_size)		return;	spin_lock_irqsave(&cam->overlay_lock, irqflags);	sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;	sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;	while (cam->overlay_cnt < 2) {		err = omap24xxcam_sg_dma_queue(cam, &cam->overlay_sglist, 1, 			omap24xxcam_overlay_callback, NULL);		if (err)			break;		++cam->overlay_cnt;	}	spin_unlock_irqrestore(&cam->overlay_lock, irqflags);}/* Enable the camera core interface. */static voidomap24xxcam_cc_enable(struct omap24xxcam_device *cam){	/* Get the CC_CTRL register value for the current capture format. */	omap24xxcam_sensor_cc_ctrl(cam);	/* program the camera interface DMA packet size */	cc_reg_out(cam, CC_CTRL_DMA, 		CC_CTRL_DMA_EN | (DMA_THRESHOLD/4 - 1));	/* enable camera core error interrupts */	cc_reg_out(cam, CC_IRQENABLE, CC_IRQENABLE_FW_ERR_IRQ 		| CC_IRQENABLE_FSC_ERR_IRQ | CC_IRQENABLE_SSC_ERR_IRQ 		| CC_IRQENABLE_FIFO_OF_IRQ);	/* enable the camera interface */	cc_reg_out(cam, CC_CTRL, cam->cc_ctrl | CC_CTRL_CC_EN);}/* Error recovery for DMA errors and camera interface errors. */static voidomap24xxcam_error_handler(struct omap24xxcam_device *cam){	/* Get the CC_CTRL register value for the current capture format. */	omap24xxcam_sensor_cc_ctrl(cam);	/* Disable and reset the camera interface. */	cc_reg_out(cam, CC_CTRL, 		cam->cc_ctrl & ~(CC_CTRL_CC_EN | CC_CTRL_CC_FRAME_TRIG));	cc_reg_out(cam, CC_CTRL, (cam->cc_ctrl | CC_CTRL_CC_RST) 		& ~(CC_CTRL_CC_EN | CC_CTRL_CC_FRAME_TRIG));	/* Stop the DMA controller and frame sync scatter-gather DMA. */	omap24xxcam_sg_dma_sync(cam, CAMDMA_CSR_TRANS_ERR);#if 1	/* Reset and re-initialize the entire camera subsystem.	 * Resetting the camera FIFO via the CC_RST bit in the CC_CTRL 	 * register is supposed to be sufficient to recover from a 	 * camera interface error, but it doesn't seem to be enough.  If 	 * we only do that then subsequent image captures are out of sync 	 * by either one or two times DMA_THRESHOLD bytes.  Resetting and 	 * re-initializing the entire camera subsystem prevents the problem 	 * with frame synchronization.  Calling cam_init() from an ISR is	 * undesirable since it waits an indeterminate amount of time for the 	 * camera subsystem reset to complete.  If we ever figure out exactly 	 * what needs to be reset to recover from a camera interface error, 	 * maybe we can replace this global reset with something less drastic.	 */	cam_init(cam);	omap24xxcam_set_xclk(cam);	/* group all channels on DMA IRQ0 and unmask irq */	camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0xffffffff);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);	camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);#endif	if (cam->previewing || cam->streaming) {		/* Preview or capture is in progress, so we need to register 		 * our routine to restart the camera interface the next time a 		 * DMA transfer is queued.		 */		omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);	}	/* Restart overlay DMA if preview is enabled. */	omap24xxcam_start_overlay_dma(cam);	/* Restart the scatter-gather DMA queue. */	omap24xxcam_sg_dma_process(cam);}/* Interrupt service routine for camera core interrupts. */static voidomap24xxcam_cc_isr(struct omap24xxcam_device *cam){	unsigned long cc_irqstatus;	const unsigned long cc_irqstatus_err = CC_IRQSTATUS_FW_ERR_IRQ 		| CC_IRQSTATUS_FSC_ERR_IRQ | CC_IRQSTATUS_SSC_ERR_IRQ		| CC_IRQSTATUS_FIFO_OF_IRQ;	cc_irqstatus = cc_reg_in(cam, CC_IRQSTATUS);	cc_reg_out(cam, CC_IRQSTATUS, cc_irqstatus);		if (cc_irqstatus & cc_irqstatus_err)		omap24xxcam_error_handler(cam);}static irqreturn_tomap24xxcam_isr(int irq, void *arg, struct pt_regs *regs){	struct omap24xxcam_device *cam = (struct omap24xxcam_device *) arg;	unsigned long irqstatus;	unsigned int irqhandled = 0;	irqstatus = cam_reg_in(cam, CAM_IRQSTATUS);	if (irqstatus & 		(CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1 		| CAM_IRQSTATUS_DMA_IRQ0))	{		omap24xxcam_dma_isr(cam);		irqhandled = 1;	}	if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {		omap24xxcam_cc_isr(cam);		irqhandled = 1;	}	if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)		printk(KERN_ERR CAM_NAME ": Unhandled camera MMU interrupt!\n");	return IRQ_RETVAL(irqhandled);}static voidomap24xxcam_adjust_xclk(struct omap24xxcam_device *cam){	unsigned long divisor;	if (cam->xclk > cam->mclk)		cam->xclk = cam->mclk;	divisor = cam->mclk/cam->xclk;	if (cam->xclk*divisor < cam->mclk)		divisor += 1;	if (divisor > 30)		divisor = 30;		cam->xclk = cam->mclk/divisor;}/* -------------------------------------------------------------------------- *//* This routine is called from interrupt context when a scatter-gather DMA  * transfer of a videobuf_buffer completes. */static voidomap24xxcam_vbq_complete(struct omap24xxcam_device *cam, unsigned long csr, 	void *arg){	struct videobuf_buffer *vb = (struct videobuf_buffer *) arg;	const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR 		| CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR 		| CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;	spin_lock(&cam->vbq_lock);	do_gettimeofday(&vb->ts);	vb->field_count = cam->field_count;	cam->field_count += 2;	if (csr & csr_error) {		vb->state = STATE_ERROR;		omap24xxcam_error_handler(cam);	}

⌨️ 快捷键说明

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