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

📄 sh_mobile_ceu_camera.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		pcdev->active = NULL;	}	spin_unlock_irqrestore(&pcdev->lock, flags);	icd->ops->release(icd);	dev_info(&icd->dev,		 "SuperH Mobile CEU driver detached from camera %d\n",		 icd->devnum);	pcdev->icd = NULL;}static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,				       __u32 pixfmt){	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct sh_mobile_ceu_dev *pcdev = ici->priv;	int ret, buswidth, width, cfszr_width, cdwdr_width;	unsigned long camera_flags, common_flags, value;	camera_flags = icd->ops->query_bus_param(icd);	common_flags = soc_camera_bus_param_compatible(camera_flags,						       pcdev->pdata->flags);	if (!common_flags)		return -EINVAL;	ret = icd->ops->set_bus_param(icd, common_flags);	if (ret < 0)		return ret;	switch (common_flags & SOCAM_DATAWIDTH_MASK) {	case SOCAM_DATAWIDTH_8:		buswidth = 8;		break;	case SOCAM_DATAWIDTH_16:		buswidth = 16;		break;	default:		return -EINVAL;	}	ceu_write(pcdev, CRCNTR, 0);	ceu_write(pcdev, CRCMPR, 0);	value = 0x00000010;	value |= (common_flags & SOCAM_VSYNC_ACTIVE_LOW) ? (1 << 1) : 0;	value |= (common_flags & SOCAM_HSYNC_ACTIVE_LOW) ? (1 << 0) : 0;	value |= (buswidth == 16) ? (1 << 12) : 0;	ceu_write(pcdev, CAMCR, value);	ceu_write(pcdev, CAPCR, 0x00300000);	ceu_write(pcdev, CAIFR, 0);	mdelay(1);	width = icd->width * (icd->current_fmt->depth / 8);	width = (buswidth == 16) ? width / 2 : width;	cfszr_width = (buswidth == 8) ? width / 2 : width;	cdwdr_width = (buswidth == 16) ? width * 2 : width;	ceu_write(pcdev, CAMOR, 0);	ceu_write(pcdev, CAPWR, (icd->height << 16) | width);	ceu_write(pcdev, CFLCR, 0); /* data fetch mode - no scaling */	ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width);	ceu_write(pcdev, CLFCR, 0); /* data fetch mode - no lowpass filter */	/* A few words about byte order (observed in Big Endian mode)	 *	 * In data fetch mode bytes are received in chunks of 8 bytes.	 * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first)	 *	 * The data is however by default written to memory in reverse order:	 * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte)	 *	 * The lowest three bits of CDOCR allows us to do swapping,	 * using 7 we swap the data bytes to match the incoming order:	 * D0, D1, D2, D3, D4, D5, D6, D7	 */	ceu_write(pcdev, CDOCR, 0x00000017);	ceu_write(pcdev, CDWDR, cdwdr_width);	ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */	/* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */	/* in data fetch mode: no need for CDACR, CDBYR, CDBCR */	return 0;}static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,				       __u32 pixfmt){	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct sh_mobile_ceu_dev *pcdev = ici->priv;	unsigned long camera_flags, common_flags;	camera_flags = icd->ops->query_bus_param(icd);	common_flags = soc_camera_bus_param_compatible(camera_flags,						       pcdev->pdata->flags);	if (!common_flags)		return -EINVAL;	return 0;}static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd,				     __u32 pixfmt, struct v4l2_rect *rect){	return icd->ops->set_fmt_cap(icd, pixfmt, rect);}static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,				     struct v4l2_format *f){	/* FIXME: calculate using depth and bus width */	if (f->fmt.pix.height < 4)		f->fmt.pix.height = 4;	if (f->fmt.pix.height > 1920)		f->fmt.pix.height = 1920;	if (f->fmt.pix.width < 2)		f->fmt.pix.width = 2;	if (f->fmt.pix.width > 2560)		f->fmt.pix.width = 2560;	f->fmt.pix.width &= ~0x01;	f->fmt.pix.height &= ~0x03;	/* limit to sensor capabilities */	return icd->ops->try_fmt_cap(icd, f);}static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,				 struct v4l2_requestbuffers *p){	int i;	/* This is for locking debugging only. I removed spinlocks and now I	 * check whether .prepare is ever called on a linked buffer, or whether	 * a dma IRQ can occur for an in-work or unlinked buffer. Until now	 * it hadn't triggered */	for (i = 0; i < p->count; i++) {		struct sh_mobile_ceu_buffer *buf;		buf = container_of(icf->vb_vidq.bufs[i],				   struct sh_mobile_ceu_buffer, vb);		INIT_LIST_HEAD(&buf->vb.queue);	}	return 0;}static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt){	struct soc_camera_file *icf = file->private_data;	struct sh_mobile_ceu_buffer *buf;	buf = list_entry(icf->vb_vidq.stream.next,			 struct sh_mobile_ceu_buffer, vb.stream);	poll_wait(file, &buf->vb.done, pt);	if (buf->vb.state == VIDEOBUF_DONE ||	    buf->vb.state == VIDEOBUF_ERROR)		return POLLIN|POLLRDNORM;	return 0;}static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,				  struct v4l2_capability *cap){	strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card));	cap->version = KERNEL_VERSION(0, 0, 5);	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;	return 0;}static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,					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;	videobuf_queue_dma_contig_init(q,				       &sh_mobile_ceu_videobuf_ops,				       &ici->dev, &pcdev->lock,				       V4L2_BUF_TYPE_VIDEO_CAPTURE,				       V4L2_FIELD_NONE,				       sizeof(struct sh_mobile_ceu_buffer),				       icd);}static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {	.owner		= THIS_MODULE,	.add		= sh_mobile_ceu_add_device,	.remove		= sh_mobile_ceu_remove_device,	.set_fmt_cap	= sh_mobile_ceu_set_fmt_cap,	.try_fmt_cap	= sh_mobile_ceu_try_fmt_cap,	.reqbufs	= sh_mobile_ceu_reqbufs,	.poll		= sh_mobile_ceu_poll,	.querycap	= sh_mobile_ceu_querycap,	.try_bus_param	= sh_mobile_ceu_try_bus_param,	.set_bus_param	= sh_mobile_ceu_set_bus_param,	.init_videobuf	= sh_mobile_ceu_init_videobuf,};static int sh_mobile_ceu_probe(struct platform_device *pdev){	struct sh_mobile_ceu_dev *pcdev;	struct resource *res;	void __iomem *base;	unsigned int irq;	int err = 0;	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	irq = platform_get_irq(pdev, 0);	if (!res || !irq) {		dev_err(&pdev->dev, "Not enough CEU platform resources.\n");		err = -ENODEV;		goto exit;	}	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);	if (!pcdev) {		dev_err(&pdev->dev, "Could not allocate pcdev\n");		err = -ENOMEM;		goto exit;	}	platform_set_drvdata(pdev, pcdev);	INIT_LIST_HEAD(&pcdev->capture);	spin_lock_init(&pcdev->lock);	pcdev->pdata = pdev->dev.platform_data;	if (!pcdev->pdata) {		err = -EINVAL;		dev_err(&pdev->dev, "CEU platform data not set.\n");		goto exit_kfree;	}	base = ioremap_nocache(res->start, res->end - res->start + 1);	if (!base) {		err = -ENXIO;		dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n");		goto exit_kfree;	}	pcdev->irq = irq;	pcdev->base = base;	pcdev->video_limit = 0; /* only enabled if second resource exists */	pcdev->dev = &pdev->dev;	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);	if (res) {		err = dma_declare_coherent_memory(&pdev->dev, res->start,						  res->start,						  (res->end - res->start) + 1,						  DMA_MEMORY_MAP |						  DMA_MEMORY_EXCLUSIVE);		if (!err) {			dev_err(&pdev->dev, "Unable to declare CEU memory.\n");			err = -ENXIO;			goto exit_iounmap;		}		pcdev->video_limit = (res->end - res->start) + 1;	}	/* request irq */	err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED,			  pdev->dev.bus_id, pcdev);	if (err) {		dev_err(&pdev->dev, "Unable to register CEU interrupt.\n");		goto exit_release_mem;	}	pcdev->ici.priv = pcdev;	pcdev->ici.dev.parent = &pdev->dev;	pcdev->ici.nr = pdev->id;	pcdev->ici.drv_name = pdev->dev.bus_id,	pcdev->ici.ops = &sh_mobile_ceu_host_ops,	err = soc_camera_host_register(&pcdev->ici);	if (err)		goto exit_free_irq;	return 0;exit_free_irq:	free_irq(pcdev->irq, pcdev);exit_release_mem:	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))		dma_release_declared_memory(&pdev->dev);exit_iounmap:	iounmap(base);exit_kfree:	kfree(pcdev);exit:	return err;}static int sh_mobile_ceu_remove(struct platform_device *pdev){	struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev);	soc_camera_host_unregister(&pcdev->ici);	free_irq(pcdev->irq, pcdev);	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))		dma_release_declared_memory(&pdev->dev);	iounmap(pcdev->base);	kfree(pcdev);	return 0;}static struct platform_driver sh_mobile_ceu_driver = {	.driver 	= {		.name	= "sh_mobile_ceu",	},	.probe		= sh_mobile_ceu_probe,	.remove		= sh_mobile_ceu_remove,};static int __init sh_mobile_ceu_init(void){	return platform_driver_register(&sh_mobile_ceu_driver);}static void __exit sh_mobile_ceu_exit(void){	platform_driver_unregister(&sh_mobile_ceu_driver);}module_init(sh_mobile_ceu_init);module_exit(sh_mobile_ceu_exit);MODULE_DESCRIPTION("SuperH Mobile CEU driver");MODULE_AUTHOR("Magnus Damm");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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