ARM: OMAP2: Camera: Add OMAP2 24xx camera driver.
Hi, Sakari!
Please find some comments interleaved below.
Quoted 800 lines · you
FYI
---------- Forwarded message ----------
From: Sakari Ailus <[email protected]>
Date: Feb 28, 2007 11:59 AM
Subject: [PATCH] ARM: OMAP2: Camera: Add OMAP2 24xx camera driver.
To: [email protected]This is a modified version of the camera driver originally from Montavista.
Signed-off-by Sakari Ailus <[email protected]>---
drivers/media/video/omap/Makefile | 1 + drivers/media/video/omap/omap24xxcam-core.c | 202 ++++ drivers/media/video/omap/omap24xxcam-dma.c | 320 +++++++ drivers/media/video/omap/omap24xxcam-dma.h | 65 ++ drivers/media/video/omap/omap24xxcam-dmahw.c | 224 +++++ drivers/media/video/omap/omap24xxcam-sensor.c | 226 +++++ drivers/media/video/omap/omap24xxcam-sgdma.c | 298 ++++++ drivers/media/video/omap/omap24xxcam-vbq.c | 370 ++++++++ drivers/media/video/omap/omap24xxcam.c | 1216 +++++++++++++++++++++++++ drivers/media/video/omap/omap24xxcam.h | 659 +++++++++++++ 10 files changed, 3581 insertions(+), 0 deletions(-)create mode 100644
drivers/media/video/omap/omap24xxcam-core.ccreate mode 100644drivers/media/video/omap/omap24xxcam-dma.ccreate mode 100644drivers/media/video/omap/omap24xxcam-dma.hcreate mode 100644drivers/media/video/omap/omap24xxcam-dmahw.ccreate mode 100644drivers/media/video/omap/omap24xxcam-sensor.ccreate mode 100644drivers/media/video/omap/omap24xxcam-sgdma.ccreate mode 100644drivers/media/video/omap/omap24xxcam-vbq.ccreate mode 100644drivers/media/video/omap/omap24xxcam.ccreate mode 100644drivers/media/video/omap/omap24xxcam.hdrivers/media/video/omap/Makefile +0
-0@@ -4,6 +4,7 @@ obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.oobj-$(CONFIG_VIDEO_CAMERA_SENSOR_OV9640) += sensor_ov9640.o
objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o camera_core.o +objs-y$(CONFIG_ARCH_OMAP24XX) += omap24xxcam.o omap24xxcam-sgdma.o omap24xxcam-dma.o omap24xxcam-dmahw.o omap24xxcam-core.o omap24xxcam-sensor.o omap24xxcam-vbq.o objs-y$(CONFIG_MACH_OMAP_H3) += h3_sensor_power.o objs-y$(CONFIG_MACH_OMAP_H4) += h4_sensor_power.o
(quoted diff) +0
-0
core.c
new file mode 100644
index 0000000..1e30768drivers/media/video/omap/omap24xxcam-core.c new file +52
-0@@ -0,0 +1,202 @@ +/* +* OMAP 24xx camera high-level DMA (not hardware) and scatter-gather +* DMA handling +* +* Author: Andy Lowe ([email protected]) +* +* Copyright (C) 2004 MontaVista Software, Inc. +* Copyright (C) 2004 Texas Instruments. +* Copyright (C) 2007 Nokia Corporation. +* +* Contact: Sakari Ailus <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA +*/ + +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/videodev.h> +#include <linux/pci.h> /* needed for videobufs */ +#include <media/video-buf.h> +#include <linux/dma-mapping.h> +#include <linux/input.h> +#include <linux/version.h> + +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/scatterlist.h> +#include <asm/irq.h> +#include <asm/semaphore.h> + +#include "omap24xxcam.h" + +/* Program the camera interface xclk for the frequency cam->img.xclk based on
+ * the functional clock frequencycam->img.mclk. If the specifed cam-> img.xclk
+ * frequency is not possible based on the value ofcam->img.mclk, then the
+ * closest xclk frequency lower than the specified xclk will be selected.
+ * The actual xclk frequency is returned incam->img.xclk. If cam-> img.xclk is zero,
+ * then xclk is turned off (stable low value).
+ */drivers/media/video/omap/omap24xxcam-core.c new file +13
-0+ +void omap24xxcam_core_init (struct omap24xxcam_core *core, +unsigned long base) +{ +DBG ; + + core->base = base; + +/* Setting the camera core AUTOIDLE bit causes problems with frame +* synchronization, so we will clear the AUTOIDLE bit instead. +*/ +//omap24xxcam_reg_out(cam, CC_SYSCONFIG, 0); + omap24xxcam_reg_out(core->base, CC_SYSCONFIG,
CC_SYSCONFIG_AUTOIDLE);drivers/media/video/omap/omap24xxcam-core.c new file +69
-0+ + core->xclk_enabled =0 ; +} + +void omap24xxcam_core_exit (const struct omap24xxcam_core *core) +{ +} + +/* Enable the camera core interface. */ +void omap24xxcam_core_enable (struct omap24xxcam_core *core) +{ +DBG ; + +/* program the camera interface DMA packet size */ +omap24xxcam_reg_out (core->base,CC_CTRL_DMA , +CC_CTRL_DMA_EN | (DMA_THRESHOLD /4 -1 )); + +/* enable camera core error interrupts */ +omap24xxcam_reg_out (core->base,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 */ +omap24xxcam_reg_out (core->base,CC_CTRL , +CC_CTRL_NOBT_SYNCHRO + |CC_CTRL_PAR_MODE_NOBT8 + |CC_CTRL_CC_EN ); + +if (core->xclk_enabled) +omap24xxcam_core_xclk_enable (core); +} + +void omap24xxcam_core_disable (struct omap24xxcam_core *core) +{ +omap24xxcam_reg_out (core->base,CC_CTRL ,0 ); +omap24xxcam_reg_out (core->base,CC_CTRL ,CC_CTRL_CC_RST ); +} + +void omap24xxcam_core_enable_callback (struct omap24xxcam_device *cam) +{ +omap24xxcam_core_enable (&cam->core); +} +/* reset core fifo and dma */ +/* void omap24xxcam_core_reset(struct omap24xxcam_device *cam) */ +/* { */ +/* omap24xxcam_reg_out(cam, CC_CTRL, CC_CTRL_CC_RST); */ +/* } */ + +/* Interrupt service routine for camera core interrupts. */ +void omap24xxcam_core_isr (struct omap24xxcam_core *core) +{ +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_UF_IRQ + |CC_IRQSTATUS_FIFO_OF_IRQ ; + +DBG ; + + cc_irqstatus =omap24xxcam_reg_in (core->base,CC_IRQSTATUS ); +omap24xxcam_reg_out (core->base,CC_IRQSTATUS , cc_irqstatus); + +if (cc_irqstatus & cc_irqstatus_err) { +printk ("%s: scheduling camera reset, cc_irqstatus 0x%lx\n" , + __FUNCTION__, cc_irqstatus); + omap24xxcam_camera_reset_schedule( + container_of(core, struct omap24xxcam_device,core));
drivers/media/video/omap/omap24xxcam-core.c new file +18
-0+ }else { +if (cc_irqstatus &0xffff ) +printk ("%s: cc_irqstatus 0x%lx\n" , + __FUNCTION__, cc_irqstatus); + } + +} + +static void xclk_set (struct omap24xxcam_core *core) +{ +unsigned long divisor = core->mclk / core->xclk; + +if (core->xclk_enabled) { +if (divisor ==1 ) +omap24xxcam_reg_out (core->base,CC_CTRL_XCLK , +CC_CTRL_XCLK_DIV_BYPASS ); +else + omap24xxcam_reg_out(core->base, CC_CTRL_XCLK,divisor);
drivers/media/video/omap/omap24xxcam-core.c new file +44
-0+ }else +omap24xxcam_reg_out (core->base,CC_CTRL_XCLK , +CC_CTRL_XCLK_DIV_STABLE_LOW ); + +} + +void omap24xxcam_core_xclk_enable (struct omap24xxcam_core *core) +{ + core->xclk_enabled =1 ; +xclk_set (core); +} + +void omap24xxcam_core_xclk_disable (struct omap24xxcam_core *core) +{ + + core->xclk_enabled =0 ; +xclk_set (core); +} + +void omap24xxcam_core_xclk_set (struct omap24xxcam_core *core, +unsigned long xclk) +{ +unsigned long divisor; + +DBG ; + +if (xclk > core->mclk) + xclk = core->mclk; + + divisor = core->mclk / xclk; +if (xclk * divisor < core->mclk) + divisor +=1 ; +if (divisor >30 ) + divisor =30 ; + core->xclk = core->mclk / divisor; + +xclk_set (core); +} + +void omap24xxcam_core_mclk_set (struct omap24xxcam_core *core, +unsigned long mclk) +{ + core->mclk = mclk; +}(quoted diff) +0
-0
dma.c
new file mode 100644
index 0000000..d10f1c8drivers/media/video/omap/omap24xxcam-dma.c new file +19
-0@@ -0,0 +1,320 @@ +/* +* drivers/media/video/omap/omap24xxcam-dma.c +* +* Video-for-Linux (Version 2) camera capture driver for +* the OMAP24xx camera controller. +* +* Author: David Cohen <[email protected]> +* Based on: omap24xxcam.c by Andy Lowe ([email protected]) +* +* Copyright (C) 2004 MontaVista Software, Inc. +* Copyright (C) 2004 Texas Instruments. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +* History: +* 2005/nov - David Cohen <[email protected]> +* Updated the driver for the Linux Device Model and new version of V4L2.
+ */drivers/media/video/omap/omap24xxcam-dma.c new file +32
-0+ +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/videodev.h> +#include <linux/pci.h> /* needed for videobufs */ +#include <media/video-buf.h> +#include <linux/dma-mapping.h> +#include <linux/input.h> +#include <linux/version.h> + +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/scatterlist.h> +#include <asm/irq.h> +#include <asm/semaphore.h> + +#include "omap24xxcam.h" +#include "omap24xxcam-dma.h" + +/* configuration macros */ +#define CAM_NAME "omap24xxcam" +#define CONFIG_H4 + +/* Start a DMA transfer from the camera to memory. +* Returns zero if the transfer was successfully started, or non-zero if all
+ * DMA channels are already in use or starting is currently inhibited.
+ */drivers/media/video/omap/omap24xxcam-dma.c new file +29
-0+int +omap24xxcam_dma_start (struct omap24xxcam_dma *dma,dma_addr_t start, +unsigned long len,dma_callback_t callback,void *arg) +{ +unsigned long irqflags; +int dmach; +void (*dma_notify)(struct omap24xxcam_device *cam); + +DBG ; + +spin_lock_irqsave (&dma->lock, irqflags); + +if (!dma->free_dmach || dma->dma_stop) { +spin_unlock_irqrestore (&dma->lock, irqflags); +DBG_MID (3 ); +return -EBUSY ; + } + + dmach = dma->next_dmach; + + dma->ch_state[dmach].callback = callback; + dma->ch_state[dmach].arg = arg; + +omap24xxcam_dmahw_transfer_setup (dma->base, dmach, start, len); + +/* We're ready to start the DMA transfer. */ + +if (dma->free_dmach <NUM_CAMDMA_CHANNELS ) { +/* A transfer is already in progress, so try to chain to it. */
+ omap24xxcam_dmahw_transfer_chain(dma->base, dmach,dma->free_dmach);drivers/media/video/omap/omap24xxcam-dma.c new file +18
-0+ } +else { +/* No transfer is in progress, so we'll just start this one +* now. +*/ +omap24xxcam_dmahw_transfer_start (dma->base, dmach); + } + + dma->next_dmach = (dma->next_dmach +1 ) %NUM_CAMDMA_CHANNELS ; + dma->free_dmach--; + + dma_notify = dma->dma_notify; + dma->dma_notify =NULL ; + +spin_unlock_irqrestore (&dma->lock, irqflags); + +if (dma_notify) + (*dma_notify)(container_of(container_of(dma, struct
omap24xxcam_sgdma, dma), structomap24xxcam_device, sgdma));drivers/media/video/omap/omap24xxcam-dma.c new file +7
-0+ +DBG_END ; + +return 0 ; +} + +/* Abort all chained DMA transfers. After all transfers have been aborted and
+ * the DMA controller is idle, the completion routines for any aborted transfers
+ * will be called in sequence. The DMA controller may not be idle after this
+ * routine completes, because the completion routines might start new transfers.
+ */drivers/media/video/omap/omap24xxcam-dma.c new file +20
-0+void +omap24xxcam_dma_abort (struct omap24xxcam_dma *dma,unsigned long csr) +{ +unsigned long irqflags; +int dmach, i, free_dmach; +dma_callback_t callback; +void *arg; + +DBG ; + +spin_lock_irqsave (&dma->lock, irqflags); + +/* stop any DMA transfers in progress */ + dmach = (dma->next_dmach + dma->free_dmach) %NUM_CAMDMA_CHANNELS ; +for (i =0 ; i <NUM_CAMDMA_CHANNELS ; i++) { +omap24xxcam_dmahw_abort_ch (dma->base, dmach); + dmach = (dmach +1 ) %NUM_CAMDMA_CHANNELS ; + } + +/* We have to be careful here because the callback routine might start
drivers/media/video/omap/omap24xxcam-dma.c new file +24
-0+* a new DMA transfer, and we only want to abort transfers that were +* started before this routine was called. +*/ + free_dmach = dma->free_dmach; +while ((dma->free_dmach <NUM_CAMDMA_CHANNELS ) && + (free_dmach <NUM_CAMDMA_CHANNELS )) { + dmach = (dma->next_dmach + dma->free_dmach) + %NUM_CAMDMA_CHANNELS ; + callback = dma->ch_state[dmach].callback; + arg = dma->ch_state[dmach].arg; + dma->free_dmach++; + free_dmach++; +if (callback) { +/* leave interrupts disabled during callback */ +spin_unlock (&dma->lock); + (*callback) (dma, csr, arg); +spin_lock (&dma->lock); + } + } + +spin_unlock_irqrestore (&dma->lock, irqflags); +} + +/* Abort all chained DMA transfers. After all transfers have been aborted and
+ * the DMA controller is idle, the completion routines for any aborted transfers
+ * will be called in sequence. If the completion routines attempt to start a
+ * new DMA transfer it will fail, so the DMA controller will be idle after this
+ * routine completes.
+ */drivers/media/video/omap/omap24xxcam-dma.c new file +21
-0+void +omap24xxcam_dma_stop (struct omap24xxcam_dma *dma,unsigned long csr) +{ +unsigned long irqflags; + +DBG ; + +spin_lock_irqsave (&dma->lock, irqflags); + dma->dma_stop++; +spin_unlock_irqrestore (&dma->lock, irqflags); +omap24xxcam_dma_abort (dma, csr); +spin_lock_irqsave (&dma->lock, irqflags); + dma->dma_stop--; +spin_unlock_irqrestore (&dma->lock, irqflags); +} + +/* 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.
+ */drivers/media/video/omap/omap24xxcam-dma.c new file +39
-0+int +omap24xxcam_dma_notify (struct omap24xxcam_dma *dma, +void (*callback) (struct omap24xxcam_device * cam)) +{ +unsigned long irqflags; + +DBG ; + +spin_lock_irqsave (&dma->lock, irqflags); + +if (dma->dma_notify && (dma->dma_notify != callback)) { +spin_unlock_irqrestore (&dma->lock, irqflags); +return -EBUSY ; + } + + dma->dma_notify = callback; + +spin_unlock_irqrestore (&dma->lock, irqflags); + +return 0 ; +} + +/* Camera DMA interrupt service routine. */ +void omap24xxcam_dma_isr (struct omap24xxcam_dma *dma) +{ +int dmach; +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 ; + +DBG ; + +spin_lock (&dma->lock); + +if (dma->free_dmach ==NUM_CAMDMA_CHANNELS ) { +/* A camera DMA interrupt occurred while all channels are idle,
+ * so we'll acknowledge the interrupt in the IRQSTATUS
registerdrivers/media/video/omap/omap24xxcam-dma.c new file +12
-0+* and exit. +*/ +omap24xxcam_dmahw_ack_all (dma->base); +spin_unlock (&dma->lock); +return ; + } + +while (dma->free_dmach <NUM_CAMDMA_CHANNELS ) { + dmach = (dma->next_dmach + dma->free_dmach) + %NUM_CAMDMA_CHANNELS ; +if (omap24xxcam_dmahw_running (dma->base, dmach)) { +/* This buffer hasn't finished yet, so we're done. */
drivers/media/video/omap/omap24xxcam-dma.c new file +5
-0+break ; + } + csr =omap24xxcam_dmahw_ack_ch (dma->base, dmach); +if (csr & csr_error) { +/* A DMA error occurred, so stop all DMA transfers in
drivers/media/video/omap/omap24xxcam-dma.c new file +20
-0+* progress. +*/ +spin_unlock (&dma->lock); +omap24xxcam_dma_stop (dma, csr); +return ; + }else { + callback = dma->ch_state[dmach].callback; + arg = dma->ch_state[dmach].arg; + dma->free_dmach++; +if (callback) { +spin_unlock (&dma->lock); + (*callback) (dma, csr, arg); +spin_lock (&dma->lock); + } + } + } + +spin_unlock (&dma->lock); + + omap24xxcam_sgdma_process(container_of(dma, struct
omap24xxcam_sgdma, dma));drivers/media/video/omap/omap24xxcam-dma.c new file +56
-0+} + +void omap24xxcam_dma_init (struct omap24xxcam_dma *dma,unsigned long base) +{ +int ch; + +DBG ; + +/* group all channels on DMA IRQ0 and unmask irq */ +spin_lock_init (&dma->lock); + dma->base = base; + dma->free_dmach =NUM_CAMDMA_CHANNELS ; + dma->next_dmach =0 ; +for (ch =0 ; ch <NUM_CAMDMA_CHANNELS ; ch++) { + dma->ch_state[ch].callback =NULL ; + dma->ch_state[ch].arg =NULL ; + } +} + +/* Shutdown the camera DMA driver and controller. */ +void +omap24xxcam_dma_exit (struct omap24xxcam_dma *dma) +{ +DBG ; + +omap24xxcam_dma_disable (dma); +} + +void omap24xxcam_dma_enable (struct omap24xxcam_dma *dma) +{ +unsigned long flags; + +spin_lock_irqsave (&dma->lock, flags); + +omap24xxcam_dmahw_init (dma->base); +omap24xxcam_dmahw_unmask_irq0 (dma->base); + +spin_unlock_irqrestore (&dma->lock, flags); +} + +void omap24xxcam_dma_disable (struct omap24xxcam_dma *dma) +{ +int ch; +unsigned long flags; + +spin_lock_irqsave (&dma->lock, flags); + +/* Mask all DMA interrupts */ +omap24xxcam_dmahw_mask_all (dma->base); + +/* disable all DMA channels */ +for (ch =0 ; ch <NUM_CAMDMA_CHANNELS ; ch++) +omap24xxcam_dmahw_disable_ch (dma->base, ch); + +spin_unlock_irqrestore (&dma->lock, flags); +}(quoted diff) +0
-0
dma.h
new file mode 100644
index 0000000..5898fd9drivers/media/video/omap/omap24xxcam-dma.h new file +18
-0@@ -0,0 +1,65 @@ +/* +* drivers/media/video/omap/omap24xxcam-dma.h +* +* Copyright (C) 2006 Instituto Nokia de Tecnolodia +* +* Author: David Cohen <[email protected]> +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +*/ + +/* sg_dma prototypes */ + +void omap24xxcam_sgdma_process (struct omap24xxcam_sgdma *sgdma); +int +omap24xxcam_sgdma_queue (struct omap24xxcam_sgdma *sgdma, + const struct scatterlist *sglist, int sglen, intlen,
drivers/media/video/omap/omap24xxcam-dma.h new file +4
-0+ sgdma_callback_t callback, void *arg); +void +omap24xxcam_sgdma_sync (struct omap24xxcam_sgdma *sgdma,unsigned long csr); +void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma, unsigned longbase);
drivers/media/video/omap/omap24xxcam-dma.h new file +9
-0+void omap24xxcam_sgdma_exit (struct omap24xxcam_sgdma *sgdma); +void omap24xxcam_sgdma_enable (struct omap24xxcam_sgdma *sgdma); +void omap24xxcam_sgdma_disable (struct omap24xxcam_sgdma *sgdma); + +/* dma prototypes */ + +int +omap24xxcam_dma_start (struct omap24xxcam_dma *dma,dma_addr_t start, + unsigned long len, dma_callback_t callback, void*arg);
drivers/media/video/omap/omap24xxcam-dma.h new file +34
-0+void +omap24xxcam_dma_abort (struct omap24xxcam_dma *dma,unsigned long csr); +void +omap24xxcam_dma_stop (struct omap24xxcam_dma *dma,unsigned long csr); +int +omap24xxcam_dma_notify (struct omap24xxcam_dma *dma, +void (*callback) (struct omap24xxcam_device * cam)); +void omap24xxcam_dma_isr (struct omap24xxcam_dma *dma); +void +omap24xxcam_dma_init (struct omap24xxcam_dma *dma,unsigned long base); +void +omap24xxcam_dma_exit (struct omap24xxcam_dma *dma); +void +omap24xxcam_dma_enable (struct omap24xxcam_dma *dma); +void +omap24xxcam_dma_disable (struct omap24xxcam_dma *dma); + +/* dmahw prototypes */ + +void omap24xxcam_dmahw_ack_all (unsigned long base); +unsigned long omap24xxcam_dmahw_ack_ch (unsigned long base,int dmach); +int omap24xxcam_dmahw_running (unsigned long base,int dmach); +void omap24xxcam_dmahw_transfer_setup (unsigned long base,int dmach, +dma_addr_t start,unsigned long len); +void omap24xxcam_dmahw_transfer_chain (unsigned long base,int dmach, +int free_dmach); +void omap24xxcam_dmahw_transfer_start (unsigned long base,int dmach); +void +omap24xxcam_dmahw_abort_ch (unsigned long base,int dmach); +void omap24xxcam_dmahw_mask_all (unsigned long base); +void omap24xxcam_dmahw_unmask_irq0 (unsigned long base); +void omap24xxcam_dmahw_disable_ch (unsigned long base,int ch); +void omap24xxcam_dmahw_init (unsigned long base); +(quoted diff) +0
-0
dmahw.c
new file mode 100644
index 0000000..21d23dbdrivers/media/video/omap/omap24xxcam-dmahw.c new file +19
-0@@ -0,0 +1,224 @@ +/* +* drivers/media/video/omap/omap24xxcam-dma.c +* +* Video-for-Linux (Version 2) camera capture driver for +* the OMAP24xx camera controller. +* +* Author: David Cohen <[email protected]> +* Based on: omap24xxcam.c by Andy Lowe ([email protected]) +* +* Copyright (C) 2004 MontaVista Software, Inc. +* Copyright (C) 2004 Texas Instruments. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +* History: +* 2005/nov - David Cohen <[email protected]> +* Updated the driver for the Linux Device Model and new version of V4L2.
+ */drivers/media/video/omap/omap24xxcam-dmahw.c new file +61
-0+ +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/videodev.h> +#include <linux/pci.h> /* needed for videobufs */ +#include <media/video-buf.h> +#include <linux/dma-mapping.h> +#include <linux/input.h> +#include <linux/version.h> + +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/scatterlist.h> +#include <asm/irq.h> +#include <asm/semaphore.h> + +#include "omap24xxcam.h" +#include "omap24xxcam-dma.h" + +/* configuration macros */ +#define CAM_NAME "omap24xxcam" +#define CONFIG_H4 + +/* Ack all interrupt on CSR and IRQSTATUS_L0 */ +void omap24xxcam_dmahw_ack_all (unsigned long base) +{ +unsigned long csr; +int i; + +for (i =0 ; i<4 ; ++i) { + csr =omap24xxcam_reg_in (base,CAMDMA_CSR (i)); +/* ack interrupt in CSR */ +omap24xxcam_reg_out (base,CAMDMA_CSR (i), csr); + } +omap24xxcam_reg_out (base,CAMDMA_IRQSTATUS_L0 ,0xffffffff ); +} + +/* Ack dmach on CSR and IRQSTATUS_L0 */ +unsigned long omap24xxcam_dmahw_ack_ch (unsigned long base,int dmach) +{ +unsigned long csr; + + csr =omap24xxcam_reg_in (base,CAMDMA_CSR (dmach)); +/* ack interrupt in CSR */ +omap24xxcam_reg_out (base,CAMDMA_CSR (dmach), csr); +/* ack interrupt in IRQSTATUS */ +omap24xxcam_reg_out (base,CAMDMA_IRQSTATUS_L0 , (1 << dmach)); + +return csr; +} + +int omap24xxcam_dmahw_running (unsigned long base,int dmach) +{ + return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) &
CAMDMA_CCR_ENABLE;drivers/media/video/omap/omap24xxcam-dmahw.c new file +23
-0+} + +void omap24xxcam_dmahw_transfer_setup (unsigned long base,int dmach, +dma_addr_t start,unsigned long len) +{ +omap24xxcam_reg_out (base,CAMDMA_CCR (dmach), +CAMDMA_CCR_SEL_SRC_DST_SYNC + |CAMDMA_CCR_BS + |CAMDMA_CCR_DST_AMODE_POST_INC + |CAMDMA_CCR_SRC_AMODE_POST_INC + |CAMDMA_CCR_FS + |CAMDMA_CCR_WR_ACTIVE + |CAMDMA_CCR_RD_ACTIVE + |CAMDMA_CCR_SYNCHRO_CAMERA ); +omap24xxcam_reg_out (base,CAMDMA_CLNK_CTRL (dmach),0 ); +omap24xxcam_reg_out (base,CAMDMA_CEN (dmach), len); +omap24xxcam_reg_out (base,CAMDMA_CFN (dmach),1 ); +omap24xxcam_reg_out (base,CAMDMA_CSDP (dmach), +CAMDMA_CSDP_WRITE_MODE_POSTED + |CAMDMA_CSDP_DST_BURST_EN_32 + |CAMDMA_CSDP_DST_PACKED + |CAMDMA_CSDP_SRC_BURST_EN_32 + | CAMDMA_CSDP_SRC_PACKED
drivers/media/video/omap/omap24xxcam-dmahw.c
Quoted 10 lines
drivers/media/video/omap/omap24xxcam-dmahw.c new file +10
-0+ | CAMDMA_CSDP_DATA_TYPE_8BITS); +omap24xxcam_reg_out (base,CAMDMA_CSSA (dmach),0 ); +omap24xxcam_reg_out (base,CAMDMA_CDSA (dmach), start); +omap24xxcam_reg_out (base,CAMDMA_CSEI (dmach),0 ); +omap24xxcam_reg_out (base,CAMDMA_CSFI (dmach),DMA_THRESHOLD ); +omap24xxcam_reg_out (base,CAMDMA_CDEI (dmach),0 ); +omap24xxcam_reg_out (base,CAMDMA_CDFI (dmach),0 ); +omap24xxcam_reg_out (base,CAMDMA_CSR (dmach), +CAMDMA_CSR_MISALIGNED_ERR + | CAMDMA_CSR_SUPERVISOR_ERR
TRM spec recommends writing zero to this position, page 974
drivers/media/video/omap/omap24xxcam-dmahw.c
Quoted 7 lines
drivers/media/video/omap/omap24xxcam-dmahw.c new file +7
-0+ | CAMDMA_CSR_SECURE_ERR + |CAMDMA_CSR_TRANS_ERR + |CAMDMA_CSR_BLOCK + | CAMDMA_CSR_DROP); +omap24xxcam_reg_out (base,CAMDMA_CICR (dmach), +CAMDMA_CICR_MISALIGNED_ERR_IE + | CAMDMA_CICR_SUPERVISOR_ERR_IE
Same here. TRM spec recommends writing zero to this position, page 974
Quoted 76 lines
drivers/media/video/omap/omap24xxcam-dmahw.c new file +52
-0+ | CAMDMA_CICR_SECURE_ERR_IE + |CAMDMA_CICR_TRANS_ERR_IE + |CAMDMA_CICR_BLOCK_IE + | CAMDMA_CICR_DROP_IE); +} + +void omap24xxcam_dmahw_transfer_chain (unsigned long base,int dmach, +int free_dmach) +{ +int prev_dmach, ch; + +if (dmach ==0 ) + prev_dmach =NUM_CAMDMA_CHANNELS -1 ; +else + prev_dmach = dmach -1 ; +omap24xxcam_reg_out (base,CAMDMA_CLNK_CTRL (prev_dmach), +CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach); +/* Did we chain the DMA transfer before the previous one +* finished? +*/ + ch = (dmach + free_dmach) %NUM_CAMDMA_CHANNELS ; +DBG_MID (1 ); +while (!(omap24xxcam_reg_in (base,CAMDMA_CCR (ch)) + &CAMDMA_CCR_ENABLE )) + { +if (ch == dmach) { +/* The previous transfer has ended and this one +* hasn't started, so we must not have chained +* to the previous one in time. We'll have to +* start it now. +*/ +omap24xxcam_dmahw_transfer_start (base, dmach); +break ; + }else + ch = (ch +1 ) %NUM_CAMDMA_CHANNELS ; + } +DBG_MID (2 ); +} + +void omap24xxcam_dmahw_transfer_start (unsigned long base,int dmach) +{ +omap24xxcam_reg_out (base,CAMDMA_CCR (dmach), +CAMDMA_CCR_SEL_SRC_DST_SYNC + |CAMDMA_CCR_BS + |CAMDMA_CCR_DST_AMODE_POST_INC + |CAMDMA_CCR_SRC_AMODE_POST_INC + |CAMDMA_CCR_ENABLE + |CAMDMA_CCR_FS + |CAMDMA_CCR_SYNCHRO_CAMERA ); +} + +/* Abort all chained DMA transfers. After all transfers have been aborted and
+ * the DMA controller is idle, the completion routines for any aborted transfers
+ * will be called in sequence. The DMA controller may not be idle after this
+ * routine completes, because the completion routines might start new transfers.
+ */drivers/media/video/omap/omap24xxcam-dmahw.c new file +10
-0+void +omap24xxcam_dmahw_abort_ch (unsigned long base,int dmach) +{ +/* mask all interrupts from this channel */ +omap24xxcam_reg_out (base,CAMDMA_CICR (dmach),0 ); +/* unlink this channel */ +omap24xxcam_reg_merge (base,CAMDMA_CLNK_CTRL (dmach),0 , +CAMDMA_CLNK_CTRL_ENABLE_LNK ); +/* disable this channel */ + omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0,
CAMDMA_CCR_ENABLE);drivers/media/video/omap/omap24xxcam-dmahw.c new file +5
-0+} + +/* Mask all DMA interrupts */ +void omap24xxcam_dmahw_mask_all (unsigned long base) +{
drivers/media/video/omap/omap24xxcam-dmahw.c
Quoted 10 lines
drivers/media/video/omap/omap24xxcam-dmahw.c new file +10
-0+omap24xxcam_reg_out (base,CAMDMA_IRQENABLE_L0 ,0 ); +omap24xxcam_reg_out (base,CAMDMA_IRQENABLE_L1 ,0 ); +omap24xxcam_reg_out (base,CAMDMA_IRQENABLE_L2 ,0 ); +omap24xxcam_reg_out (base,CAMDMA_IRQENABLE_L3 ,0 ); +} + +/* group all channels on DMA IRQ0 and unmask irq */ +void omap24xxcam_dmahw_unmask_irq0 (unsigned long base) +{ +omap24xxcam_reg_out (base,CAMDMA_IRQENABLE_L0 ,0xffffffff );
TRM spec recommends writing zero to the reserved positions, page 954
Quoted 1,674 lines
drivers/media/video/omap/omap24xxcam-dmahw.c new file +22
-0+omap24xxcam_reg_out (base,CAMDMA_IRQENABLE_L1 ,0 ); +omap24xxcam_reg_out (base,CAMDMA_IRQENABLE_L2 ,0 ); +omap24xxcam_reg_out (base,CAMDMA_IRQENABLE_L3 ,0 ); +} + +void omap24xxcam_dmahw_disable_ch (unsigned long base,int ch) +{ +omap24xxcam_reg_out (base,CAMDMA_CCR (ch),0 ); +} + +void omap24xxcam_dmahw_init (unsigned long base) +{ +DBG ; +omap24xxcam_reg_out (base,CAMDMA_OCP_SYSCONFIG , +CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY + |CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE + |CAMDMA_OCP_SYSCONFIG_AUTOIDLE ); + +omap24xxcam_reg_merge (base,CAMDMA_GCR ,0x10 , +CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH ); +} +(quoted diff) +0
-0
sensor.c
new file mode 100644
index 0000000..bde7429drivers/media/video/omap/omap24xxcam-sensor.c new file +19
-0@@ -0,0 +1,226 @@ +/* +* drivers/media/video/omap/omap24xxcam-dma.c +* +* Video-for-Linux (Version 2) camera capture driver for +* the OMAP24xx camera controller. +* +* Author: David Cohen <[email protected]> +* Based on: omap24xxcam.c by Andy Lowe ([email protected]) +* +* Copyright (C) 2004 MontaVista Software, Inc. +* Copyright (C) 2004 Texas Instruments. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +* History: +* 2005/nov - David Cohen <[email protected]> +* Updated the driver for the Linux Device Model and new version of V4L2.
+ */drivers/media/video/omap/omap24xxcam-sensor.c new file +46
-0+ +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/videodev.h> +#include <linux/pci.h> /* needed for videobufs */ +#include <media/video-buf.h> +#include <linux/dma-mapping.h> +#include <linux/input.h> +#include <linux/version.h> + +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/scatterlist.h> +#include <asm/irq.h> +#include <asm/semaphore.h> + +#include "omap24xxcam.h" +#include "sensor_if.h" +#include "omap24xxcam-dma.h" + +/* camera driver: initialise sensor */ +int omap24xxcam_sensor_init (struct omap24xxcam_device *cam) +{ +int err =0 ; + +if (cam->sensor ==NULL ) +return -ENODEV ; + +if (cam->sensor_alive) +return 0 ; + +omap24xxcam_clock_on (cam); +omap24xxcam_core_xclk_enable (&cam->core); + +/* power up sensor during sensor initialization */ +if (cam->sensor->power_on) + cam->sensor->power_on (cam->sensor); + +/* initialize the sensor and define a default capture format cam-> img.pix */
drivers/media/video/omap/omap24xxcam-sensor.c new file +56
-0+ err = cam->sensor->init (cam->sensor, + &cam->img.pix, + &omap24xxcam_camera); +if (err) { + printk(KERN_ERR CAM_NAME + ": cannot initialize sensor, error %d\n", err); + goto out; + } +printk (KERN_INFO "Sensor is %s\n" , cam->sensor->name); + +out: +omap24xxcam_core_xclk_disable (&cam->core); +omap24xxcam_clock_off (cam); + +if (cam->sensor->power_off) + cam->sensor->power_off (cam->sensor); + + cam->sensor_alive =1 ; + +return err; +} + +void omap24xxcam_sensor_exit (struct omap24xxcam_device *cam) +{ +if (cam->sensor ==NULL ) +return ; +if (!cam->sensor_alive) +return ; + +omap24xxcam_sensor_disable (cam); + cam->sensor->cleanup (cam->sensor); + cam->sensor_alive =0 ; +} + +/* Power-up and configure camera sensor */ +int omap24xxcam_sensor_enable (struct omap24xxcam_device *cam) +{ +omap24xxcam_clock_on (cam); + +/* calculate xclk based on the default capture format and default +* frame rate +*/ +omap24xxcam_core_xclk_set ( + &cam->core, + cam->sensor->calc_xclk ( + cam->sensor, + &cam->img.pix, + &cam->img.cparm.timeperframe)); +omap24xxcam_core_xclk_enable (&cam->core); + +if (cam->sensor->power_on) + cam->sensor->power_on (cam->sensor); + +/* program the sensor for the default capture format and rate */ + cam->sensor->configure (cam->sensor, &cam->img.pix, + cam->core.xclk, &cam->img.cparm.timeperframe);
drivers/media/video/omap/omap24xxcam-sensor.c new file +104
-0+ +return 0 ; +} + +void omap24xxcam_sensor_disable (struct omap24xxcam_device *cam) +{ +omap24xxcam_core_xclk_disable (&cam->core); +omap24xxcam_clock_off (cam); +if (cam->sensor->power_off) + cam->sensor->power_off (cam->sensor); +} + +void omap24xxcam_sensor_reset_work (void * data) +{ +struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data; + +omap24xxcam_sensor_disable (cam); + +omap24xxcam_sensor_enable (cam); +} + +void omap24xxcam_sensor_reset_schedule (struct omap_camera *oc, +struct omap_camera_sensor *os) +{ +struct omap24xxcam_device *cam = oc->priv; + +schedule_work (&cam->sensor_reset_work); +} + +EXPORT_SYMBOL (omap24xxcam_sensor_reset_schedule); + +unsigned long omap24xxcam_sensor_calc_xclk (struct omap24xxcam_device *cam, +struct v4l2_pix_format *pix, +struct v4l2_fract *timeperframe) +{ +return cam->sensor->calc_xclk (cam->sensor, + pix, + timeperframe); +} + +int omap24xxcam_sensor_try_format (struct omap24xxcam_device *cam, +struct v4l2_pix_format *pix) +{ +return cam->sensor->try_format (cam->sensor, + pix); +} + +int omap24xxcam_sensor_set_format (struct omap24xxcam_device *cam, +struct v4l2_pix_format *pix, +struct v4l2_fract *timeperframe, +unsigned long *xclk) +{ +int err; + +if (timeperframe->numerator ==0 + || timeperframe->denominator ==0 ) +return -EINVAL ; + + *xclk = cam->sensor->calc_xclk (cam->sensor, pix, timeperframe); + +omap24xxcam_core_xclk_set (&cam->core, *xclk); + + err = cam->sensor->configure (cam->sensor, pix, *xclk, timeperframe); + +return err; +} + +/* This should be called by the sensor code whenever it's ready */ +int omap24xxcam_sensor_register (struct omap_camera *oc, +struct omap_camera_sensor *os) +{ +struct omap24xxcam_device *cam = oc->priv; +int rval; + +/* the device has not been initialised yet */ +if (cam ==NULL ) +return -ENODEV ; +if (os ==NULL ) +return -EINVAL ; +if (cam->sensor !=NULL ) +return -EBUSY ; + + cam->sensor = os; + rval =omap24xxcam_device_enable (cam); + +if (rval) + cam->sensor =NULL ; +return rval; +} + +EXPORT_SYMBOL (omap24xxcam_sensor_register); + +void omap24xxcam_sensor_unregister (struct omap_camera *oc, +struct omap_camera_sensor *os) +{ +struct omap24xxcam_device *cam = oc->priv; + +BUG_ON (cam->users !=0 ); +BUG_ON (cam->sensor ==NULL ); + + cam->sensor =NULL ; +} + +EXPORT_SYMBOL (omap24xxcam_sensor_unregister);(quoted diff) +0
-0
sgdma.c
new file mode 100644
index 0000000..0243a59drivers/media/video/omap/omap24xxcam-sgdma.c new file +136
-0@@ -0,0 +1,298 @@ +/* +* OMAP 24xx camera high-level DMA (not hardware) and scatter-gather +* DMA handling +* +* Author: Andy Lowe ([email protected]) +* +* Copyright (C) 2004 MontaVista Software, Inc. +* Copyright (C) 2004 Texas Instruments. +* Copyright (C) 2007 Nokia Corporation. +* +* Contact: Sakari Ailus <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA +*/ + +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/videodev.h> +#include <linux/pci.h> /* needed for videobufs */ +#include <media/video-buf.h> +#include <linux/dma-mapping.h> +#include <linux/input.h> +#include <linux/version.h> + +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/scatterlist.h> +#include <asm/irq.h> +#include <asm/semaphore.h> + +#include "omap24xxcam.h" +#include "omap24xxcam-dma.h" + +/* +* Scatter-gather DMA +* +* High-level DMA construct for transferring whole picture frames to +* memory that is discontinuous. +*/ + +/* DMA completion routine for the scatter-gather DMA fragments. */ +static void +omap24xxcam_sgdma_callback (struct omap24xxcam_dma *dma,unsigned long csr, +void *arg) +{ +struct omap24xxcam_sgdma *sgdma = + container_of(dma, struct omap24xxcam_sgdma, dma); +int sgslot = (int )arg; +struct sgdma_state *sg_state; +const unsigned long csr_error =CAMDMA_CSR_MISALIGNED_ERR + |CAMDMA_CSR_SUPERVISOR_ERR |CAMDMA_CSR_SECURE_ERR + |CAMDMA_CSR_TRANS_ERR |CAMDMA_CSR_DROP ; + +DBG ; + +spin_lock (&sgdma->lock); + +/* We got an interrupt, we can remove the timer */ +del_timer (&sgdma->reset_timer); + + sg_state = sgdma->sg_state + sgslot; +if (!sg_state->queued_sglist) { +spin_unlock (&sgdma->lock); + printk(KERN_DEBUG CAM_NAME + ": sgdma completed when none queued!\n"); +return ; + } + + sg_state->csr |= csr; +if (!--sg_state->queued_sglist) { +/* Queue for this sglist is empty, so check to see if we're +* done. +*/ +if ((sg_state->next_sglist == sg_state->sglen) + || (sg_state->csr & csr_error)) { +sgdma_callback_t callback = sg_state->callback; +void *arg = sg_state->arg; +unsigned long sg_csr = sg_state->csr; +/* All done with this sglist */ + sgdma->free_sgdma++; +if (callback) { +spin_unlock (&sgdma->lock); + (*callback) (sgdma, sg_csr, arg); +return ; + } + } + } + +spin_unlock (&sgdma->lock); +} + +/* Process the scatter-gather DMA queue by starting queued transfers. */ +void omap24xxcam_sgdma_process (struct omap24xxcam_sgdma *sgdma) +{ +unsigned long irqflags; +int queued_sgdma, sgslot; +struct sgdma_state *sg_state; +const unsigned long csr_error =CAMDMA_CSR_MISALIGNED_ERR + |CAMDMA_CSR_SUPERVISOR_ERR |CAMDMA_CSR_SECURE_ERR + |CAMDMA_CSR_TRANS_ERR |CAMDMA_CSR_DROP ; + +DBG ; + +spin_lock_irqsave (&sgdma->lock, irqflags); + + queued_sgdma =NUM_SG_DMA - sgdma->free_sgdma; + sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) %NUM_SG_DMA ; +while (queued_sgdma >0 ) { + sg_state = sgdma->sg_state + sgslot; +while ((sg_state->next_sglist < sg_state->sglen) && + !(sg_state->csr & csr_error)) { +const struct scatterlist *sglist; +unsigned int len; + + sglist = sg_state->sglist + sg_state->next_sglist; +/* try to start the next DMA transfer */ +if ( sg_state->next_sglist +1 == sg_state->sglen ){
drivers/media/video/omap/omap24xxcam-sgdma.c new file +10
-0+/* +* On the last sg, we handle the case where +* cam->img.pix.sizeimage % PAGE_ALIGN != 0 +*/ + len = sg_state->len - sg_state->bytes_read; + }else { + len =sg_dma_len (sglist); + } + + if (omap24xxcam_dma_start(&sgdma->dma,
sg_dma_address(sglist),drivers/media/video/omap/omap24xxcam-sgdma.c new file +2
-0+ len, +
omap24xxcam_sgdma_callback,drivers/media/video/omap/omap24xxcam-sgdma.c new file +3
-0+ (void *)sgslot)) { +/* DMA start failed */ + spin_unlock_irqrestore(&sgdma->lock,irqflags);
drivers/media/video/omap/omap24xxcam-sgdma.c new file +28
-0+return ; + }else { +unsigned long expires; +/* DMA start was successful */ + sg_state->next_sglist++; + sg_state->bytes_read += len; + sg_state->queued_sglist++; + +/* We start the reset timer */ + expires = jiffies +HZ ; +mod_timer (&sgdma->reset_timer, expires); + } + } + queued_sgdma--; + sgslot = (sgslot +1 ) %NUM_SG_DMA ; + } + +spin_unlock_irqrestore (&sgdma->lock, irqflags); +DBG_END ; +} + +/* Queue a scatter-gather DMA transfer from the camera to memory. +* Returns zero if the transfer was successfully queued, or +* non-zero if all of the scatter-gather slots are already in use. +*/ +int +omap24xxcam_sgdma_queue (struct omap24xxcam_sgdma *sgdma, + const struct scatterlist *sglist, int sglen, intlen,
drivers/media/video/omap/omap24xxcam-sgdma.c new file +40
-0+ sgdma_callback_t callback, void *arg) +{ + unsigned long irqflags; +struct sgdma_state *sg_state; + +DBG ; + +if ((sglen <0 ) || ((sglen >0 ) & !sglist)) +return -EINVAL ; + +spin_lock_irqsave (&sgdma->lock, irqflags); + +if (!sgdma->free_sgdma) { +spin_unlock_irqrestore (&sgdma->lock, irqflags); +return -EBUSY ; + } + + sg_state = sgdma->sg_state + sgdma->next_sgdma; + + sg_state->sglist = sglist; + sg_state->sglen = sglen; + sg_state->next_sglist =0 ; + sg_state->bytes_read =0 ; + sg_state->len = len; + sg_state->queued_sglist =0 ; + sg_state->csr =0 ; + sg_state->callback = callback; + sg_state->arg = arg; + + sgdma->next_sgdma = (sgdma->next_sgdma +1 ) %NUM_SG_DMA ; + sgdma->free_sgdma--; + +spin_unlock_irqrestore (&sgdma->lock, irqflags); + +omap24xxcam_sgdma_process (sgdma); + +return 0 ; +} + +/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
+ * Any queued scatter-gather DMA transactions that have not yet been started
+ * will remain queued. The DMA controller will be idle after this routine
+ * completes. When the scatter-gather queue is restarted, the next
+ * scatter-gather DMA transfer will begin at the start of a new transaction.
+ */drivers/media/video/omap/omap24xxcam-sgdma.c new file +16
-0+void +omap24xxcam_sgdma_sync (struct omap24xxcam_sgdma *sgdma,unsigned long csr) +{ +unsigned long irqflags; +int sgslot; +struct sgdma_state *sg_state; + +DBG ; + +/* stop any DMA transfers in progress */ +omap24xxcam_dma_stop (&sgdma->dma, csr); + +spin_lock_irqsave (&sgdma->lock, irqflags); + +if (sgdma->free_sgdma <NUM_SG_DMA ) { + sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) %
NUM_SG_DMA;drivers/media/video/omap/omap24xxcam-sgdma.c new file +3
-0+ sg_state = sgdma->sg_state + sgslot; +if (sg_state->next_sglist !=0 ) { +/* This DMA transfer was in progress, so abort it. */
drivers/media/video/omap/omap24xxcam-sgdma.c new file +17
-0+sgdma_callback_t callback = sg_state->callback; +void *arg = sg_state->arg; + sgdma->free_sgdma++; +if (callback) { +/* leave interrupts masked */ +spin_unlock (&sgdma->lock); + (*callback) (sgdma, csr, arg); +spin_lock (&sgdma->lock); + } + } + } + +spin_unlock_irqrestore (&sgdma->lock, irqflags); +} + + +void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma, unsigned longbase)
drivers/media/video/omap/omap24xxcam-sgdma.c new file +38
-0+{ +int sg; + +DBG ; + +spin_lock_init (&sgdma->lock); + sgdma->free_sgdma =NUM_SG_DMA ; + sgdma->next_sgdma =0 ; +for (sg =0 ; sg <NUM_SG_DMA ; sg++) { + sgdma->sg_state[sg].sglen =0 ; + sgdma->sg_state[sg].next_sglist =0 ; + sgdma->sg_state[sg].bytes_read =0 ; + sgdma->sg_state[sg].queued_sglist =0 ; + sgdma->sg_state[sg].csr =0 ; + sgdma->sg_state[sg].callback =NULL ; + sgdma->sg_state[sg].arg =NULL ; + } + +omap24xxcam_dma_init (&sgdma->dma, base); +} + +void omap24xxcam_sgdma_exit (struct omap24xxcam_sgdma *sgdma) +{ +omap24xxcam_sgdma_sync (sgdma,CAMDMA_CSR_TRANS_ERR ); +omap24xxcam_dma_exit (&sgdma->dma); +} + +void omap24xxcam_sgdma_enable (struct omap24xxcam_sgdma *sgdma) +{ +omap24xxcam_dma_enable (&sgdma->dma); +omap24xxcam_sgdma_process (sgdma); +} + +void omap24xxcam_sgdma_disable (struct omap24xxcam_sgdma *sgdma) +{ +omap24xxcam_sgdma_sync (sgdma,CAMDMA_CSR_TRANS_ERR ); +omap24xxcam_dma_disable (&sgdma->dma); +}(quoted diff) +0
-0
vbq.c
new file mode 100644
index 0000000..f6d8803drivers/media/video/omap/omap24xxcam-vbq.c new file +90
-0@@ -0,0 +1,370 @@ +/* +* OMAP 24xx camera high-level DMA (not hardware) and scatter-gather +* DMA handling +* +* Author: Andy Lowe ([email protected]) +* +* Copyright (C) 2004 MontaVista Software, Inc. +* Copyright (C) 2004 Texas Instruments. +* Copyright (C) 2007 Nokia Corporation. +* +* Contact: Sakari Ailus <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA +*/ + +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/videodev.h> +#include <linux/pci.h> /* needed for videobufs */ +#include <media/video-buf.h> +#include <linux/dma-mapping.h> +#include <linux/input.h> +#include <linux/version.h> + +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/scatterlist.h> +#include <asm/irq.h> +#include <asm/semaphore.h> + +#include "omap24xxcam.h" +#include "omap24xxcam-dma.h" + +static void +omap24xxcam_vbq_free_mmap_buffer (struct videobuf_buffer *vb) +{ +int i; +size_t alloc_size; +struct page *page; + +if (vb->dma.sglist ==NULL ) +return ; + + i = vb->dma.sglen; +while (i) { + i--; + alloc_size = vb->dma.sglist[i].length; + page = vb->dma.sglist[i].page; +do { +ClearPageReserved (page++); + }while (alloc_size -=PAGE_SIZE ); +__free_pages (vb->dma.sglist[i].page, +get_order (vb->dma.sglist[i].length)); + } + +kfree (vb->dma.sglist); + vb->dma.sglist =NULL ; +} + +/* Allocate physically as contiguous as possible buffer for video frame and +* build DMA scatter-gather list for it +*/ +static int +omap24xxcam_vbq_alloc_mmap_buffer (struct videobuf_buffer *vb) +{ +unsigned long order; +size_t alloc_size, size = vb->bsize;/* vb->bsize is page aligned */ +struct page *page; +int max_pages, err =0 , i =0 ; + +/* allocate maximum size scatter-gather list. Note this is overhead. We
drivers/media/video/omap/omap24xxcam-vbq.c new file +3
-0+* may not use as many entries as we allocate */ + max_pages = vb->bsize >>PAGE_SHIFT ; + vb->dma.sglist = kcalloc(max_pages, sizeof(*vb->dma.sglist),
GFP_KERNEL);drivers/media/video/omap/omap24xxcam-vbq.c new file +8
-0+if (vb->dma.sglist ==NULL ) { + err = -ENOMEM ; + goto out; + } + +while (size) { + order =get_order (size); +/* do not over-allocate even if we would get larger contiguous
drivers/media/video/omap/omap24xxcam-vbq.c new file +18
-0+* chunk that way */ +if ((PAGE_SIZE << order) > size) + order--; + +/* try to allocate as many contiguous pages as possible */ + page =alloc_pages (GFP_KERNEL |GFP_DMA , order); +/* if allocation fails, try to allocate smaller amount */ +while (page ==NULL ) { + order--; + page =alloc_pages (GFP_KERNEL |GFP_DMA , order); +if (page ==NULL && !order) { + err = -ENOMEM ; + goto out; + } + } + size -= (PAGE_SIZE << order); + +/* append allocated chunk of pages into scatter-gather list */
drivers/media/video/omap/omap24xxcam-vbq.c new file +16
-0+ vb->dma.sglist[i].page = page; + vb->dma.sglist[i].length = (PAGE_SIZE << order); + vb->dma.sglen++; + i++; + + alloc_size = (PAGE_SIZE << order); + +/* clear pages before giving them to user space */ +memset (page_address (page),0 , alloc_size); + +/* mark allocated pages reserved */ +do { +SetPageReserved (page++); + }while (alloc_size -=PAGE_SIZE ); + } +/* REVISIT: not fully correct to assign nr_pages == sglen but video-buf
drivers/media/video/omap/omap24xxcam-vbq.c new file +43
-0+* is passing nr_pages for e.g. unmap_sg calls */ + vb->dma.nr_pages = vb->dma.sglen; + vb->dma.direction =PCI_DMA_FROMDEVICE ; + +return 0 ; + +out: +omap24xxcam_vbq_free_mmap_buffer (vb); +return err; +} + +int +omap24xxcam_vbq_alloc_mmap_buffers (struct videobuf_queue *vbq, +unsigned int count) +{ +int i, err =0 ; + +mutex_lock (&vbq->lock); +for (i =0 ; i < count; i++) { + err =omap24xxcam_vbq_alloc_mmap_buffer (vbq->bufs[i]); +if (err) + goto out; +printk ("%s: sglen is %d for buffer %d\n" , + __FUNCTION__, vbq->bufs[i]->dma.sglen, i); + } +mutex_unlock (&vbq->lock); + +return 0 ; +out: +while (i) { + i--; +omap24xxcam_vbq_free_mmap_buffer (vbq->bufs[i]); + } +mutex_unlock (&vbq->lock); + +return err; +} + +/* This routine is called from interrupt context when a scatter-gather DMA +* transfer of a videobuf_buffer completes. +*/ +void +omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma, unsigned longcsr,
drivers/media/video/omap/omap24xxcam-vbq.c new file +30
-0+ void *arg) +{ +struct omap24xxcam_device *cam = + container_of(sgdma, struct omap24xxcam_device, sgdma); +struct omap24xxcam_capture *capture = &cam->capture; +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 ; + +DBG ; + +spin_lock (&capture->lock); + +do_gettimeofday (&vb->ts); + vb->field_count = capture->field_count; + capture->field_count +=2 ; +if (csr & csr_error) { + vb->state =STATE_ERROR ; +printk (KERN_INFO "%s: scheduling camera reset, csr 0x%lx\n" , + __FUNCTION__, csr); +omap24xxcam_camera_reset_schedule (cam); + }else + vb->state =STATE_DONE ; +wake_up (&vb->done); +spin_unlock (&capture->lock); +} + +void +omap24xxcam_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer*vb)
drivers/media/video/omap/omap24xxcam-vbq.c new file +32
-0+{ +struct videobuf_dmabuf *dma = &vb->dma; +DBG ; + +videobuf_waiton (vb,0 ,0 ); +if (vb->memory ==V4L2_MEMORY_MMAP ) { +dma_unmap_sg (vbq->dev, dma->sglist, dma->sglen, + dma->direction); + dma->direction =PCI_DMA_NONE ; +omap24xxcam_vbq_free_mmap_buffer (vb); + }else { +videobuf_dma_unmap (vbq, &vb->dma); +videobuf_dma_free (&vb->dma); + } + + vb->state =STATE_NEEDS_INIT ; +} + +/* Limit the number of available kernel image capture buffers based on the +* number requested, the currently selected image size, and the maximum +* amount of memory permitted for kernel capture buffers. +*/ +static int +omap24xxcam_vbq_setup (struct videobuf_queue *vbq,unsigned int *cnt, +unsigned int *size) +{ +struct omap24xxcam_device *cam = vbq->priv_data; + +DBG ; + +if (*cnt <=0 ) + *cnt =VIDEO_MAX_FRAME ;/* supply a default number of buffers */
drivers/media/video/omap/omap24xxcam-vbq.c new file +18
-0+ +if (*cnt >VIDEO_MAX_FRAME ) + *cnt =VIDEO_MAX_FRAME ; + +spin_lock (&cam->img.img_lock); + + *size = cam->img.pix.sizeimage; + +spin_unlock (&cam->img.img_lock); + +while (*size * *cnt > cam->capture_mem) + (*cnt)--; + +return 0 ; +} + +static int +omap24xxcam_dma_iolock(struct videobuf_queue* vbq, struct videobuf_dmabuf*dma)
drivers/media/video/omap/omap24xxcam-vbq.c new file +5
-0+{ +int err =0 ; + + dma->direction =PCI_DMA_FROMDEVICE ; +if (!dma_map_sg (vbq->dev, dma->sglist, dma->sglen, dma->direction)){
drivers/media/video/omap/omap24xxcam-vbq.c new file +11
-0+kfree (dma->sglist); + dma->sglist =NULL ; + dma->sglen =0 ; + err = -EIO ; + } + +return err; +} + +static int +omap24xxcam_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer*vb,
drivers/media/video/omap/omap24xxcam-vbq.c new file +19
-0+ enum v4l2_field field) +{ +struct omap24xxcam_device *cam = vbq->priv_data; +int err =0 ; + +DBG ; + +spin_lock (&cam->img.img_lock); + +if (vb->baddr) { +/* This is a userspace buffer. */ +if (cam->img.pix.sizeimage > vb->bsize) { +/* The buffer isn't big enough. */ + err = -EINVAL ; + }else + vb->size = cam->img.pix.sizeimage; + }else if (!vb->baddr) { +if (vb->state !=STATE_NEEDS_INIT ) { +/* We have a kernel bounce buffer that has already been
drivers/media/video/omap/omap24xxcam-vbq.c new file +4
-0+* allocated. +*/ +if (cam->img.pix.sizeimage > vb->size) { +/* The image size has been changed to a larger
+ * size since this buffer was allocated, so
wedrivers/media/video/omap/omap24xxcam-vbq.c new file +9
-0+* need to free and reallocate it. +*/ +spin_unlock (&cam->img.img_lock); +omap24xxcam_vbq_release (vbq, vb); +spin_lock (&cam->img.img_lock); + vb->size = cam->img.pix.sizeimage; + } + }else { +/* We need to allocate a new kernel bounce buffer. */
drivers/media/video/omap/omap24xxcam-vbq.c new file +16
-0+ vb->size = cam->img.pix.sizeimage; + } + } + + vb->width = cam->img.pix.width; + vb->height = cam->img.pix.height; + vb->field = field; + +spin_unlock (&cam->img.img_lock); + +if (err) +return err; + +if (vb->state ==STATE_NEEDS_INIT ) { +if (vb->memory ==V4L2_MEMORY_MMAP ) +/* we have built the scatter-gather list by ourself so
drivers/media/video/omap/omap24xxcam-vbq.c new file +16
-0+* do the scatter-gather mapping as well */ + err =omap24xxcam_dma_iolock (vbq, &vb->dma); + else + err =videobuf_iolock (vbq, vb,NULL ); + } + +if (!err) + vb->state =STATE_PREPARED ; +else +omap24xxcam_vbq_release (vbq, vb); + +return err; +} + +static void +omap24xxcam_vbq_queue(struct videobuf_queue *vbq, struct videobuf_buffer*vb)
drivers/media/video/omap/omap24xxcam-vbq.c new file +9
-0+{ +struct omap24xxcam_device *cam = vbq->priv_data; +enum videobuf_state state = vb->state; +int err; + +DBG ; + + vb->state =STATE_QUEUED ; + err = omap24xxcam_sgdma_queue(&cam->sgdma, vb->dma.sglist, vb->dma.sglen,
drivers/media/video/omap/omap24xxcam-vbq.c new file +4
-0+ cam->img.pix.sizeimage, + omap24xxcam_vbq_complete, vb); +if (err) { +/* Oops. We're not supposed to get any errors here. The only
+ * way we could get an error is if we ran out of
scatter-gatherdrivers/media/video/omap/omap24xxcam-vbq.c new file +17
-0+* DMA slots, but we are supposed to have at least as many +* scatter-gather DMA slots as video buffers so that can't +* happen. +*/ + printk(KERN_DEBUG CAM_NAME + ": Failed to queue a video buffer for DMA!\n"); + vb->state = state; + } +} + +struct videobuf_queue_ops omap24xxcam_vbq_ops = { + .buf_setup = omap24xxcam_vbq_setup, + .buf_prepare = omap24xxcam_vbq_prepare, + .buf_queue = omap24xxcam_vbq_queue, + .buf_release = omap24xxcam_vbq_release, +}; +drivers/media/video/omap/omap24xxcam.c new file +18
-0@@ -0,0 +1,1216 @@ +/* +* drivers/media/video/omap/omap24xxcam.c +* +* Video-for-Linux (Version 2) camera capture driver for +* the OMAP24xx camera controller. +* +* Author: Andy Lowe ([email protected]) +* +* Copyright (C) 2004 MontaVista Software, Inc. +* Copyright (C) 2004 Texas Instruments. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +* History: +* 2005/nov - David Cohen <[email protected]> +* Updated the driver for the Linux Device Model and new version of V4L2.
+ */drivers/media/video/omap/omap24xxcam.c new file +50
-0+ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/interrupt.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/i2c.h> +#include <linux/videodev2.h> +#include <linux/pci.h> /* needed for videobufs */ +#include <linux/dma-mapping.h> +#include <linux/device.h> +#include <linux/input.h> +#include <linux/version.h> +#include <linux/platform_device.h> +#include <linux/clk.h> + +#include <media/video-buf.h> +#include <media/v4l2-common.h> + +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/scatterlist.h> +#include <asm/irq.h> +#include <asm/semaphore.h> +#include <asm/processor.h> + +#include <asm/arch/clock.h> + +#include "omap24xxcam.h" +#include "omap24xxcam-dma.h" + +#include "sensor_if.h" + +/* configuration macros */ + +//#define DEBUG_CAM +#ifdef DEBUG_CAM +#define DBG printk(KERN_INFO CAM_NAME ": %s\n", __FUNCTION__) +#define DBG_END printk(KERN_INFO CAM_NAME ": %s END!\n",
__FUNCTION__)
+#defineDBG_MID(x)printk(KERN_INFOCAM_NAME": %s - %d\n",__FUNCTION__, x)drivers/media/video/omap/omap24xxcam.c new file +22
-0+#else +#define DBG +#define DBG_END +#define DBG_MID (x) +#endif + +#define RESET_TIMEOUT (HZ / 5) + +struct omap_camera omap24xxcam_camera = { + .sensor_register = &omap24xxcam_sensor_register, + .sensor_unregister = &omap24xxcam_sensor_unregister, + .sensor_reset = &omap24xxcam_sensor_reset_schedule, +}; + +struct omap24xxcam_device *camera_module; + +static struct platform_device omap24xxcam_dev; + +static int omap24xxcam_remove (struct platform_device *pdev); + +/* module parameters */ +static int video_nr =-1 ;/* video device minor (-1 ==> auto assign) */
drivers/media/video/omap/omap24xxcam.c new file +6
-1+/* Maximum amount of memory to use for capture buffers. +* Default is 4800KB, enough to double-buffer SXGA. +*/ +static int capture_mem =1280 *960 *2 *2 ; + +/* --------------------------------------------------------------------------*/
drivers/media/video/omap/omap24xxcam.c new file +2
-0+ +/* Initialize the camera subsystem (camera core, camera DMA, and camera MMU) */
drivers/media/video/omap/omap24xxcam.c new file +69
-0+static void omap24xxcam_reset (const struct omap24xxcam_device *cam) +{ +unsigned long timeout; + +DBG ; + +omap24xxcam_reg_out (cam->mmio_base, +CAM_SYSCONFIG , +CAM_SYSCONFIG_SOFTRESET ); + +/* wait for reset to complete */ + timeout = jiffies +RESET_TIMEOUT ; + +while (!(omap24xxcam_reg_in (cam->mmio_base,CAM_SYSSTATUS ) + &CAM_SYSSTATUS_RESETDONE ) + &&time_before (jiffies, timeout)) { +msleep (1 ); + } + +if (!(omap24xxcam_reg_in (cam->mmio_base,CAM_SYSSTATUS ) + &CAM_SYSSTATUS_RESETDONE )) { + printk(KERN_WARNING CAM_NAME + ": timeout waiting for camera subsystem reset\n"); + } + +/* set the camera subsystem autoidle bit */ +omap24xxcam_reg_out (cam->mmio_base,CAM_SYSCONFIG , +CAM_SYSCONFIG_AUTOIDLE ); + +/* initialize the camera MMU */ +/* set the camera MMU autoidle bit */ +omap24xxcam_reg_out (cam->mmio_base, +CAMMMU_REG_OFFSET +CAMMMU_SYSCONFIG , +CAMMMU_SYSCONFIG_AUTOIDLE ); +} + +/* This gets called whenever a DMA transfer is stalled */ +static void omap24xxcam_reset_timer (unsigned long data) +{ +struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data; + +printk ("%s()\n" , __FUNCTION__); + +/* +* Sensor reset must not be called from +* interrupt context as it may sleep +*/ +omap24xxcam_camera_reset_schedule (cam); +} + +void omap24xxcam_camera_reset_work (void * data) +{ +struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data; + +/* Disable and reset the camera interface. */ +omap24xxcam_core_disable (&cam->core); + +/* Stop the DMA controller and frame sync scatter-gather DMA. */ +omap24xxcam_sgdma_disable (&cam->sgdma); + +/* 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
exactlydrivers/media/video/omap/omap24xxcam.c new file +2
-0+* what needs to be reset to recover from a camera interface error, +* maybe we can replace this global reset with something less drastic.
drivers/media/video/omap/omap24xxcam.c new file +7
-0+*/ +omap24xxcam_reset (cam); +omap24xxcam_core_enable (&cam->core); + +if (cam->capture.streaming) { +/* Preview or capture is in progress, so we need to register +* our routine to restart the camera interface the next time a
drivers/media/video/omap/omap24xxcam.c new file +3
-0+* DMA transfer is queued. +*/ + omap24xxcam_dma_notify(&cam->sgdma.dma,
omap24xxcam_core_enable_callback);drivers/media/video/omap/omap24xxcam.c new file +11
-0+ } + +omap24xxcam_sgdma_enable (&cam->sgdma); +} + +void omap24xxcam_camera_reset_schedule (struct omap24xxcam_device *cam) +{ +schedule_work (&cam->camera_reset_work); +} + +static irqreturn_t omap24xxcam_isr(int irq, void *arg, struct pt_regs*regs)
drivers/media/video/omap/omap24xxcam.c new file +21
-0+{ + struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg; + unsigned long irqstatus; + unsigned int irqhandled = 0; + + DBG; + + irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS); + + if (irqstatus & + (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1 + | CAM_IRQSTATUS_DMA_IRQ0)) { + omap24xxcam_dma_isr(&cam->sgdma.dma); + irqhandled = 1; + } + if (irqstatus & CAM_IRQSTATUS_CC_IRQ) { + omap24xxcam_core_isr(&cam->core); + irqhandled = 1; + } + if (irqstatus & CAM_IRQSTATUS_MMU_IRQ) + printk(KERN_ERR CAM_NAME ": Unhandled camera MMUinterrupt!\n");
drivers/media/video/omap/omap24xxcam.c new file +5
-1+ +return IRQ_RETVAL (irqhandled); +} + +/* --------------------------------------------------------------------------*/
drivers/media/video/omap/omap24xxcam.c new file +213
-0+ +static int vidioc_querycap (struct file *file,void *fh, +struct v4l2_capability *cap) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; + +memset (cap,0 ,sizeof (*cap)); +strlcpy (cap->driver,CAM_NAME ,sizeof (cap->driver)); +strlcpy (cap->card, cam->vfd->name,sizeof (cap->card)); + cap->bus_info[0 ] ='\0' ; + cap->version =KERNEL_VERSION (0 ,0 ,0 ); + cap->capabilities = +V4L2_CAP_VIDEO_CAPTURE + |V4L2_CAP_READWRITE + |V4L2_CAP_STREAMING ; + +return 0 ; +} + +static int vidioc_enum_input (struct file *file,void *fh, +struct v4l2_input *inp) +{ +/* default handler assumes 1 video input (the camera) */ +int index = inp->index; + +memset (inp,0 ,sizeof (*inp)); + inp->index = index; + +if (index >0 ) +return -EINVAL ; + +strlcpy (inp->name,"camera" ,sizeof (inp->name)); + inp->type =V4L2_INPUT_TYPE_CAMERA ; + +return 0 ; +} + +static int vidioc_g_input (struct file *file,void *fh,unsigned int *i) +{ + *i =0 ; + +return 0 ; + +} + +static int vidioc_s_input (struct file *file,void *fh,unsigned int i) +{ +if (i >0 ) +return -EINVAL ; + +return 0 ; +} + +static int vidioc_g_fmt_cap (struct file *file,void *fh, +struct v4l2_format *f) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; +struct v4l2_pix_format *pix = &f->fmt.pix; + +memset (pix,0 ,sizeof (*pix)); +spin_lock (&cam->img.img_lock); + *pix = cam->img.pix; +spin_unlock (&cam->img.img_lock); +return 0 ; +} + +static int vidioc_try_fmt_cap (struct file *file,void *fh, +struct v4l2_format *f) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; + +return omap24xxcam_sensor_try_format (cam, &f->fmt.pix); +} + +static int vidioc_s_fmt_cap (struct file *file,void *fh, +struct v4l2_format *f) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; +struct omap24xxcam_capture *capture = &cam->capture; +int err; + +spin_lock (&capture->lock); +if (capture->streaming) { +spin_unlock (&capture->lock); +return -EBUSY ; + } +spin_unlock (&capture->lock); +spin_lock (&cam->img.img_lock); +omap24xxcam_sensor_try_format (cam, &f->fmt.pix); +/* set the new capture format */ + cam->img.pix = f->fmt.pix; +/* adjust the capture frame rate */ + err =omap24xxcam_sensor_set_format (cam, + &cam->img.pix, + &cam->img.cparm.timeperframe, + &cam->core.xclk); +spin_unlock (&cam->img.img_lock); +return err; +} + +static int vidioc_g_parm (struct file *file,void *fh, +struct v4l2_streamparm *a) { +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; + +enum v4l2_buf_type type = a->type; + +memset (a,0 ,sizeof (*a)); + a->type = type; +if (type !=V4L2_BUF_TYPE_VIDEO_CAPTURE ) +return -EINVAL ; +spin_lock (&cam->img.img_lock); + a->parm.capture = cam->img.cparm; +spin_unlock (&cam->img.img_lock); +return 0 ; +} + +static int vidioc_s_parm (struct file *file,void *fh, +struct v4l2_streamparm *a) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; +struct omap24xxcam_capture *capture = &cam->capture; +int err; +struct v4l2_captureparm *cparm = &a->parm.capture; + +if (a->type !=V4L2_BUF_TYPE_VIDEO_CAPTURE ) +return -EINVAL ; +spin_lock (&capture->lock); +if (capture->streaming) { +spin_unlock (&capture->lock); +return -EBUSY ; + } +spin_unlock (&capture->lock); +spin_lock (&cam->img.img_lock); + err =omap24xxcam_sensor_set_format ( + cam, + &cam->img.pix, + &cparm->timeperframe, + &cam->core.xclk); +if (!err) { + cam->img.cparm.capturemode = cparm->capturemode; + cam->img.cparm.timeperframe = + cparm->timeperframe; +spin_unlock (&cam->img.img_lock); + }else { +spin_unlock (&cam->img.img_lock); + } +return 0 ; +} + +static int vidioc_reqbufs (struct file *file,void *fh, +struct v4l2_requestbuffers *b) +{ +struct omap24xxcam_fh *ofh = fh; + +int err =videobuf_reqbufs (&ofh->vbq, b); +if (b->memory ==V4L2_MEMORY_MMAP && !err) { + err =omap24xxcam_vbq_alloc_mmap_buffers (&ofh->vbq, + b->count); +if (err) { +/* REVISIT: is this proper reverse for +* videobuf_reqbufs? */ +videobuf_mmap_free (&ofh->vbq); + } + } +return err; +} + +static int vidioc_querybuf (struct file *file,void *fh, +struct v4l2_buffer *b) +{ +struct omap24xxcam_fh *ofh = fh; + +return videobuf_querybuf (&ofh->vbq, b); +} + +static int vidioc_qbuf (struct file *file,void *fh,struct v4l2_buffer *b) +{ +struct omap24xxcam_fh *ofh = fh; + +return videobuf_qbuf (&ofh->vbq, b); +} + +static int vidioc_dqbuf (struct file *file,void *fh,struct v4l2_buffer *b) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; +struct videobuf_buffer *vb; +int rval; + + rval =videobuf_dqbuf (&ofh->vbq, b, + file->f_flags &O_NONBLOCK ); + +if (rval <0 ) +return rval; + vb = ofh->vbq.bufs[b->index]; + +if (cam->sensor->frame_check) + rval = cam->sensor->frame_check ( + cam->sensor, + &cam->img.pix, + (void *)vb->baddr); + +return rval; + +} + +static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_typei)
drivers/media/video/omap/omap24xxcam.c new file +14
-0+{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; +struct omap24xxcam_capture *capture = &cam->capture; + +spin_lock (&capture->lock); +if (capture->streaming) { +spin_unlock (&capture->lock); +return -EBUSY ; + }else + capture->streaming = file; +spin_unlock (&capture->lock); + + omap24xxcam_dma_notify(&cam->sgdma.dma,
omap24xxcam_core_enable_callback);drivers/media/video/omap/omap24xxcam.c new file +4
-0+return videobuf_streamon (&ofh->vbq); +} + +static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_typei)
drivers/media/video/omap/omap24xxcam.c new file +66
-1+{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; +struct omap24xxcam_capture *capture = &cam->capture; +struct videobuf_queue *q = &ofh->vbq; +int j; +int err; + +/* video-buf lib has trouble to turn off streaming while +any buffer is still in QUEUED state. Let's wait until +all queued buffers are filled. +*/ +for (j =0 ; j <VIDEO_MAX_FRAME ; j++) { +if (NULL == q->bufs[j]) +continue ; +videobuf_waiton (q->bufs[j],0 ,0 ); + } + + err =videobuf_streamoff (q); + +if (err <0 ) +return err; + +spin_lock (&capture->lock); +if (capture->streaming == file) + capture->streaming =NULL ; +spin_unlock (&capture->lock); +return 0 ; +} +static int vidioc_g_ctrl (struct file *file,void *fh, +struct v4l2_control *a) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; + +return cam->sensor->get_control (cam->sensor, a); +} + +static int vidioc_s_ctrl (struct file *file,void *fh, +struct v4l2_control *a) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; + +return cam->sensor->set_control (cam->sensor, a); +} + +static int vidioc_queryctrl (struct file *file,void *fh, +struct v4l2_queryctrl *a) { +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; + +return cam->sensor->query_control (cam->sensor, a); +} + +static int vidioc_enum_fmt_cap (struct file *file,void *fh, +struct v4l2_fmtdesc *f) +{ +struct omap24xxcam_fh *ofh = fh; +struct omap24xxcam_device *cam = ofh->cam; + +return cam->sensor->enum_pixformat (cam->sensor, + f); +} + +/* --------------------------------------------------------------------------*/
drivers/media/video/omap/omap24xxcam.c new file +27
-0+ +/* +* file operations +*/ + +static unsigned +int omap24xxcam_poll (struct file *file,struct poll_table_struct *wait) +{ +struct omap24xxcam_fh *fh = file->private_data; +struct omap24xxcam_device *cam = fh->cam; +struct omap24xxcam_capture *capture = &cam->capture; +struct videobuf_buffer *vb; +enum v4l2_field field; + +DBG ; + +spin_lock (&capture->lock); + +if (capture->streaming == file) { +spin_unlock (&capture->lock); +/* streaming capture */ +if (list_empty (&fh->vbq.stream)) +return POLLERR ; + vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, + stream); + }else if (capture->streaming) { +/* streaming I/O is in progress on another file descriptor */
drivers/media/video/omap/omap24xxcam.c new file +24
-0+spin_unlock (&capture->lock); +return POLLERR ; + }else { +/* read() capture */ +spin_unlock (&capture->lock); +mutex_lock (&fh->vbq.lock); +if (fh->vbq.read_buf ==NULL ) { +/* need to capture a new image */ + fh->vbq.read_buf = +videobuf_alloc (fh->vbq.msize); +if (fh->vbq.read_buf ==NULL ) { +mutex_unlock (&fh->vbq.lock); +return POLLERR ; + } + fh->vbq.read_buf->memory =V4L2_MEMORY_USERPTR ; + field =videobuf_next_field (&fh->vbq); +if (fh->vbq.ops->buf_prepare (&fh->vbq, + fh->vbq.read_buf, + field) !=0 ) { +mutex_unlock (&fh->vbq.lock); +return POLLERR ; + } + + omap24xxcam_dma_notify(&cam->sgdma.dma,
omap24xxcam_core_enable_callback);drivers/media/video/omap/omap24xxcam.c new file +9
-0+ fh->vbq.ops->buf_queue (&fh->vbq, + fh->vbq.read_buf); + fh->vbq.read_off =0 ; + } +mutex_unlock (&fh->vbq.lock); + vb = (struct videobuf_buffer *)fh->vbq.read_buf; + } + + omap24xxcam_dma_notify(&cam->sgdma.dma,
omap24xxcam_core_enable_callback);drivers/media/video/omap/omap24xxcam.c new file +9
-0+poll_wait (file, &vb->done, wait); +if (vb->state ==STATE_DONE || vb->state ==STATE_ERROR ) +return POLLIN |POLLRDNORM ; + +return 0 ; +} + +static ssize_t +omap24xxcam_read(struct file *file, char *data, size_t count, loff_t *ppos)
drivers/media/video/omap/omap24xxcam.c new file +16
-0+{ +struct omap24xxcam_fh *fh = file->private_data; +struct omap24xxcam_device *cam = fh->cam; +struct omap24xxcam_capture *capture = &cam->capture; +int err; + +DBG ; + +spin_lock (&capture->lock); +if (capture->streaming) { +spin_unlock (&capture->lock); +return -EBUSY ; + } +spin_unlock (&capture->lock); + + omap24xxcam_dma_notify(&cam->sgdma.dma,
omap24xxcam_core_enable_callback);drivers/media/video/omap/omap24xxcam.c new file +49
-0+ + err = +videobuf_read_one (&fh->vbq, data, count, ppos, + file->f_flags &O_NONBLOCK ); + +DBG_END ; + +return err; +} + +static int +omap24xxcam_mmap_buffers (struct file *file,struct vm_area_struct *vma) +{ +struct omap24xxcam_fh *fh = file->private_data; +struct videobuf_queue *vbq = &fh->vbq; +struct videobuf_buffer *vb; +unsigned int first, last, size, i, j; +int err =0 ; + +mutex_lock (&vbq->lock); + +/* look for first buffer to map */ +for (first =0 ; first <VIDEO_MAX_FRAME ; first++) { +if (NULL == vbq->bufs[first]) +continue ; +if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory) +continue ; +if (vbq->bufs[first]->boff == (vma->vm_pgoff <<PAGE_SHIFT )) +break ; + } + +/* look for last buffer to map */ +for (size =0 , last = first; last <VIDEO_MAX_FRAME ; last++) { +if (NULL == vbq->bufs[last]) +continue ; +if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory) +continue ; + size += vbq->bufs[last]->bsize; +if (size == (vma->vm_end - vma->vm_start)) +break ; + } + + size =0 ; +for (i = first; i <= last; i++) { + vb = vbq->bufs[i]; +for (j =0 ; j < vb->dma.sglen; j++) { + err = remap_pfn_range(vma, vma->vm_start + size, + page_to_pfn(vb->dma.sglist[j].page), + vb->dma.sglist[j].length,
vma->vm_page_prot);drivers/media/video/omap/omap24xxcam.c new file +19
-0+if (err) + goto out; + size += vb->dma.sglist[j].length; + } + } + +out: +mutex_unlock (&vbq->lock); + +return err; +} + +static int +omap24xxcam_mmap (struct file *file,struct vm_area_struct *vma) +{ +struct omap24xxcam_fh *fh = file->private_data; +int err; + +/* let the video-buf mapper check arguments and set-up structures */
drivers/media/video/omap/omap24xxcam.c
Quoted 10 lines
drivers/media/video/omap/omap24xxcam.c new file +10
-0+ err =videobuf_mmap_mapper (&fh->vbq, vma); +if (err) + goto err1; + + vma->vm_page_prot =pgprot_noncached (vma->vm_page_prot); + +/* do mapping to our allocated buffers */ + err =omap24xxcam_mmap_buffers (file, vma); +if (err) + goto err2;
Same comments of Trilok here, but also please find that videobuf_mmap_mapper() allocates memory. Where is it being released in this case?
Should we call videobuf_mmap_free() in this error case?
drivers/media/video/omap/omap24xxcam.c
Quoted 6 lines
drivers/media/video/omap/omap24xxcam.c new file +6
-0+ +return 0 ; + +err2: +if (vma->vm_private_data) +kfree (vma->vm_private_data);
There is no need of this check, kfree already does it
Quoted 123 lines
drivers/media/video/omap/omap24xxcam.c new file +63
-0+err1: + +return err; +} + +static int omap24xxcam_clock_get (struct omap24xxcam_device *cam) +{ + cam->img.fck =clk_get (0 ,"cam_fck" ); +if (IS_ERR ((cam->img.fck))) { +dev_err (cam->dev,"can't get cam_fck" ); +return PTR_ERR (cam->img.fck); + } + + cam->img.ick =clk_get (0 ,"cam_ick" ); +if (IS_ERR ((cam->img.ick))) { +dev_err (cam->dev,"can't get cam_ick" ); +clk_put (cam->img.fck); +return PTR_ERR (cam->img.ick); + } + +return 0 ; +} + +static void omap24xxcam_clock_put (struct omap24xxcam_device *cam) +{ +if (cam->img.ick ==NULL ) +return ; + +clk_put (cam->img.ick); +clk_put (cam->img.fck); +} + +/* +* Do some sanity check, set clock rate, starts it and +* turn codec audio on +*/ +int omap24xxcam_clock_on (struct omap24xxcam_device *cam) +{ + +clk_enable (cam->img.fck); +clk_enable (cam->img.ick); + +printk (KERN_DEBUG +"FCLK = %d [%d], usecount = %d\n" , + (uint )clk_get_rate (cam->img.fck),CAM_CLOCK , +clk_get_usecount (cam->img.fck)); + +return 0 ; +} + +/* +* Do some sanity check, turn clock off and then turn +* codec audio off +*/ +int omap24xxcam_clock_off(struct omap24xxcam_device *cam) +{ + if (cam->img.ick == NULL) + return 0; + + if (clk_get_usecount(cam->img.fck) > 0) { + if (clk_get_rate(cam->img.fck) != CAM_CLOCK) { + printk(KERN_WARNING + "FCLK for camera should be %d Hz. But is %dHz\n",
+ (uint)clk_get_rate(cam->img.fck),CAM_CLOCK);drivers/media/video/omap/omap24xxcam.c new file +57
-0+ } + +clk_disable (cam->img.fck); +clk_disable (cam->img.ick); + } + +return 0 ; +} + +static int omap24xxcam_release (struct inode *inode,struct file *file) +{ +struct omap24xxcam_fh *fh = file->private_data; +struct omap24xxcam_device *cam = fh->cam; +struct omap24xxcam_capture *capture = &cam->capture; + +DBG ; + +spin_lock (&capture->lock); + +/* stop streaming capture */ +if (capture->streaming == file) { + capture->streaming =NULL ; +spin_unlock (&capture->lock); +videobuf_streamoff (&fh->vbq); +spin_lock (&capture->lock); + } + +/* release read_buf videobuf_buffer struct */ +if (fh->vbq.read_buf) { +omap24xxcam_vbq_release (&fh->vbq, fh->vbq.read_buf); +kfree (fh->vbq.read_buf); + } +spin_unlock (&capture->lock); + +mutex_lock (&cam->mutex); +if (--cam->users ==0 ) { +/* power down the sensor */ +omap24xxcam_core_disable (&cam->core); +omap24xxcam_sgdma_disable (&cam->sgdma); +omap24xxcam_sensor_disable (cam); + } +mutex_unlock (&cam->mutex); + + file->private_data =NULL ; + +module_put (cam->sensor->module); +kfree (fh); + +return 0 ; +} + +static int omap24xxcam_open (struct inode *inode,struct file *file) +{ +int minor =iminor (inode); +struct omap24xxcam_device *cam = camera_module; +struct omap24xxcam_capture *capture = &cam->capture; +struct omap24xxcam_fh *fh;
drivers/media/video/omap/omap24xxcam.c
Quoted 10 lines
drivers/media/video/omap/omap24xxcam.c new file +10
-0+ +DBG ; + +if (!cam || !cam->vfd || (cam->vfd->minor != minor)) +return -ENODEV ; + +if (!try_module_get (cam->sensor->module)) +return -ENODEV ; + + fh =kzalloc (sizeof (struct omap24xxcam_fh ),GFP_KERNEL );
What about sizeof(*fh) ? You can change fh type without caring of changing sizeof() too.
Quoted 175 lines
drivers/media/video/omap/omap24xxcam.c new file +36
-1+ +if (fh ==NULL ) +return -ENOMEM ; + + fh->cam = cam; + file->private_data = fh; + +videobuf_queue_init (&fh->vbq, &omap24xxcam_vbq_ops,NULL , + &capture->lock,V4L2_BUF_TYPE_VIDEO_CAPTURE , +V4L2_FIELD_NONE , +sizeof (struct videobuf_buffer ), cam); + +mutex_lock (&cam->mutex); +if (cam->users ==0 ) { +omap24xxcam_sgdma_enable (&cam->sgdma); +omap24xxcam_sensor_enable (cam); + + } + cam->users++; +mutex_unlock (&cam->mutex); + +return 0 ; +} + +static struct file_operations omap24xxcam_fops = { + .owner =THIS_MODULE , + .llseek = no_llseek, + .read = omap24xxcam_read, + .poll = omap24xxcam_poll, + .ioctl = video_ioctl2, + .mmap = omap24xxcam_mmap, + .open = omap24xxcam_open, + .release = omap24xxcam_release, +}; + +/* --------------------------------------------------------------------------*/
drivers/media/video/omap/omap24xxcam.c new file +2
-0+#ifdef CONFIG_PM +static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_tstate)
drivers/media/video/omap/omap24xxcam.c new file +42
-0+{ +struct omap24xxcam_device *cam =platform_get_drvdata (pdev); + +DBG ; + +mutex_lock (&cam->mutex); +if (cam->users ==0 ) { +mutex_unlock (&cam->mutex); +return 0 ; + } +mutex_unlock (&cam->mutex); + +/* Disable the camera interface. */ +omap24xxcam_core_disable (&cam->core); + +/* Stop the DMA controller and frame sync scatter-gather DMA. */ +omap24xxcam_sgdma_disable (&cam->sgdma); + +/* power down the sensor */ +omap24xxcam_sensor_disable (cam); + +return 0 ; +} +static int omap24xxcam_resume (struct platform_device *pdev) +{ +struct omap24xxcam_device *cam =platform_get_drvdata (pdev); + +DBG ; + +mutex_lock (&cam->mutex); +if (cam->users ==0 ) { +mutex_unlock (&cam->mutex); +return 0 ; + } +mutex_unlock (&cam->mutex); + +/* FIXME: what clocks need to be enabled now? None? */ +omap24xxcam_core_enable (&cam->core); + +if (cam->capture.streaming) { +/* capture was in progress, so we need to register +* our routine to restart the camera interface the next time a
drivers/media/video/omap/omap24xxcam.c new file +3
-0+* DMA transfer is queued. +*/ + omap24xxcam_dma_notify(&cam->sgdma.dma,
omap24xxcam_core_enable_callback);drivers/media/video/omap/omap24xxcam.c new file +87
-0+ } + +/* Restart the scatter-gather DMA queue. */ +omap24xxcam_sgdma_enable (&cam->sgdma); + +/* power-up and re-configure the sensor */ +omap24xxcam_sensor_enable (cam); + +/* camera interface will be enabled through dma_notify function +** automatically when new dma starts +*/ + +return 0 ; +} +#endif /* CONFIG_PM */ + +int omap24xxcam_device_enable (struct omap24xxcam_device *cam) +{ +struct video_device *vfd; +int rval; + +if (cam ==NULL || !cam->camera_block_alive || cam->vfd !=NULL ) +return -EBUSY ; + +/* initialize the video_device struct */ + vfd = cam->vfd =video_device_alloc (); +if (!vfd) { + printk(KERN_ERR CAM_NAME + ": could not allocate video device struct\n"); + rval = -ENOMEM ; + goto err; + } + vfd->release = video_device_release; + +strlcpy (vfd->name,CAM_NAME ,sizeof (vfd->name)); + vfd->type =VID_TYPE_CAPTURE |VID_TYPE_CHROMAKEY ; +/* need to register for a VID_HARDWARE_* ID in videodev.h */ + vfd->hardware =0 ; + vfd->fops = &omap24xxcam_fops; +/* FIXME: need to use the full v4l2 API */ + vfd->priv = camera_module; + vfd->minor =-1 ; + + vfd->vidioc_querycap = &vidioc_querycap; + vfd->vidioc_enum_input = &vidioc_enum_input; + vfd->vidioc_g_input = &vidioc_g_input; + vfd->vidioc_s_input = &vidioc_s_input; + vfd->vidioc_g_fmt_cap = &vidioc_g_fmt_cap; + vfd->vidioc_try_fmt_cap = &vidioc_try_fmt_cap; + vfd->vidioc_s_fmt_cap = &vidioc_s_fmt_cap; + vfd->vidioc_g_parm = &vidioc_g_parm; + vfd->vidioc_s_parm = &vidioc_s_parm; + vfd->vidioc_reqbufs = &vidioc_reqbufs; + vfd->vidioc_querybuf = &vidioc_querybuf; + vfd->vidioc_qbuf = &vidioc_qbuf; + vfd->vidioc_dqbuf = &vidioc_dqbuf; + vfd->vidioc_streamon = &vidioc_streamon; + vfd->vidioc_streamoff = &vidioc_streamoff; + vfd->vidioc_g_ctrl = &vidioc_g_ctrl; + vfd->vidioc_s_ctrl = &vidioc_s_ctrl; + vfd->vidioc_queryctrl = &vidioc_queryctrl; + vfd->vidioc_enum_fmt_cap = &vidioc_enum_fmt_cap; + +/* Enable the xclk output. The sensor may (and does, in the case of +* the OV9640) require an xclk input in order for its initialization +* routine to work. +*/ +/* choose an arbitrary xclk frequency */ +omap24xxcam_core_xclk_set (&cam->core,12000000 ); + + omap24xxcam_camera.priv = cam; + +if ((rval =omap24xxcam_sensor_init (cam))) { + goto err; + } + +if (video_register_device (vfd,VFL_TYPE_GRABBER , video_nr) <0 ) { + printk(KERN_ERR CAM_NAME + ": could not register Video for Linux device\n"); + vfd->minor =-1 ; + rval = -EBUSY ; + goto err; + } + + printk(KERN_INFO CAM_NAME + ": registered device video%d [v4l2]\n", vfd->minor); +
drivers/media/video/omap/omap24xxcam.c
Quoted 10 lines
drivers/media/video/omap/omap24xxcam.c new file +10
-0+return 0 ; + +err: +omap24xxcam_device_disable (cam); + +return rval; +} + +void omap24xxcam_device_disable (struct omap24xxcam_device *cam) +{
You can avoid dereferencing cam->vfd here by caching it in a local variable.
Quoted 11 lines
drivers/media/video/omap/omap24xxcam.c new file +10
-0+omap24xxcam_sensor_exit (cam); + +if (cam->vfd) { +if (cam->vfd->minor ==-1 ) { +/* The device was never registered, so release the +* video_device struct directly. +*/ +video_device_release (cam->vfd); + }else { +/* The unregister function will release the
video_device
drivers/media/video/omap/omap24xxcam.c
Quoted 3 lines
drivers/media/video/omap/omap24xxcam.c new file +3
-0+* struct as well as unregistering it. +*/ +video_unregister_device (cam->vfd);
Are you sure that video_unregister_device() calls video_device_release(cam->vfd) or does kfree(cam->vfd) in its regular path?
drivers/media/video/omap/omap24xxcam.c
Quoted 12 lines
drivers/media/video/omap/omap24xxcam.c new file +12
-0+ } + cam->vfd =NULL ; + } +} + +static int omap24xxcam_probe (struct platform_device *pdev) +{ +struct omap24xxcam_device *cam; +DBG ; + + cam = camera_module =kzalloc (sizeof (struct omap24xxcam_device ), +GFP_KERNEL );
What about sizeof(*cam) ?
Quoted 736 lines
drivers/media/video/omap/omap24xxcam.c new file +10
-0+if (!cam) { + printk(KERN_ERR CAM_NAME ": could not allocate memory\n"); + goto err; + } + cam->dev = &pdev->dev; + +/* initialize the videobuf queue ops */ +spin_lock_init (&cam->capture.lock); + +/* Impose a lower limit on the amount of memory allocated for capture.
drivers/media/video/omap/omap24xxcam.c new file +56
-0+* We require at least enough memory to double-buffer QVGA (300KB). +*/ +if (capture_mem <320 *240 *2 *2 ) + capture_mem =320 *240 *2 *2 ; + cam->capture_mem = capture_mem; + +/* request the mem region for the camera registers */ +if (!request_mem_region (CAM_REG_BASE ,CAM_REG_SIZE ,CAM_NAME )) { + printk(KERN_ERR CAM_NAME + ": cannot reserve camera register I/O region\n"); + goto err; + } + cam->mmio_base_phys =CAM_REG_BASE ; + cam->mmio_size =CAM_REG_SIZE ; + +/* map the region */ + cam->mmio_base = (unsigned long ) +ioremap_nocache (cam->mmio_base_phys, + cam->mmio_size); +if (!cam->mmio_base) { + printk(KERN_ERR CAM_NAME + ": cannot map camera register I/O region\n"); + goto err; + } + +/* initialize the camera interface */ +omap24xxcam_reset (cam); + +init_timer (&cam->sgdma.reset_timer); + cam->sgdma.reset_timer.function = omap24xxcam_reset_timer; + cam->sgdma.reset_timer.data = (unsigned long )cam; +INIT_WORK (&cam->camera_reset_work, + omap24xxcam_camera_reset_work, cam); +INIT_WORK (&cam->sensor_reset_work, + omap24xxcam_sensor_reset_work, cam); + +/* initialize the spinlock used to serialize access to the image +* parameters +*/ +spin_lock_init (&cam->img.img_lock); + +/* initialize the camera interface functional clock frequency */ +omap24xxcam_core_mclk_set (&cam->core,96000000 );/* 96MHz */ +if (omap24xxcam_clock_get (cam) <0 ) + goto err; + +/* initialize the streaming capture parameters */ + cam->img.cparm.readbuffers =1 ; + cam->img.cparm.capability =V4L2_CAP_TIMEPERFRAME ; + +/* select an arbitrary default capture frame rate of 5fps */ + cam->img.cparm.timeperframe.numerator =1 ; + cam->img.cparm.timeperframe.denominator =15 ; + +omap24xxcam_core_init (&cam->core, cam->mmio_base +CC_REG_OFFSET ); + omap24xxcam_sgdma_init(&cam->sgdma, cam->mmio_base +
CAMDMA_REG_OFFSET);drivers/media/video/omap/omap24xxcam.c new file +126
-0+ +/* install the interrupt service routine */ +if (request_irq (INT_24XX_CAM_IRQ , omap24xxcam_isr,IRQF_DISABLED , +CAM_NAME , cam)) { + printk(KERN_ERR CAM_NAME + ": could not install interrupt service routine\n"); + goto err; + } + cam->irq =INT_24XX_CAM_IRQ ; + +/* set driver specific data to use in power management functions */ +platform_set_drvdata (pdev, cam); + +mutex_init (&cam->mutex); + cam->users =0 ; + + cam->camera_block_alive =1 ; + +omap24xxcam_device_enable (cam); + +return 0 ; + +err: +omap24xxcam_remove (&omap24xxcam_dev); +return -ENODEV ; +} + +static int omap24xxcam_remove (struct platform_device *pdev) +{ +struct omap24xxcam_device *cam = camera_module; + +if (!cam) +return 0 ; + +omap24xxcam_device_disable (cam); + +if (cam->irq) { +free_irq (cam->irq, cam); + cam->irq =0 ; + } + +omap24xxcam_sgdma_exit (&cam->sgdma); +omap24xxcam_core_exit (&cam->core); + +omap24xxcam_clock_off (cam); +omap24xxcam_clock_put (cam); + +if (cam->mmio_base) { +iounmap ((void *)cam->mmio_base); + cam->mmio_base =0 ; + } + +if (cam->mmio_base_phys) { +release_mem_region (cam->mmio_base_phys, + cam->mmio_size); + cam->mmio_base_phys =0 ; + } + +kfree (cam); + camera_module =NULL ; + +return 0 ; +} + +static struct platform_driver omap24xxcam_driver = { + .probe = omap24xxcam_probe, + .remove = omap24xxcam_remove, +#ifdef CONFIG_PM + .suspend = omap24xxcam_suspend, + .resume = omap24xxcam_resume, +#else + .suspend =NULL , + .resume =NULL , +#endif + .shutdown =NULL , + .driver = { + .name =CAM_NAME , + }, +}; + +static struct platform_device omap24xxcam_dev = { + .name =CAM_NAME , + .dev = { + .release =NULL , + }, + .id =0 , +}; + +int __init omap24xxcam_init (void ) +{ +int ret; + +DBG ; + + ret =platform_driver_register (&omap24xxcam_driver); +if (ret !=0 ) +return ret; + + ret =platform_device_register (&omap24xxcam_dev); +if (ret !=0 ) { +platform_driver_unregister (&omap24xxcam_driver); +return ret; + } + +return 0 ; +} + +void __exit omap24xxcam_cleanup(void) +{ +DBG ; + +platform_device_unregister (&omap24xxcam_dev); +platform_driver_unregister (&omap24xxcam_driver); + +omap24xxcam_remove (&omap24xxcam_dev); +} + +MODULE_AUTHOR ("MontaVista Software, Inc." ); +MODULE_DESCRIPTION ("OMAP24xx Video for Linux camera driver" ); +MODULE_LICENSE ("GPL" ); +module_param (video_nr, int,0 ); +MODULE_PARM_DESC (video_nr, +"Minor number for video device (-1 ==> auto assign)" ); +module_param (capture_mem, int,0 ); +MODULE_PARM_DESC(capture_mem, + "Maximum amount of memory for capture buffers (default4800KB)");
drivers/media/video/omap/omap24xxcam.c new file +3
-0+ +module_init (omap24xxcam_init); +module_exit (omap24xxcam_cleanup);drivers/media/video/omap/omap24xxcam.h new file +28
-0@@ -0,0 +1,659 @@ +/* +* drivers/media/video/omap24xxcam.h +* +* Video-for-Linux (Version 2) camera capture driver for +* the OMAP24xx camera controller. +* +* Author: Andy Lowe ([email protected]) +* +* Copyright (C) 2004 MontaVista Software, Inc. +* Copyright (C) 2004 Texas Instruments. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +*/ + +#ifndef OMAP24XXCAM_H +#define OMAP24XXCAM_H + +#include "sensor_if.h" + +//#define DEBUG_CAM + +#define CAM_NAME "omap24xxcam" + +#ifdef DEBUG_CAM +#define DBG printk(KERN_INFO CAM_NAME ": %s\n", __FUNCTION__) +#define DBG_END printk(KERN_INFO CAM_NAME ": %s END!\n",
__FUNCTION__)
+#defineDBG_MID(x)printk(KERN_INFOCAM_NAME": %s - %d\n",__FUNCTION__, x)drivers/media/video/omap/omap24xxcam.h new file +284
-0+#else +#define DBG +#define DBG_END +#define DBG_MID (x) +#endif + +#define CAM_CLOCK 96000000 + +/* physical memory map definitions */ +/* camera subsystem */ +#define CAM_REG_BASE 0x48052000 +#define CAM_REG_SIZE 0x00001000 +/* camera core */ +#define CC_REG_OFFSET 0x00000400 +/* camera DMA */ +#define CAMDMA_REG_OFFSET 0x00000800 +/* camera MMU */ +#define CAMMMU_REG_OFFSET 0x00000C00 + +/* define camera subsystem register offsets */ +#define CAM_REVISION 0x000 +#define CAM_SYSCONFIG 0x010 +#define CAM_SYSSTATUS 0x014 +#define CAM_IRQSTATUS 0x018 +#define CAM_GPO 0x040 +#define CAM_GPI 0x050 + +/* define camera core register offsets */ +#define CC_REVISION 0x000 +#define CC_SYSCONFIG 0x010 +#define CC_SYSSTATUS 0x014 +#define CC_IRQSTATUS 0x018 +#define CC_IRQENABLE 0x01C +#define CC_CTRL 0x040 +#define CC_CTRL_DMA 0x044 +#define CC_CTRL_XCLK 0x048 +#define CC_FIFODATA 0x04C +#define CC_TEST 0x050 +#define CC_GENPAR 0x054 +#define CC_CCPFSCR 0x058 +#define CC_CCPFECR 0x05C +#define CC_CCPLSCR 0x060 +#define CC_CCPLECR 0x064 +#define CC_CCPDFR 0x068 + +/* define camera dma register offsets */ +#define CAMDMA_REVISION 0x000 +#define CAMDMA_IRQSTATUS_L0 0x008 +#define CAMDMA_IRQSTATUS_L1 0x00C +#define CAMDMA_IRQSTATUS_L2 0x010 +#define CAMDMA_IRQSTATUS_L3 0x014 +#define CAMDMA_IRQENABLE_L0 0x018 +#define CAMDMA_IRQENABLE_L1 0x01C +#define CAMDMA_IRQENABLE_L2 0x020 +#define CAMDMA_IRQENABLE_L3 0x024 +#define CAMDMA_SYSSTATUS 0x028 +#define CAMDMA_OCP_SYSCONFIG 0x02C +#define CAMDMA_CAPS_0 0x064 +#define CAMDMA_CAPS_2 0x06C +#define CAMDMA_CAPS_3 0x070 +#define CAMDMA_CAPS_4 0x074 +#define CAMDMA_GCR 0x078 +#define CAMDMA_CCR (n) (0x080 + (n)*0x60) +#define CAMDMA_CLNK_CTRL (n) (0x084 + (n)*0x60) +#define CAMDMA_CICR (n) (0x088 + (n)*0x60) +#define CAMDMA_CSR (n) (0x08C + (n)*0x60) +#define CAMDMA_CSDP (n) (0x090 + (n)*0x60) +#define CAMDMA_CEN (n) (0x094 + (n)*0x60) +#define CAMDMA_CFN (n) (0x098 + (n)*0x60) +#define CAMDMA_CSSA (n) (0x09C + (n)*0x60) +#define CAMDMA_CDSA (n) (0x0A0 + (n)*0x60) +#define CAMDMA_CSEI (n) (0x0A4 + (n)*0x60) +#define CAMDMA_CSFI (n) (0x0A8 + (n)*0x60) +#define CAMDMA_CDEI (n) (0x0AC + (n)*0x60) +#define CAMDMA_CDFI (n) (0x0B0 + (n)*0x60) +#define CAMDMA_CSAC (n) (0x0B4 + (n)*0x60) +#define CAMDMA_CDAC (n) (0x0B8 + (n)*0x60) +#define CAMDMA_CCEN (n) (0x0BC + (n)*0x60) +#define CAMDMA_CCFN (n) (0x0C0 + (n)*0x60) +#define CAMDMA_COLOR (n) (0x0C4 + (n)*0x60) + +/* define camera mmu register offsets */ +#define CAMMMU_REVISION 0x000 +#define CAMMMU_SYSCONFIG 0x010 +#define CAMMMU_SYSSTATUS 0x014 +#define CAMMMU_IRQSTATUS 0x018 +#define CAMMMU_IRQENABLE 0x01C +#define CAMMMU_WALKING_ST 0x040Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
0))
drivers/media/video/omap/omap24xxcam.h new file +99
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
DMA request */
+/*NUM_CAMDMA_CHANNELSis the number of logical channels provided by the camera
+ * DMA controller.
+ */drivers/media/video/omap/omap24xxcam.h new file +2
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
queued.
+ * We need it to be 2 greater than the maximum number of video frames so that
+ * we can use 2 slots for overlay while still havingVIDEO_MAX_FRAMEslots left
+ * for streaming.
+ */drivers/media/video/omap/omap24xxcam.h new file +19
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
due to page alignment) */
+ intqueued_sglist; /* number of sglist entries queued for DMA
*/drivers/media/video/omap/omap24xxcam.h new file +19
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
when
drivers/media/video/omap/omap24xxcam.h new file +25
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
*/
drivers/media/video/omap/omap24xxcam.h new file +6
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
for
drivers/media/video/omap/omap24xxcam.h new file +10
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
the
drivers/media/video/omap/omap24xxcam.h new file +15
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Quoted 1 line
[Message clipped]
Cheers,
André
-------------------------------------------------------
Part of the diff is not shown here. View the raw message.