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

📄 sh_mobile_ceu_camera.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * V4L2 Driver for SuperH Mobile CEU interface * * Copyright (C) 2008 Magnus Damm * * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", * * Copyright (C) 2006, Sascha Hauer, Pengutronix * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */#include <linux/init.h>#include <linux/module.h>#include <linux/io.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/moduleparam.h>#include <linux/time.h>#include <linux/version.h>#include <linux/device.h>#include <linux/platform_device.h>#include <linux/mutex.h>#include <linux/videodev2.h>#include <media/v4l2-common.h>#include <media/v4l2-dev.h>#include <media/soc_camera.h>#include <media/sh_mobile_ceu.h>#include <media/videobuf-dma-contig.h>/* register offsets for sh7722 / sh7723 */#define CAPSR  0x00 /* Capture start register */#define CAPCR  0x04 /* Capture control register */#define CAMCR  0x08 /* Capture interface control register */#define CMCYR  0x0c /* Capture interface cycle  register */#define CAMOR  0x10 /* Capture interface offset register */#define CAPWR  0x14 /* Capture interface width register */#define CAIFR  0x18 /* Capture interface input format register */#define CSTCR  0x20 /* Camera strobe control register (<= sh7722) */#define CSECR  0x24 /* Camera strobe emission count register (<= sh7722) */#define CRCNTR 0x28 /* CEU register control register */#define CRCMPR 0x2c /* CEU register forcible control register */#define CFLCR  0x30 /* Capture filter control register */#define CFSZR  0x34 /* Capture filter size clip register */#define CDWDR  0x38 /* Capture destination width register */#define CDAYR  0x3c /* Capture data address Y register */#define CDACR  0x40 /* Capture data address C register */#define CDBYR  0x44 /* Capture data bottom-field address Y register */#define CDBCR  0x48 /* Capture data bottom-field address C register */#define CBDSR  0x4c /* Capture bundle destination size register */#define CFWCR  0x5c /* Firewall operation control register */#define CLFCR  0x60 /* Capture low-pass filter control register */#define CDOCR  0x64 /* Capture data output control register */#define CDDCR  0x68 /* Capture data complexity level register */#define CDDAR  0x6c /* Capture data complexity level address register */#define CEIER  0x70 /* Capture event interrupt enable register */#define CETCR  0x74 /* Capture event flag clear register */#define CSTSR  0x7c /* Capture status register */#define CSRTR  0x80 /* Capture software reset register */#define CDSSR  0x84 /* Capture data size register */#define CDAYR2 0x90 /* Capture data address Y register 2 */#define CDACR2 0x94 /* Capture data address C register 2 */#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */static DEFINE_MUTEX(camera_lock);/* per video frame buffer */struct sh_mobile_ceu_buffer {	struct videobuf_buffer vb; /* v4l buffer must be first */	const struct soc_camera_data_format *fmt;};struct sh_mobile_ceu_dev {	struct device *dev;	struct soc_camera_host ici;	struct soc_camera_device *icd;	unsigned int irq;	void __iomem *base;	unsigned long video_limit;	/* lock used to protect videobuf */	spinlock_t lock;	struct list_head capture;	struct videobuf_buffer *active;	struct sh_mobile_ceu_info *pdata;};static void ceu_write(struct sh_mobile_ceu_dev *priv,		      unsigned long reg_offs, unsigned long data){	iowrite32(data, priv->base + reg_offs);}static unsigned long ceu_read(struct sh_mobile_ceu_dev *priv,			      unsigned long reg_offs){	return ioread32(priv->base + reg_offs);}/* *  Videobuf operations */static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,					unsigned int *count,					unsigned int *size){	struct soc_camera_device *icd = vq->priv_data;	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct sh_mobile_ceu_dev *pcdev = ici->priv;	int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;	*size = PAGE_ALIGN(icd->width * icd->height * bytes_per_pixel);	if (0 == *count)		*count = 2;	if (pcdev->video_limit) {		while (*size * *count > pcdev->video_limit)			(*count)--;	}	dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);	return 0;}static void free_buffer(struct videobuf_queue *vq,			struct sh_mobile_ceu_buffer *buf){	struct soc_camera_device *icd = vq->priv_data;	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,		&buf->vb, buf->vb.baddr, buf->vb.bsize);	if (in_interrupt())		BUG();	videobuf_dma_contig_free(vq, &buf->vb);	dev_dbg(&icd->dev, "%s freed\n", __func__);	buf->vb.state = VIDEOBUF_NEEDS_INIT;}static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev){	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~1);	ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & 0x0317f313);	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | 1);	ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~0x10000);	ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10);	if (pcdev->active) {		pcdev->active->state = VIDEOBUF_ACTIVE;		ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active));		ceu_write(pcdev, CAPSR, 0x1); /* start capture */	}}static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,					  struct videobuf_buffer *vb,					  enum v4l2_field field){	struct soc_camera_device *icd = vq->priv_data;	struct sh_mobile_ceu_buffer *buf;	int ret;	buf = container_of(vb, struct sh_mobile_ceu_buffer, vb);	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,		vb, vb->baddr, vb->bsize);	/* Added list head initialization on alloc */	WARN_ON(!list_empty(&vb->queue));#ifdef DEBUG	/* This can be useful if you want to see if we actually fill	 * the buffer with something */	memset((void *)vb->baddr, 0xaa, vb->bsize);#endif	BUG_ON(NULL == icd->current_fmt);	if (buf->fmt	!= icd->current_fmt ||	    vb->width	!= icd->width ||	    vb->height	!= icd->height ||	    vb->field	!= field) {		buf->fmt	= icd->current_fmt;		vb->width	= icd->width;		vb->height	= icd->height;		vb->field	= field;		vb->state	= VIDEOBUF_NEEDS_INIT;	}	vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3);	if (0 != vb->baddr && vb->bsize < vb->size) {		ret = -EINVAL;		goto out;	}	if (vb->state == VIDEOBUF_NEEDS_INIT) {		ret = videobuf_iolock(vq, vb, NULL);		if (ret)			goto fail;		vb->state = VIDEOBUF_PREPARED;	}	return 0;fail:	free_buffer(vq, buf);out:	return ret;}static void sh_mobile_ceu_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 sh_mobile_ceu_dev *pcdev = ici->priv;	unsigned long flags;	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,		vb, vb->baddr, vb->bsize);	vb->state = VIDEOBUF_QUEUED;	spin_lock_irqsave(&pcdev->lock, flags);	list_add_tail(&vb->queue, &pcdev->capture);	if (!pcdev->active) {		pcdev->active = vb;		sh_mobile_ceu_capture(pcdev);	}	spin_unlock_irqrestore(&pcdev->lock, flags);}static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,					   struct videobuf_buffer *vb){	free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb));}static struct videobuf_queue_ops sh_mobile_ceu_videobuf_ops = {	.buf_setup      = sh_mobile_ceu_videobuf_setup,	.buf_prepare    = sh_mobile_ceu_videobuf_prepare,	.buf_queue      = sh_mobile_ceu_videobuf_queue,	.buf_release    = sh_mobile_ceu_videobuf_release,};static irqreturn_t sh_mobile_ceu_irq(int irq, void *data){	struct sh_mobile_ceu_dev *pcdev = data;	struct videobuf_buffer *vb;	unsigned long flags;	spin_lock_irqsave(&pcdev->lock, flags);	vb = pcdev->active;	list_del_init(&vb->queue);	if (!list_empty(&pcdev->capture))		pcdev->active = list_entry(pcdev->capture.next,					   struct videobuf_buffer, queue);	else		pcdev->active = NULL;	sh_mobile_ceu_capture(pcdev);	vb->state = VIDEOBUF_DONE;	do_gettimeofday(&vb->ts);	vb->field_count++;	wake_up(&vb->done);	spin_unlock_irqrestore(&pcdev->lock, flags);	return IRQ_HANDLED;}static int sh_mobile_ceu_add_device(struct soc_camera_device *icd){	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct sh_mobile_ceu_dev *pcdev = ici->priv;	int ret = -EBUSY;	mutex_lock(&camera_lock);	if (pcdev->icd)		goto err;	dev_info(&icd->dev,		 "SuperH Mobile CEU driver attached to camera %d\n",		 icd->devnum);	ret = icd->ops->init(icd);	if (ret)		goto err;	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */	while (ceu_read(pcdev, CSTSR) & 1)		msleep(1);	pcdev->icd = icd;err:	mutex_unlock(&camera_lock);	return ret;}static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd){	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct sh_mobile_ceu_dev *pcdev = ici->priv;	unsigned long flags;	BUG_ON(icd != pcdev->icd);	/* disable capture, disable interrupts */	ceu_write(pcdev, CEIER, 0);	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */	/* make sure active buffer is canceled */	spin_lock_irqsave(&pcdev->lock, flags);	if (pcdev->active) {		list_del(&pcdev->active->queue);		pcdev->active->state = VIDEOBUF_ERROR;		wake_up_all(&pcdev->active->done);

⌨️ 快捷键说明

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