2006-11-04 09:25:53 -03:00
/*
* A driver for the CMOS camera controller in the Marvell 88 ALP01 " cafe "
* multifunction chip . Currently works with the Omnivision OV7670
* sensor .
*
2007-10-23 17:31:36 -03:00
* The data sheet for this device can be found at :
* http : //www.marvell.com/products/pcconn/88ALP01.jsp
*
2006-11-04 09:25:53 -03:00
* Copyright 2006 One Laptop Per Child Association , Inc .
2007-03-22 19:44:17 -03:00
* Copyright 2006 - 7 Jonathan Corbet < corbet @ lwn . net >
2006-11-04 09:25:53 -03:00
*
* Written by Jonathan Corbet , corbet @ lwn . net .
*
2009-03-18 13:31:56 -03:00
* v4l2_device / v4l2_subdev conversion by :
* Copyright ( C ) 2009 Hans Verkuil < hverkuil @ xs4all . nl >
*
* Note : this conversion is untested ! Please contact the linux - media
* mailinglist if you can test this , together with the test results .
*
2006-11-04 09:25:53 -03:00
* This file may be distributed under the terms of the GNU General
* Public License , version 2.
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/fs.h>
2008-09-03 02:15:39 -03:00
# include <linux/mm.h>
2006-11-04 09:25:53 -03:00
# include <linux/pci.h>
# include <linux/i2c.h>
# include <linux/interrupt.h>
# include <linux/spinlock.h>
# include <linux/videodev2.h>
2009-03-18 13:13:09 -03:00
# include <media/v4l2-device.h>
2008-07-20 08:12:02 -03:00
# include <media/v4l2-ioctl.h>
2007-04-27 12:31:08 -03:00
# include <media/v4l2-chip-ident.h>
2006-11-04 09:25:53 -03:00
# include <linux/device.h>
# include <linux/wait.h>
# include <linux/list.h>
# include <linux/dma-mapping.h>
# include <linux/delay.h>
# include <linux/jiffies.h>
# include <linux/vmalloc.h>
# include <asm/uaccess.h>
# include <asm/io.h>
# include "cafe_ccic-regs.h"
2007-03-25 11:36:28 -03:00
# define CAFE_VERSION 0x000002
2006-11-04 09:25:53 -03:00
/*
* Parameters .
*/
MODULE_AUTHOR ( " Jonathan Corbet <corbet@lwn.net> " ) ;
MODULE_DESCRIPTION ( " Marvell 88ALP01 CMOS Camera Controller driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_SUPPORTED_DEVICE ( " Video " ) ;
/*
* Internal DMA buffer management . Since the controller cannot do S / G I / O ,
* we must have physically contiguous buffers to bring frames into .
* These parameters control how many buffers we use , whether we
* allocate them at load time ( better chance of success , but nails down
* memory ) or when somebody tries to use the camera ( riskier ) , and ,
* for load - time allocation , how big they should be .
*
* The controller can cycle through three buffers . We could use
* more by flipping pointers around , but it probably makes little
* sense .
*/
# define MAX_DMA_BUFS 3
2008-04-22 14:41:48 -03:00
static int alloc_bufs_at_read ;
2007-09-19 02:44:18 -03:00
module_param ( alloc_bufs_at_read , bool , 0444 ) ;
MODULE_PARM_DESC ( alloc_bufs_at_read ,
" Non-zero value causes DMA buffers to be allocated when the "
" video capture device is read, rather than at module load "
" time. This saves memory, but decreases the chances of "
" successfully getting those buffers. " ) ;
2006-11-04 09:25:53 -03:00
static int n_dma_bufs = 3 ;
module_param ( n_dma_bufs , uint , 0644 ) ;
MODULE_PARM_DESC ( n_dma_bufs ,
" The number of DMA buffers to allocate. Can be either two "
" (saves memory, makes timing tighter) or three. " ) ;
static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2 ; /* Worst case */
module_param ( dma_buf_size , uint , 0444 ) ;
MODULE_PARM_DESC ( dma_buf_size ,
" The size of the allocated DMA buffers. If actual operating "
" parameters require larger buffers, an attempt to reallocate "
" will be made. " ) ;
static int min_buffers = 1 ;
module_param ( min_buffers , uint , 0644 ) ;
MODULE_PARM_DESC ( min_buffers ,
" The minimum number of streaming I/O buffers we are willing "
" to work with. " ) ;
static int max_buffers = 10 ;
module_param ( max_buffers , uint , 0644 ) ;
MODULE_PARM_DESC ( max_buffers ,
" The maximum number of streaming I/O buffers an application "
" will be allowed to allocate. These buffers are big and live "
" in vmalloc space. " ) ;
2008-04-22 14:41:48 -03:00
static int flip ;
2006-11-04 09:25:53 -03:00
module_param ( flip , bool , 0444 ) ;
MODULE_PARM_DESC ( flip ,
" If set, the sensor will be instructed to flip the image "
" vertically. " ) ;
enum cafe_state {
S_NOTREADY , /* Not yet initialized */
S_IDLE , /* Just hanging around */
S_FLAKED , /* Some sort of problem */
S_SINGLEREAD , /* In read() */
S_SPECREAD , /* Speculative read (for future read()) */
S_STREAMING /* Streaming data */
} ;
/*
* Tracking of streaming I / O buffers .
*/
struct cafe_sio_buffer {
struct list_head list ;
struct v4l2_buffer v4lbuf ;
char * buffer ; /* Where it lives in kernel space */
int mapcount ;
struct cafe_camera * cam ;
} ;
/*
* A description of one of our devices .
* Locking : controlled by s_mutex . Certain fields , however , require
* the dev_lock spinlock ; they are marked as such by comments .
* dev_lock is also required for access to device registers .
*/
struct cafe_camera
{
2009-03-18 13:13:09 -03:00
struct v4l2_device v4l2_dev ;
2006-11-04 09:25:53 -03:00
enum cafe_state state ;
unsigned long flags ; /* Buffer status, mainly (dev_lock) */
int users ; /* How many open FDs */
struct file * owner ; /* Who has data access (v4l2) */
/*
* Subsystem structures .
*/
struct pci_dev * pdev ;
2009-03-18 13:13:09 -03:00
struct video_device vdev ;
2006-11-04 09:25:53 -03:00
struct i2c_adapter i2c_adapter ;
2009-03-18 13:16:44 -03:00
struct v4l2_subdev * sensor ;
unsigned short sensor_addr ;
2006-11-04 09:25:53 -03:00
unsigned char __iomem * regs ;
struct list_head dev_list ; /* link to other devices */
/* DMA buffers */
unsigned int nbufs ; /* How many are alloc'd */
int next_buf ; /* Next to consume (dev_lock) */
unsigned int dma_buf_size ; /* allocated size */
void * dma_bufs [ MAX_DMA_BUFS ] ; /* Internal buffer addresses */
dma_addr_t dma_handles [ MAX_DMA_BUFS ] ; /* Buffer bus addresses */
unsigned int specframes ; /* Unconsumed spec frames (dev_lock) */
unsigned int sequence ; /* Frame sequence number */
unsigned int buf_seq [ MAX_DMA_BUFS ] ; /* Sequence for individual buffers */
/* Streaming buffers */
unsigned int n_sbufs ; /* How many we have */
struct cafe_sio_buffer * sb_bufs ; /* The array of housekeeping structs */
struct list_head sb_avail ; /* Available for data (we own) (dev_lock) */
struct list_head sb_full ; /* With data (user space owns) (dev_lock) */
struct tasklet_struct s_tasklet ;
/* Current operating parameters */
2007-04-27 12:31:08 -03:00
u32 sensor_type ; /* Currently ov7670 only */
2006-11-04 09:25:53 -03:00
struct v4l2_pix_format pix_format ;
/* Locks */
struct mutex s_mutex ; /* Access to this structure */
spinlock_t dev_lock ; /* Access to device */
/* Misc */
wait_queue_head_t smbus_wait ; /* Waiting on i2c events */
wait_queue_head_t iowait ; /* Waiting on frame data */
} ;
/*
* Status flags . Always manipulated with bit operations .
*/
# define CF_BUF0_VALID 0 /* Buffers valid - first three */
# define CF_BUF1_VALID 1
# define CF_BUF2_VALID 2
# define CF_DMA_ACTIVE 3 /* A frame is incoming */
# define CF_CONFIG_NEEDED 4 /* Must configure hardware */
2009-03-18 13:16:44 -03:00
# define sensor_call(cam, o, f, args...) \
v4l2_subdev_call ( cam - > sensor , o , f , # # args )
2006-11-04 09:25:53 -03:00
2009-03-18 13:13:09 -03:00
static inline struct cafe_camera * to_cam ( struct v4l2_device * dev )
{
return container_of ( dev , struct cafe_camera , v4l2_dev ) ;
}
2006-11-04 09:25:53 -03:00
/*
* Start over with DMA buffers - dev_lock needed .
*/
static void cafe_reset_buffers ( struct cafe_camera * cam )
{
int i ;
cam - > next_buf = - 1 ;
for ( i = 0 ; i < cam - > nbufs ; i + + )
clear_bit ( i , & cam - > flags ) ;
cam - > specframes = 0 ;
}
static inline int cafe_needs_config ( struct cafe_camera * cam )
{
return test_bit ( CF_CONFIG_NEEDED , & cam - > flags ) ;
}
static void cafe_set_config_needed ( struct cafe_camera * cam , int needed )
{
if ( needed )
set_bit ( CF_CONFIG_NEEDED , & cam - > flags ) ;
else
clear_bit ( CF_CONFIG_NEEDED , & cam - > flags ) ;
}
/*
* Debugging and related .
*/
# define cam_err(cam, fmt, arg...) \
dev_err ( & ( cam ) - > pdev - > dev , fmt , # # arg ) ;
# define cam_warn(cam, fmt, arg...) \
dev_warn ( & ( cam ) - > pdev - > dev , fmt , # # arg ) ;
# define cam_dbg(cam, fmt, arg...) \
dev_dbg ( & ( cam ) - > pdev - > dev , fmt , # # arg ) ;
/* ---------------------------------------------------------------------*/
/*
* Device register I / O
*/
static inline void cafe_reg_write ( struct cafe_camera * cam , unsigned int reg ,
unsigned int val )
{
iowrite32 ( val , cam - > regs + reg ) ;
}
static inline unsigned int cafe_reg_read ( struct cafe_camera * cam ,
unsigned int reg )
{
return ioread32 ( cam - > regs + reg ) ;
}
static inline void cafe_reg_write_mask ( struct cafe_camera * cam , unsigned int reg ,
unsigned int val , unsigned int mask )
{
unsigned int v = cafe_reg_read ( cam , reg ) ;
v = ( v & ~ mask ) | ( val & mask ) ;
cafe_reg_write ( cam , reg , v ) ;
}
static inline void cafe_reg_clear_bit ( struct cafe_camera * cam ,
unsigned int reg , unsigned int val )
{
cafe_reg_write_mask ( cam , reg , 0 , val ) ;
}
static inline void cafe_reg_set_bit ( struct cafe_camera * cam ,
unsigned int reg , unsigned int val )
{
cafe_reg_write_mask ( cam , reg , val , val ) ;
}
/* -------------------------------------------------------------------- */
/*
* The I2C / SMBUS interface to the camera itself starts here . The
* controller handles SMBUS itself , presenting a relatively simple register
* interface ; all we have to do is to tell it where to route the data .
*/
# define CAFE_SMBUS_TIMEOUT (HZ) /* generous */
static int cafe_smbus_write_done ( struct cafe_camera * cam )
{
unsigned long flags ;
int c1 ;
/*
* We must delay after the interrupt , or the controller gets confused
* and never does give us good status . Fortunately , we don ' t do this
* often .
*/
udelay ( 20 ) ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
c1 = cafe_reg_read ( cam , REG_TWSIC1 ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
return ( c1 & ( TWSIC1_WSTAT | TWSIC1_ERROR ) ) ! = TWSIC1_WSTAT ;
}
static int cafe_smbus_write_data ( struct cafe_camera * cam ,
u16 addr , u8 command , u8 value )
{
unsigned int rval ;
unsigned long flags ;
2007-08-17 01:02:33 -03:00
DEFINE_WAIT ( the_wait ) ;
2006-11-04 09:25:53 -03:00
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
rval = TWSIC0_EN | ( ( addr < < TWSIC0_SID_SHIFT ) & TWSIC0_SID ) ;
rval | = TWSIC0_OVMAGIC ; /* Make OV sensors work */
/*
* Marvell sez set clkdiv to all 1 ' s for now .
*/
rval | = TWSIC0_CLKDIV ;
cafe_reg_write ( cam , REG_TWSIC0 , rval ) ;
( void ) cafe_reg_read ( cam , REG_TWSIC1 ) ; /* force write */
rval = value | ( ( command < < TWSIC1_ADDR_SHIFT ) & TWSIC1_ADDR ) ;
cafe_reg_write ( cam , REG_TWSIC1 , rval ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
2007-08-17 01:02:33 -03:00
/*
* Time to wait for the write to complete . THIS IS A RACY
* WAY TO DO IT , but the sad fact is that reading the TWSIC1
* register too quickly after starting the operation sends
* the device into a place that may be kinder and better , but
* which is absolutely useless for controlling the sensor . In
* practice we have plenty of time to get into our sleep state
* before the interrupt hits , and the worst case is that we
* time out and then see that things completed , so this seems
* the best way for now .
*/
do {
prepare_to_wait ( & cam - > smbus_wait , & the_wait ,
TASK_UNINTERRUPTIBLE ) ;
schedule_timeout ( 1 ) ; /* even 1 jiffy is too long */
finish_wait ( & cam - > smbus_wait , & the_wait ) ;
} while ( ! cafe_smbus_write_done ( cam ) ) ;
# ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT
2006-11-04 09:25:53 -03:00
wait_event_timeout ( cam - > smbus_wait , cafe_smbus_write_done ( cam ) ,
CAFE_SMBUS_TIMEOUT ) ;
2007-08-17 01:02:33 -03:00
# endif
2006-11-04 09:25:53 -03:00
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
rval = cafe_reg_read ( cam , REG_TWSIC1 ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
if ( rval & TWSIC1_WSTAT ) {
cam_err ( cam , " SMBUS write (%02x/%02x/%02x) timed out \n " , addr ,
command , value ) ;
return - EIO ;
}
if ( rval & TWSIC1_ERROR ) {
cam_err ( cam , " SMBUS write (%02x/%02x/%02x) error \n " , addr ,
command , value ) ;
return - EIO ;
}
return 0 ;
}
static int cafe_smbus_read_done ( struct cafe_camera * cam )
{
unsigned long flags ;
int c1 ;
/*
* We must delay after the interrupt , or the controller gets confused
* and never does give us good status . Fortunately , we don ' t do this
* often .
*/
udelay ( 20 ) ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
c1 = cafe_reg_read ( cam , REG_TWSIC1 ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
return c1 & ( TWSIC1_RVALID | TWSIC1_ERROR ) ;
}
static int cafe_smbus_read_data ( struct cafe_camera * cam ,
u16 addr , u8 command , u8 * value )
{
unsigned int rval ;
unsigned long flags ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
rval = TWSIC0_EN | ( ( addr < < TWSIC0_SID_SHIFT ) & TWSIC0_SID ) ;
rval | = TWSIC0_OVMAGIC ; /* Make OV sensors work */
/*
* Marvel sez set clkdiv to all 1 ' s for now .
*/
rval | = TWSIC0_CLKDIV ;
cafe_reg_write ( cam , REG_TWSIC0 , rval ) ;
( void ) cafe_reg_read ( cam , REG_TWSIC1 ) ; /* force write */
rval = TWSIC1_READ | ( ( command < < TWSIC1_ADDR_SHIFT ) & TWSIC1_ADDR ) ;
cafe_reg_write ( cam , REG_TWSIC1 , rval ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
wait_event_timeout ( cam - > smbus_wait ,
cafe_smbus_read_done ( cam ) , CAFE_SMBUS_TIMEOUT ) ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
rval = cafe_reg_read ( cam , REG_TWSIC1 ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
if ( rval & TWSIC1_ERROR ) {
cam_err ( cam , " SMBUS read (%02x/%02x) error \n " , addr , command ) ;
return - EIO ;
}
if ( ! ( rval & TWSIC1_RVALID ) ) {
cam_err ( cam , " SMBUS read (%02x/%02x) timed out \n " , addr ,
command ) ;
return - EIO ;
}
* value = rval & 0xff ;
return 0 ;
}
/*
* Perform a transfer over SMBUS . This thing is called under
* the i2c bus lock , so we shouldn ' t race with ourselves . . .
*/
static int cafe_smbus_xfer ( struct i2c_adapter * adapter , u16 addr ,
unsigned short flags , char rw , u8 command ,
int size , union i2c_smbus_data * data )
{
2009-03-18 13:13:09 -03:00
struct v4l2_device * v4l2_dev = i2c_get_adapdata ( adapter ) ;
struct cafe_camera * cam = to_cam ( v4l2_dev ) ;
2006-11-04 09:25:53 -03:00
int ret = - EINVAL ;
/*
* This interface would appear to only do byte data ops . OK
* it can do word too , but the cam chip has no use for that .
*/
if ( size ! = I2C_SMBUS_BYTE_DATA ) {
cam_err ( cam , " funky xfer size %d \n " , size ) ;
return - EINVAL ;
}
if ( rw = = I2C_SMBUS_WRITE )
ret = cafe_smbus_write_data ( cam , addr , command , data - > byte ) ;
else if ( rw = = I2C_SMBUS_READ )
ret = cafe_smbus_read_data ( cam , addr , command , & data - > byte ) ;
return ret ;
}
static void cafe_smbus_enable_irq ( struct cafe_camera * cam )
{
unsigned long flags ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
cafe_reg_set_bit ( cam , REG_IRQMASK , TWSIIRQS ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
}
static u32 cafe_smbus_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_SMBUS_READ_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA ;
}
static struct i2c_algorithm cafe_smbus_algo = {
. smbus_xfer = cafe_smbus_xfer ,
. functionality = cafe_smbus_func
} ;
/* Somebody is on the bus */
2006-11-19 19:04:55 -03:00
static void cafe_ctlr_stop_dma ( struct cafe_camera * cam ) ;
static void cafe_ctlr_power_down ( struct cafe_camera * cam ) ;
2006-11-04 09:25:53 -03:00
static int cafe_smbus_setup ( struct cafe_camera * cam )
{
struct i2c_adapter * adap = & cam - > i2c_adapter ;
int ret ;
cafe_smbus_enable_irq ( cam ) ;
adap - > owner = THIS_MODULE ;
adap - > algo = & cafe_smbus_algo ;
strcpy ( adap - > name , " cafe_ccic " ) ;
2007-02-13 22:09:03 +01:00
adap - > dev . parent = & cam - > pdev - > dev ;
2009-03-18 13:13:09 -03:00
i2c_set_adapdata ( adap , & cam - > v4l2_dev ) ;
2006-11-04 09:25:53 -03:00
ret = i2c_add_adapter ( adap ) ;
if ( ret )
printk ( KERN_ERR " Unable to register cafe i2c adapter \n " ) ;
return ret ;
}
static void cafe_smbus_shutdown ( struct cafe_camera * cam )
{
i2c_del_adapter ( & cam - > i2c_adapter ) ;
}
/* ------------------------------------------------------------------- */
/*
* Deal with the controller .
*/
/*
* Do everything we think we need to have the interface operating
* according to the desired format .
*/
static void cafe_ctlr_dma ( struct cafe_camera * cam )
{
/*
* Store the first two Y buffers ( we aren ' t supporting
* planar formats for now , so no UV bufs ) . Then either
* set the third if it exists , or tell the controller
* to just use two .
*/
cafe_reg_write ( cam , REG_Y0BAR , cam - > dma_handles [ 0 ] ) ;
cafe_reg_write ( cam , REG_Y1BAR , cam - > dma_handles [ 1 ] ) ;
if ( cam - > nbufs > 2 ) {
cafe_reg_write ( cam , REG_Y2BAR , cam - > dma_handles [ 2 ] ) ;
cafe_reg_clear_bit ( cam , REG_CTRL1 , C1_TWOBUFS ) ;
}
else
cafe_reg_set_bit ( cam , REG_CTRL1 , C1_TWOBUFS ) ;
cafe_reg_write ( cam , REG_UBAR , 0 ) ; /* 32 bits only for now */
}
static void cafe_ctlr_image ( struct cafe_camera * cam )
{
int imgsz ;
struct v4l2_pix_format * fmt = & cam - > pix_format ;
imgsz = ( ( fmt - > height < < IMGSZ_V_SHIFT ) & IMGSZ_V_MASK ) |
( fmt - > bytesperline & IMGSZ_H_MASK ) ;
cafe_reg_write ( cam , REG_IMGSIZE , imgsz ) ;
cafe_reg_write ( cam , REG_IMGOFFSET , 0 ) ;
/* YPITCH just drops the last two bits */
cafe_reg_write_mask ( cam , REG_IMGPITCH , fmt - > bytesperline ,
IMGP_YP_MASK ) ;
/*
* Tell the controller about the image format we are using .
*/
switch ( cam - > pix_format . pixelformat ) {
case V4L2_PIX_FMT_YUYV :
cafe_reg_write_mask ( cam , REG_CTRL0 ,
C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_YUYV ,
C0_DF_MASK ) ;
break ;
case V4L2_PIX_FMT_RGB444 :
cafe_reg_write_mask ( cam , REG_CTRL0 ,
C0_DF_RGB | C0_RGBF_444 | C0_RGB4_XRGB ,
C0_DF_MASK ) ;
/* Alpha value? */
break ;
case V4L2_PIX_FMT_RGB565 :
cafe_reg_write_mask ( cam , REG_CTRL0 ,
C0_DF_RGB | C0_RGBF_565 | C0_RGB5_BGGR ,
C0_DF_MASK ) ;
break ;
default :
cam_err ( cam , " Unknown format %x \n " , cam - > pix_format . pixelformat ) ;
break ;
}
/*
* Make sure it knows we want to use hsync / vsync .
*/
cafe_reg_write_mask ( cam , REG_CTRL0 , C0_SIF_HVSYNC ,
C0_SIFM_MASK ) ;
}
/*
* Configure the controller for operation ; caller holds the
* device mutex .
*/
static int cafe_ctlr_configure ( struct cafe_camera * cam )
{
unsigned long flags ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
cafe_ctlr_dma ( cam ) ;
cafe_ctlr_image ( cam ) ;
cafe_set_config_needed ( cam , 0 ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
return 0 ;
}
static void cafe_ctlr_irq_enable ( struct cafe_camera * cam )
{
/*
* Clear any pending interrupts , since we do not
* expect to have I / O active prior to enabling .
*/
cafe_reg_write ( cam , REG_IRQSTAT , FRAMEIRQS ) ;
cafe_reg_set_bit ( cam , REG_IRQMASK , FRAMEIRQS ) ;
}
static void cafe_ctlr_irq_disable ( struct cafe_camera * cam )
{
cafe_reg_clear_bit ( cam , REG_IRQMASK , FRAMEIRQS ) ;
}
/*
* Make the controller start grabbing images . Everything must
* be set up before doing this .
*/
static void cafe_ctlr_start ( struct cafe_camera * cam )
{
/* set_bit performs a read, so no other barrier should be
needed here */
cafe_reg_set_bit ( cam , REG_CTRL0 , C0_ENABLE ) ;
}
static void cafe_ctlr_stop ( struct cafe_camera * cam )
{
cafe_reg_clear_bit ( cam , REG_CTRL0 , C0_ENABLE ) ;
}
static void cafe_ctlr_init ( struct cafe_camera * cam )
{
unsigned long flags ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
/*
* Added magic to bring up the hardware on the B - Test board
*/
cafe_reg_write ( cam , 0x3038 , 0x8 ) ;
cafe_reg_write ( cam , 0x315c , 0x80008 ) ;
/*
* Go through the dance needed to wake the device up .
* Note that these registers are global and shared
* with the NAND and SD devices . Interaction between the
* three still needs to be examined .
*/
cafe_reg_write ( cam , REG_GL_CSR , GCSR_SRS | GCSR_MRS ) ; /* Needed? */
cafe_reg_write ( cam , REG_GL_CSR , GCSR_SRC | GCSR_MRC ) ;
cafe_reg_write ( cam , REG_GL_CSR , GCSR_SRC | GCSR_MRS ) ;
2007-04-27 12:32:28 -03:00
/*
* Here we must wait a bit for the controller to come around .
*/
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
2007-08-17 01:03:22 -03:00
msleep ( 5 ) ;
2007-04-27 12:32:28 -03:00
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
2006-11-04 09:25:53 -03:00
cafe_reg_write ( cam , REG_GL_CSR , GCSR_CCIC_EN | GCSR_SRC | GCSR_MRC ) ;
cafe_reg_set_bit ( cam , REG_GL_IMASK , GIMSK_CCIC_EN ) ;
/*
* Make sure it ' s not powered down .
*/
cafe_reg_clear_bit ( cam , REG_CTRL1 , C1_PWRDWN ) ;
/*
* Turn off the enable bit . It sure should be off anyway ,
* but it ' s good to be sure .
*/
cafe_reg_clear_bit ( cam , REG_CTRL0 , C0_ENABLE ) ;
/*
* Mask all interrupts .
*/
cafe_reg_write ( cam , REG_IRQMASK , 0 ) ;
/*
* Clock the sensor appropriately . Controller clock should
* be 48 MHz , sensor " typical " value is half that .
*/
cafe_reg_write_mask ( cam , REG_CLKCTRL , 2 , CLK_DIV_MASK ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
}
/*
* Stop the controller , and don ' t return until we ' re really sure that no
* further DMA is going on .
*/
static void cafe_ctlr_stop_dma ( struct cafe_camera * cam )
{
unsigned long flags ;
/*
* Theory : stop the camera controller ( whether it is operating
* or not ) . Delay briefly just in case we race with the SOF
* interrupt , then wait until no DMA is active .
*/
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
cafe_ctlr_stop ( cam ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
mdelay ( 1 ) ;
wait_event_timeout ( cam - > iowait ,
! test_bit ( CF_DMA_ACTIVE , & cam - > flags ) , HZ ) ;
if ( test_bit ( CF_DMA_ACTIVE , & cam - > flags ) )
cam_err ( cam , " Timeout waiting for DMA to end \n " ) ;
/* This would be bad news - what now? */
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
cam - > state = S_IDLE ;
cafe_ctlr_irq_disable ( cam ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
}
/*
* Power up and down .
*/
static void cafe_ctlr_power_up ( struct cafe_camera * cam )
{
unsigned long flags ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
cafe_reg_clear_bit ( cam , REG_CTRL1 , C1_PWRDWN ) ;
2007-05-22 00:37:58 -03:00
/*
* Part one of the sensor dance : turn the global
* GPIO signal on .
*/
cafe_reg_write ( cam , REG_GL_FCR , GFCR_GPIO_ON ) ;
cafe_reg_write ( cam , REG_GL_GPIOR , GGPIO_OUT | GGPIO_VAL ) ;
2006-11-04 09:25:53 -03:00
/*
* Put the sensor into operational mode ( assumes OLPC - style
* wiring ) . Control 0 is reset - set to 1 to operate .
* Control 1 is power down , set to 0 to operate .
*/
2006-11-19 19:04:55 -03:00
cafe_reg_write ( cam , REG_GPR , GPR_C1EN | GPR_C0EN ) ; /* pwr up, reset */
2009-03-18 13:13:09 -03:00
/* mdelay(1); */ /* Marvell says 1ms will do it */
2006-11-04 09:25:53 -03:00
cafe_reg_write ( cam , REG_GPR , GPR_C1EN | GPR_C0EN | GPR_C0 ) ;
2009-03-18 13:13:09 -03:00
/* mdelay(1); */ /* Enough? */
2006-11-04 09:25:53 -03:00
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
2007-05-22 00:37:58 -03:00
msleep ( 5 ) ; /* Just to be sure */
2006-11-04 09:25:53 -03:00
}
static void cafe_ctlr_power_down ( struct cafe_camera * cam )
{
unsigned long flags ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
cafe_reg_write ( cam , REG_GPR , GPR_C1EN | GPR_C0EN | GPR_C1 ) ;
2007-05-22 00:37:58 -03:00
cafe_reg_write ( cam , REG_GL_FCR , GFCR_GPIO_ON ) ;
cafe_reg_write ( cam , REG_GL_GPIOR , GGPIO_OUT ) ;
2006-11-04 09:25:53 -03:00
cafe_reg_set_bit ( cam , REG_CTRL1 , C1_PWRDWN ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
}
/* -------------------------------------------------------------------- */
/*
* Communications with the sensor .
*/
static int __cafe_cam_reset ( struct cafe_camera * cam )
{
2009-03-18 13:16:44 -03:00
return sensor_call ( cam , core , reset , 0 ) ;
2006-11-04 09:25:53 -03:00
}
/*
* We have found the sensor on the i2c . Let ' s try to have a
* conversation .
*/
static int cafe_cam_init ( struct cafe_camera * cam )
{
2008-12-30 07:14:19 -03:00
struct v4l2_dbg_chip_ident chip ;
2006-11-04 09:25:53 -03:00
int ret ;
mutex_lock ( & cam - > s_mutex ) ;
if ( cam - > state ! = S_NOTREADY )
cam_warn ( cam , " Cam init with device in funky state %d " ,
cam - > state ) ;
ret = __cafe_cam_reset ( cam ) ;
if ( ret )
goto out ;
2009-05-05 08:08:38 -03:00
chip . ident = V4L2_IDENT_NONE ;
2008-12-30 07:14:19 -03:00
chip . match . type = V4L2_CHIP_MATCH_I2C_ADDR ;
2009-03-18 13:16:44 -03:00
chip . match . addr = cam - > sensor_addr ;
ret = sensor_call ( cam , core , g_chip_ident , & chip ) ;
2006-11-04 09:25:53 -03:00
if ( ret )
goto out ;
2007-04-27 12:31:08 -03:00
cam - > sensor_type = chip . ident ;
2006-11-04 09:25:53 -03:00
if ( cam - > sensor_type ! = V4L2_IDENT_OV7670 ) {
2009-03-18 13:16:44 -03:00
cam_err ( cam , " Unsupported sensor type 0x%x " , cam - > sensor_type ) ;
2006-11-04 09:25:53 -03:00
ret = - EINVAL ;
goto out ;
}
/* Get/set parameters? */
ret = 0 ;
cam - > state = S_IDLE ;
out :
2007-05-22 00:37:58 -03:00
cafe_ctlr_power_down ( cam ) ;
2006-11-04 09:25:53 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
/*
* Configure the sensor to match the parameters we have . Caller should
* hold s_mutex
*/
static int cafe_cam_set_flip ( struct cafe_camera * cam )
{
struct v4l2_control ctrl ;
memset ( & ctrl , 0 , sizeof ( ctrl ) ) ;
ctrl . id = V4L2_CID_VFLIP ;
ctrl . value = flip ;
2009-03-18 13:16:44 -03:00
return sensor_call ( cam , core , s_ctrl , & ctrl ) ;
2006-11-04 09:25:53 -03:00
}
static int cafe_cam_configure ( struct cafe_camera * cam )
{
struct v4l2_format fmt ;
2009-03-18 13:16:44 -03:00
int ret ;
2006-11-04 09:25:53 -03:00
if ( cam - > state ! = S_IDLE )
return - EINVAL ;
fmt . fmt . pix = cam - > pix_format ;
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , core , init , 0 ) ;
2006-11-04 09:25:53 -03:00
if ( ret = = 0 )
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , video , s_fmt , & fmt ) ;
2006-11-04 09:25:53 -03:00
/*
* OV7670 does weird things if flip is set * before * format . . .
*/
ret + = cafe_cam_set_flip ( cam ) ;
return ret ;
}
/* -------------------------------------------------------------------- */
/*
* DMA buffer management . These functions need s_mutex held .
*/
/* FIXME: this is inefficient as hell, since dma_alloc_coherent just
* does a get_free_pages ( ) call , and we waste a good chunk of an orderN
* allocation . Should try to allocate the whole set in one chunk .
*/
static int cafe_alloc_dma_bufs ( struct cafe_camera * cam , int loadtime )
{
int i ;
cafe_set_config_needed ( cam , 1 ) ;
if ( loadtime )
cam - > dma_buf_size = dma_buf_size ;
2006-12-01 15:37:49 -03:00
else
2006-11-04 09:25:53 -03:00
cam - > dma_buf_size = cam - > pix_format . sizeimage ;
if ( n_dma_bufs > 3 )
n_dma_bufs = 3 ;
cam - > nbufs = 0 ;
for ( i = 0 ; i < n_dma_bufs ; i + + ) {
cam - > dma_bufs [ i ] = dma_alloc_coherent ( & cam - > pdev - > dev ,
cam - > dma_buf_size , cam - > dma_handles + i ,
GFP_KERNEL ) ;
if ( cam - > dma_bufs [ i ] = = NULL ) {
cam_warn ( cam , " Failed to allocate DMA buffer \n " ) ;
break ;
}
/* For debug, remove eventually */
memset ( cam - > dma_bufs [ i ] , 0xcc , cam - > dma_buf_size ) ;
( cam - > nbufs ) + + ;
}
switch ( cam - > nbufs ) {
case 1 :
dma_free_coherent ( & cam - > pdev - > dev , cam - > dma_buf_size ,
cam - > dma_bufs [ 0 ] , cam - > dma_handles [ 0 ] ) ;
cam - > nbufs = 0 ;
case 0 :
cam_err ( cam , " Insufficient DMA buffers, cannot operate \n " ) ;
return - ENOMEM ;
case 2 :
if ( n_dma_bufs > 2 )
cam_warn ( cam , " Will limp along with only 2 buffers \n " ) ;
break ;
}
return 0 ;
}
static void cafe_free_dma_bufs ( struct cafe_camera * cam )
{
int i ;
for ( i = 0 ; i < cam - > nbufs ; i + + ) {
dma_free_coherent ( & cam - > pdev - > dev , cam - > dma_buf_size ,
cam - > dma_bufs [ i ] , cam - > dma_handles [ i ] ) ;
cam - > dma_bufs [ i ] = NULL ;
}
cam - > nbufs = 0 ;
}
/* ----------------------------------------------------------------------- */
/*
* Here starts the V4L2 interface code .
*/
/*
* Read an image from the device .
*/
static ssize_t cafe_deliver_buffer ( struct cafe_camera * cam ,
char __user * buffer , size_t len , loff_t * pos )
{
int bufno ;
unsigned long flags ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
if ( cam - > next_buf < 0 ) {
cam_err ( cam , " deliver_buffer: No next buffer \n " ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
return - EIO ;
}
bufno = cam - > next_buf ;
clear_bit ( bufno , & cam - > flags ) ;
if ( + + ( cam - > next_buf ) > = cam - > nbufs )
cam - > next_buf = 0 ;
if ( ! test_bit ( cam - > next_buf , & cam - > flags ) )
cam - > next_buf = - 1 ;
cam - > specframes = 0 ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
if ( len > cam - > pix_format . sizeimage )
len = cam - > pix_format . sizeimage ;
if ( copy_to_user ( buffer , cam - > dma_bufs [ bufno ] , len ) )
return - EFAULT ;
( * pos ) + = len ;
return len ;
}
/*
* Get everything ready , and start grabbing frames .
*/
static int cafe_read_setup ( struct cafe_camera * cam , enum cafe_state state )
{
int ret ;
unsigned long flags ;
/*
* Configuration . If we still don ' t have DMA buffers ,
* make one last , desperate attempt .
*/
if ( cam - > nbufs = = 0 )
if ( cafe_alloc_dma_bufs ( cam , 0 ) )
return - ENOMEM ;
if ( cafe_needs_config ( cam ) ) {
cafe_cam_configure ( cam ) ;
ret = cafe_ctlr_configure ( cam ) ;
if ( ret )
return ret ;
}
/*
* Turn it loose .
*/
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
cafe_reset_buffers ( cam ) ;
cafe_ctlr_irq_enable ( cam ) ;
cam - > state = state ;
cafe_ctlr_start ( cam ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
return 0 ;
}
static ssize_t cafe_v4l_read ( struct file * filp ,
char __user * buffer , size_t len , loff_t * pos )
{
struct cafe_camera * cam = filp - > private_data ;
2007-02-13 19:31:45 -03:00
int ret = 0 ;
2006-11-04 09:25:53 -03:00
/*
* Perhaps we ' re in speculative read mode and already
* have data ?
*/
mutex_lock ( & cam - > s_mutex ) ;
if ( cam - > state = = S_SPECREAD ) {
if ( cam - > next_buf > = 0 ) {
ret = cafe_deliver_buffer ( cam , buffer , len , pos ) ;
if ( ret ! = 0 )
goto out_unlock ;
}
} else if ( cam - > state = = S_FLAKED | | cam - > state = = S_NOTREADY ) {
ret = - EIO ;
goto out_unlock ;
} else if ( cam - > state ! = S_IDLE ) {
ret = - EBUSY ;
goto out_unlock ;
}
/*
* v4l2 : multiple processes can open the device , but only
* one gets to grab data from it .
*/
if ( cam - > owner & & cam - > owner ! = filp ) {
ret = - EBUSY ;
goto out_unlock ;
}
cam - > owner = filp ;
/*
* Do setup if need be .
*/
if ( cam - > state ! = S_SPECREAD ) {
ret = cafe_read_setup ( cam , S_SINGLEREAD ) ;
if ( ret )
goto out_unlock ;
}
/*
* Wait for something to happen . This should probably
* be interruptible ( FIXME ) .
*/
wait_event_timeout ( cam - > iowait , cam - > next_buf > = 0 , HZ ) ;
if ( cam - > next_buf < 0 ) {
cam_err ( cam , " read() operation timed out \n " ) ;
cafe_ctlr_stop_dma ( cam ) ;
ret = - EIO ;
goto out_unlock ;
}
/*
* Give them their data and we should be done .
*/
ret = cafe_deliver_buffer ( cam , buffer , len , pos ) ;
out_unlock :
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
/*
* Streaming I / O support .
*/
static int cafe_vidioc_streamon ( struct file * filp , void * priv ,
enum v4l2_buf_type type )
{
struct cafe_camera * cam = filp - > private_data ;
int ret = - EINVAL ;
if ( type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
goto out ;
mutex_lock ( & cam - > s_mutex ) ;
if ( cam - > state ! = S_IDLE | | cam - > n_sbufs = = 0 )
goto out_unlock ;
cam - > sequence = 0 ;
ret = cafe_read_setup ( cam , S_STREAMING ) ;
out_unlock :
mutex_unlock ( & cam - > s_mutex ) ;
out :
return ret ;
}
static int cafe_vidioc_streamoff ( struct file * filp , void * priv ,
enum v4l2_buf_type type )
{
struct cafe_camera * cam = filp - > private_data ;
int ret = - EINVAL ;
if ( type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
goto out ;
mutex_lock ( & cam - > s_mutex ) ;
if ( cam - > state ! = S_STREAMING )
goto out_unlock ;
cafe_ctlr_stop_dma ( cam ) ;
ret = 0 ;
out_unlock :
mutex_unlock ( & cam - > s_mutex ) ;
out :
return ret ;
}
static int cafe_setup_siobuf ( struct cafe_camera * cam , int index )
{
struct cafe_sio_buffer * buf = cam - > sb_bufs + index ;
INIT_LIST_HEAD ( & buf - > list ) ;
buf - > v4lbuf . length = PAGE_ALIGN ( cam - > pix_format . sizeimage ) ;
buf - > buffer = vmalloc_user ( buf - > v4lbuf . length ) ;
if ( buf - > buffer = = NULL )
return - ENOMEM ;
buf - > mapcount = 0 ;
buf - > cam = cam ;
buf - > v4lbuf . index = index ;
buf - > v4lbuf . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
buf - > v4lbuf . field = V4L2_FIELD_NONE ;
buf - > v4lbuf . memory = V4L2_MEMORY_MMAP ;
/*
2007-08-23 16:37:49 -03:00
* Offset : must be 32 - bit even on a 64 - bit system . videobuf - dma - sg
2006-11-04 09:25:53 -03:00
* just uses the length times the index , but the spec warns
* against doing just that - vma merging problems . So we
* leave a gap between each pair of buffers .
*/
buf - > v4lbuf . m . offset = 2 * index * buf - > v4lbuf . length ;
return 0 ;
}
static int cafe_free_sio_buffers ( struct cafe_camera * cam )
{
int i ;
/*
* If any buffers are mapped , we cannot free them at all .
*/
for ( i = 0 ; i < cam - > n_sbufs ; i + + )
if ( cam - > sb_bufs [ i ] . mapcount > 0 )
return - EBUSY ;
/*
* OK , let ' s do it .
*/
for ( i = 0 ; i < cam - > n_sbufs ; i + + )
vfree ( cam - > sb_bufs [ i ] . buffer ) ;
cam - > n_sbufs = 0 ;
kfree ( cam - > sb_bufs ) ;
cam - > sb_bufs = NULL ;
INIT_LIST_HEAD ( & cam - > sb_avail ) ;
INIT_LIST_HEAD ( & cam - > sb_full ) ;
return 0 ;
}
static int cafe_vidioc_reqbufs ( struct file * filp , void * priv ,
struct v4l2_requestbuffers * req )
{
struct cafe_camera * cam = filp - > private_data ;
2007-02-06 21:52:36 -03:00
int ret = 0 ; /* Silence warning */
2006-11-04 09:25:53 -03:00
/*
* Make sure it ' s something we can do . User pointers could be
* implemented without great pain , but that ' s not been done yet .
*/
if ( req - > memory ! = V4L2_MEMORY_MMAP )
return - EINVAL ;
/*
* If they ask for zero buffers , they really want us to stop streaming
* ( if it ' s happening ) and free everything . Should we check owner ?
*/
mutex_lock ( & cam - > s_mutex ) ;
if ( req - > count = = 0 ) {
if ( cam - > state = = S_STREAMING )
cafe_ctlr_stop_dma ( cam ) ;
ret = cafe_free_sio_buffers ( cam ) ;
goto out ;
}
/*
* Device needs to be idle and working . We * could * try to do the
* right thing in S_SPECREAD by shutting things down , but it
* probably doesn ' t matter .
*/
if ( cam - > state ! = S_IDLE | | ( cam - > owner & & cam - > owner ! = filp ) ) {
ret = - EBUSY ;
goto out ;
}
cam - > owner = filp ;
if ( req - > count < min_buffers )
req - > count = min_buffers ;
else if ( req - > count > max_buffers )
req - > count = max_buffers ;
if ( cam - > n_sbufs > 0 ) {
ret = cafe_free_sio_buffers ( cam ) ;
if ( ret )
goto out ;
}
cam - > sb_bufs = kzalloc ( req - > count * sizeof ( struct cafe_sio_buffer ) ,
GFP_KERNEL ) ;
if ( cam - > sb_bufs = = NULL ) {
ret = - ENOMEM ;
goto out ;
}
for ( cam - > n_sbufs = 0 ; cam - > n_sbufs < req - > count ; ( cam - > n_sbufs + + ) ) {
ret = cafe_setup_siobuf ( cam , cam - > n_sbufs ) ;
if ( ret )
break ;
}
if ( cam - > n_sbufs = = 0 ) /* no luck at all - ret already set */
kfree ( cam - > sb_bufs ) ;
req - > count = cam - > n_sbufs ; /* In case of partial success */
out :
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
static int cafe_vidioc_querybuf ( struct file * filp , void * priv ,
struct v4l2_buffer * buf )
{
struct cafe_camera * cam = filp - > private_data ;
int ret = - EINVAL ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-28 22:25:36 -03:00
if ( buf - > index > = cam - > n_sbufs )
2006-11-04 09:25:53 -03:00
goto out ;
* buf = cam - > sb_bufs [ buf - > index ] . v4lbuf ;
ret = 0 ;
out :
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
static int cafe_vidioc_qbuf ( struct file * filp , void * priv ,
struct v4l2_buffer * buf )
{
struct cafe_camera * cam = filp - > private_data ;
struct cafe_sio_buffer * sbuf ;
int ret = - EINVAL ;
unsigned long flags ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-28 22:25:36 -03:00
if ( buf - > index > = cam - > n_sbufs )
2006-11-04 09:25:53 -03:00
goto out ;
sbuf = cam - > sb_bufs + buf - > index ;
if ( sbuf - > v4lbuf . flags & V4L2_BUF_FLAG_QUEUED ) {
ret = 0 ; /* Already queued?? */
goto out ;
}
if ( sbuf - > v4lbuf . flags & V4L2_BUF_FLAG_DONE ) {
/* Spec doesn't say anything, seems appropriate tho */
ret = - EBUSY ;
goto out ;
}
sbuf - > v4lbuf . flags | = V4L2_BUF_FLAG_QUEUED ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
list_add ( & sbuf - > list , & cam - > sb_avail ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
ret = 0 ;
out :
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
static int cafe_vidioc_dqbuf ( struct file * filp , void * priv ,
struct v4l2_buffer * buf )
{
struct cafe_camera * cam = filp - > private_data ;
struct cafe_sio_buffer * sbuf ;
int ret = - EINVAL ;
unsigned long flags ;
mutex_lock ( & cam - > s_mutex ) ;
if ( cam - > state ! = S_STREAMING )
goto out_unlock ;
if ( list_empty ( & cam - > sb_full ) & & filp - > f_flags & O_NONBLOCK ) {
ret = - EAGAIN ;
goto out_unlock ;
}
while ( list_empty ( & cam - > sb_full ) & & cam - > state = = S_STREAMING ) {
mutex_unlock ( & cam - > s_mutex ) ;
if ( wait_event_interruptible ( cam - > iowait ,
! list_empty ( & cam - > sb_full ) ) ) {
ret = - ERESTARTSYS ;
goto out ;
}
mutex_lock ( & cam - > s_mutex ) ;
}
if ( cam - > state ! = S_STREAMING )
ret = - EINTR ;
else {
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
/* Should probably recheck !list_empty() here */
sbuf = list_entry ( cam - > sb_full . next ,
struct cafe_sio_buffer , list ) ;
list_del_init ( & sbuf - > list ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
sbuf - > v4lbuf . flags & = ~ V4L2_BUF_FLAG_DONE ;
* buf = sbuf - > v4lbuf ;
ret = 0 ;
}
out_unlock :
mutex_unlock ( & cam - > s_mutex ) ;
out :
return ret ;
}
static void cafe_v4l_vm_open ( struct vm_area_struct * vma )
{
struct cafe_sio_buffer * sbuf = vma - > vm_private_data ;
/*
* Locking : done under mmap_sem , so we don ' t need to
* go back to the camera lock here .
*/
sbuf - > mapcount + + ;
}
static void cafe_v4l_vm_close ( struct vm_area_struct * vma )
{
struct cafe_sio_buffer * sbuf = vma - > vm_private_data ;
mutex_lock ( & sbuf - > cam - > s_mutex ) ;
sbuf - > mapcount - - ;
/* Docs say we should stop I/O too... */
if ( sbuf - > mapcount = = 0 )
sbuf - > v4lbuf . flags & = ~ V4L2_BUF_FLAG_MAPPED ;
mutex_unlock ( & sbuf - > cam - > s_mutex ) ;
}
2009-09-27 22:29:37 +04:00
static const struct vm_operations_struct cafe_v4l_vm_ops = {
2006-11-04 09:25:53 -03:00
. open = cafe_v4l_vm_open ,
. close = cafe_v4l_vm_close
} ;
static int cafe_v4l_mmap ( struct file * filp , struct vm_area_struct * vma )
{
struct cafe_camera * cam = filp - > private_data ;
unsigned long offset = vma - > vm_pgoff < < PAGE_SHIFT ;
int ret = - EINVAL ;
int i ;
struct cafe_sio_buffer * sbuf = NULL ;
if ( ! ( vma - > vm_flags & VM_WRITE ) | | ! ( vma - > vm_flags & VM_SHARED ) )
return - EINVAL ;
/*
* Find the buffer they are looking for .
*/
mutex_lock ( & cam - > s_mutex ) ;
for ( i = 0 ; i < cam - > n_sbufs ; i + + )
if ( cam - > sb_bufs [ i ] . v4lbuf . m . offset = = offset ) {
sbuf = cam - > sb_bufs + i ;
break ;
}
if ( sbuf = = NULL )
goto out ;
ret = remap_vmalloc_range ( vma , sbuf - > buffer , 0 ) ;
if ( ret )
goto out ;
vma - > vm_flags | = VM_DONTEXPAND ;
vma - > vm_private_data = sbuf ;
vma - > vm_ops = & cafe_v4l_vm_ops ;
sbuf - > v4lbuf . flags | = V4L2_BUF_FLAG_MAPPED ;
cafe_v4l_vm_open ( vma ) ;
ret = 0 ;
out :
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
2008-12-30 06:58:20 -03:00
static int cafe_v4l_open ( struct file * filp )
2006-11-04 09:25:53 -03:00
{
2009-03-18 13:13:09 -03:00
struct cafe_camera * cam = video_drvdata ( filp ) ;
2006-11-04 09:25:53 -03:00
filp - > private_data = cam ;
mutex_lock ( & cam - > s_mutex ) ;
if ( cam - > users = = 0 ) {
cafe_ctlr_power_up ( cam ) ;
__cafe_cam_reset ( cam ) ;
cafe_set_config_needed ( cam , 1 ) ;
/* FIXME make sure this is complete */
}
( cam - > users ) + + ;
mutex_unlock ( & cam - > s_mutex ) ;
return 0 ;
}
2008-12-30 06:58:20 -03:00
static int cafe_v4l_release ( struct file * filp )
2006-11-04 09:25:53 -03:00
{
struct cafe_camera * cam = filp - > private_data ;
mutex_lock ( & cam - > s_mutex ) ;
( cam - > users ) - - ;
if ( filp = = cam - > owner ) {
cafe_ctlr_stop_dma ( cam ) ;
cafe_free_sio_buffers ( cam ) ;
cam - > owner = NULL ;
}
2006-11-19 19:04:55 -03:00
if ( cam - > users = = 0 ) {
2006-11-04 09:25:53 -03:00
cafe_ctlr_power_down ( cam ) ;
2007-09-19 02:44:18 -03:00
if ( alloc_bufs_at_read )
2006-11-19 19:04:55 -03:00
cafe_free_dma_bufs ( cam ) ;
}
2006-11-04 09:25:53 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
return 0 ;
}
static unsigned int cafe_v4l_poll ( struct file * filp ,
struct poll_table_struct * pt )
{
struct cafe_camera * cam = filp - > private_data ;
poll_wait ( filp , & cam - > iowait , pt ) ;
if ( cam - > next_buf > = 0 )
return POLLIN | POLLRDNORM ;
return 0 ;
}
static int cafe_vidioc_queryctrl ( struct file * filp , void * priv ,
struct v4l2_queryctrl * qc )
{
2009-03-18 13:13:09 -03:00
struct cafe_camera * cam = priv ;
2006-11-04 09:25:53 -03:00
int ret ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , core , queryctrl , qc ) ;
2006-11-04 09:25:53 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
static int cafe_vidioc_g_ctrl ( struct file * filp , void * priv ,
struct v4l2_control * ctrl )
{
2009-03-18 13:13:09 -03:00
struct cafe_camera * cam = priv ;
2006-11-04 09:25:53 -03:00
int ret ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , core , g_ctrl , ctrl ) ;
2006-11-04 09:25:53 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
static int cafe_vidioc_s_ctrl ( struct file * filp , void * priv ,
struct v4l2_control * ctrl )
{
2009-03-18 13:13:09 -03:00
struct cafe_camera * cam = priv ;
2006-11-04 09:25:53 -03:00
int ret ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , core , s_ctrl , ctrl ) ;
2006-11-04 09:25:53 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
static int cafe_vidioc_querycap ( struct file * file , void * priv ,
struct v4l2_capability * cap )
{
strcpy ( cap - > driver , " cafe_ccic " ) ;
strcpy ( cap - > card , " cafe_ccic " ) ;
cap - > version = CAFE_VERSION ;
cap - > capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING ;
return 0 ;
}
/*
* The default format we use until somebody says otherwise .
*/
static struct v4l2_pix_format cafe_def_pix_format = {
. width = VGA_WIDTH ,
. height = VGA_HEIGHT ,
. pixelformat = V4L2_PIX_FMT_YUYV ,
. field = V4L2_FIELD_NONE ,
. bytesperline = VGA_WIDTH * 2 ,
. sizeimage = VGA_WIDTH * VGA_HEIGHT * 2 ,
} ;
2008-05-28 12:16:41 -03:00
static int cafe_vidioc_enum_fmt_vid_cap ( struct file * filp ,
2006-11-04 09:25:53 -03:00
void * priv , struct v4l2_fmtdesc * fmt )
{
struct cafe_camera * cam = priv ;
int ret ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , video , enum_fmt , fmt ) ;
2006-11-04 09:25:53 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
2008-05-28 12:16:41 -03:00
static int cafe_vidioc_try_fmt_vid_cap ( struct file * filp , void * priv ,
2006-11-04 09:25:53 -03:00
struct v4l2_format * fmt )
{
struct cafe_camera * cam = priv ;
int ret ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , video , try_fmt , fmt ) ;
2006-11-04 09:25:53 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
2008-05-28 12:16:41 -03:00
static int cafe_vidioc_s_fmt_vid_cap ( struct file * filp , void * priv ,
2006-11-04 09:25:53 -03:00
struct v4l2_format * fmt )
{
struct cafe_camera * cam = priv ;
int ret ;
/*
* Can ' t do anything if the device is not idle
* Also can ' t if there are streaming buffers in place .
*/
if ( cam - > state ! = S_IDLE | | cam - > n_sbufs > 0 )
return - EBUSY ;
/*
* See if the formatting works in principle .
*/
2008-05-28 12:16:41 -03:00
ret = cafe_vidioc_try_fmt_vid_cap ( filp , priv , fmt ) ;
2006-11-04 09:25:53 -03:00
if ( ret )
return ret ;
/*
* Now we start to change things for real , so let ' s do it
* under lock .
*/
mutex_lock ( & cam - > s_mutex ) ;
cam - > pix_format = fmt - > fmt . pix ;
/*
* Make sure we have appropriate DMA buffers .
*/
ret = - ENOMEM ;
if ( cam - > nbufs > 0 & & cam - > dma_buf_size < cam - > pix_format . sizeimage )
cafe_free_dma_bufs ( cam ) ;
if ( cam - > nbufs = = 0 ) {
if ( cafe_alloc_dma_bufs ( cam , 0 ) )
goto out ;
}
/*
* It looks like this might work , so let ' s program the sensor .
*/
ret = cafe_cam_configure ( cam ) ;
if ( ! ret )
ret = cafe_ctlr_configure ( cam ) ;
out :
mutex_unlock ( & cam - > s_mutex ) ;
return ret ;
}
/*
* Return our stored notion of how the camera is / should be configured .
* The V4l2 spec wants us to be smarter , and actually get this from
* the camera ( and not mess with it at open time ) . Someday .
*/
2008-05-28 12:16:41 -03:00
static int cafe_vidioc_g_fmt_vid_cap ( struct file * filp , void * priv ,
2006-11-04 09:25:53 -03:00
struct v4l2_format * f )
{
struct cafe_camera * cam = priv ;
f - > fmt . pix = cam - > pix_format ;
return 0 ;
}
/*
* We only have one input - the sensor - so minimize the nonsense here .
*/
static int cafe_vidioc_enum_input ( struct file * filp , void * priv ,
struct v4l2_input * input )
{
if ( input - > index ! = 0 )
return - EINVAL ;
input - > type = V4L2_INPUT_TYPE_CAMERA ;
input - > std = V4L2_STD_ALL ; /* Not sure what should go here */
strcpy ( input - > name , " Camera " ) ;
return 0 ;
}
static int cafe_vidioc_g_input ( struct file * filp , void * priv , unsigned int * i )
{
* i = 0 ;
return 0 ;
}
static int cafe_vidioc_s_input ( struct file * filp , void * priv , unsigned int i )
{
if ( i ! = 0 )
return - EINVAL ;
return 0 ;
}
/* from vivi.c */
2006-11-20 13:19:20 -03:00
static int cafe_vidioc_s_std ( struct file * filp , void * priv , v4l2_std_id * a )
2006-11-04 09:25:53 -03:00
{
return 0 ;
}
2006-12-01 15:50:59 -03:00
/*
* G / S_PARM . Most of this is done by the sensor , but we are
* the level which controls the number of read buffers .
*/
static int cafe_vidioc_g_parm ( struct file * filp , void * priv ,
struct v4l2_streamparm * parms )
{
struct cafe_camera * cam = priv ;
int ret ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , video , g_parm , parms ) ;
2006-12-01 15:50:59 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
parms - > parm . capture . readbuffers = n_dma_bufs ;
return ret ;
}
static int cafe_vidioc_s_parm ( struct file * filp , void * priv ,
struct v4l2_streamparm * parms )
{
struct cafe_camera * cam = priv ;
int ret ;
mutex_lock ( & cam - > s_mutex ) ;
2009-03-18 13:16:44 -03:00
ret = sensor_call ( cam , video , s_parm , parms ) ;
2006-12-01 15:50:59 -03:00
mutex_unlock ( & cam - > s_mutex ) ;
parms - > parm . capture . readbuffers = n_dma_bufs ;
return ret ;
}
2009-03-18 13:25:54 -03:00
static int cafe_vidioc_g_chip_ident ( struct file * file , void * priv ,
struct v4l2_dbg_chip_ident * chip )
{
struct cafe_camera * cam = priv ;
chip - > ident = V4L2_IDENT_NONE ;
chip - > revision = 0 ;
if ( v4l2_chip_match_host ( & chip - > match ) ) {
chip - > ident = V4L2_IDENT_CAFE ;
return 0 ;
}
return sensor_call ( cam , core , g_chip_ident , chip ) ;
}
# ifdef CONFIG_VIDEO_ADV_DEBUG
static int cafe_vidioc_g_register ( struct file * file , void * priv ,
struct v4l2_dbg_register * reg )
{
struct cafe_camera * cam = priv ;
if ( v4l2_chip_match_host ( & reg - > match ) ) {
reg - > val = cafe_reg_read ( cam , reg - > reg ) ;
reg - > size = 4 ;
return 0 ;
}
return sensor_call ( cam , core , g_register , reg ) ;
}
static int cafe_vidioc_s_register ( struct file * file , void * priv ,
struct v4l2_dbg_register * reg )
{
struct cafe_camera * cam = priv ;
if ( v4l2_chip_match_host ( & reg - > match ) ) {
cafe_reg_write ( cam , reg - > reg , reg - > val ) ;
return 0 ;
}
return sensor_call ( cam , core , s_register , reg ) ;
}
# endif
2006-11-04 09:25:53 -03:00
/*
* This template device holds all of those v4l2 methods ; we
* clone it for specific real devices .
*/
2008-12-30 06:58:20 -03:00
static const struct v4l2_file_operations cafe_v4l_fops = {
2006-11-04 09:25:53 -03:00
. owner = THIS_MODULE ,
. open = cafe_v4l_open ,
. release = cafe_v4l_release ,
. read = cafe_v4l_read ,
. poll = cafe_v4l_poll ,
. mmap = cafe_v4l_mmap ,
. ioctl = video_ioctl2 ,
} ;
2008-07-21 02:57:38 -03:00
static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
2006-11-04 09:25:53 -03:00
. vidioc_querycap = cafe_vidioc_querycap ,
2008-05-28 12:16:41 -03:00
. vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap ,
. vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap ,
. vidioc_s_fmt_vid_cap = cafe_vidioc_s_fmt_vid_cap ,
. vidioc_g_fmt_vid_cap = cafe_vidioc_g_fmt_vid_cap ,
2006-11-04 09:25:53 -03:00
. vidioc_enum_input = cafe_vidioc_enum_input ,
. vidioc_g_input = cafe_vidioc_g_input ,
. vidioc_s_input = cafe_vidioc_s_input ,
. vidioc_s_std = cafe_vidioc_s_std ,
. vidioc_reqbufs = cafe_vidioc_reqbufs ,
. vidioc_querybuf = cafe_vidioc_querybuf ,
. vidioc_qbuf = cafe_vidioc_qbuf ,
. vidioc_dqbuf = cafe_vidioc_dqbuf ,
. vidioc_streamon = cafe_vidioc_streamon ,
. vidioc_streamoff = cafe_vidioc_streamoff ,
. vidioc_queryctrl = cafe_vidioc_queryctrl ,
. vidioc_g_ctrl = cafe_vidioc_g_ctrl ,
. vidioc_s_ctrl = cafe_vidioc_s_ctrl ,
2006-12-01 15:50:59 -03:00
. vidioc_g_parm = cafe_vidioc_g_parm ,
. vidioc_s_parm = cafe_vidioc_s_parm ,
2009-03-18 13:25:54 -03:00
. vidioc_g_chip_ident = cafe_vidioc_g_chip_ident ,
# ifdef CONFIG_VIDEO_ADV_DEBUG
. vidioc_g_register = cafe_vidioc_g_register ,
. vidioc_s_register = cafe_vidioc_s_register ,
# endif
2006-11-04 09:25:53 -03:00
} ;
2008-07-21 02:57:38 -03:00
static struct video_device cafe_v4l_template = {
. name = " cafe " ,
. tvnorms = V4L2_STD_NTSC_M ,
. current_norm = V4L2_STD_NTSC_M , /* make mplayer happy */
. fops = & cafe_v4l_fops ,
. ioctl_ops = & cafe_v4l_ioctl_ops ,
2009-03-18 13:13:09 -03:00
. release = video_device_release_empty ,
2008-07-21 02:57:38 -03:00
} ;
2006-11-04 09:25:53 -03:00
/* ---------------------------------------------------------------------- */
/*
* Interrupt handler stuff
*/
static void cafe_frame_tasklet ( unsigned long data )
{
struct cafe_camera * cam = ( struct cafe_camera * ) data ;
int i ;
unsigned long flags ;
struct cafe_sio_buffer * sbuf ;
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
for ( i = 0 ; i < cam - > nbufs ; i + + ) {
int bufno = cam - > next_buf ;
if ( bufno < 0 ) { /* "will never happen" */
cam_err ( cam , " No valid bufs in tasklet! \n " ) ;
break ;
}
if ( + + ( cam - > next_buf ) > = cam - > nbufs )
cam - > next_buf = 0 ;
if ( ! test_bit ( bufno , & cam - > flags ) )
continue ;
if ( list_empty ( & cam - > sb_avail ) )
break ; /* Leave it valid, hope for better later */
clear_bit ( bufno , & cam - > flags ) ;
sbuf = list_entry ( cam - > sb_avail . next ,
struct cafe_sio_buffer , list ) ;
2007-04-27 12:32:28 -03:00
/*
* Drop the lock during the big copy . This * should * be safe . . .
*/
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
2006-12-01 15:37:49 -03:00
memcpy ( sbuf - > buffer , cam - > dma_bufs [ bufno ] ,
cam - > pix_format . sizeimage ) ;
2006-11-04 09:25:53 -03:00
sbuf - > v4lbuf . bytesused = cam - > pix_format . sizeimage ;
sbuf - > v4lbuf . sequence = cam - > buf_seq [ bufno ] ;
sbuf - > v4lbuf . flags & = ~ V4L2_BUF_FLAG_QUEUED ;
sbuf - > v4lbuf . flags | = V4L2_BUF_FLAG_DONE ;
2007-04-27 12:32:28 -03:00
spin_lock_irqsave ( & cam - > dev_lock , flags ) ;
2006-11-04 09:25:53 -03:00
list_move_tail ( & sbuf - > list , & cam - > sb_full ) ;
}
if ( ! list_empty ( & cam - > sb_full ) )
wake_up ( & cam - > iowait ) ;
spin_unlock_irqrestore ( & cam - > dev_lock , flags ) ;
}
static void cafe_frame_complete ( struct cafe_camera * cam , int frame )
{
/*
* Basic frame housekeeping .
*/
if ( test_bit ( frame , & cam - > flags ) & & printk_ratelimit ( ) )
cam_err ( cam , " Frame overrun on %d, frames lost \n " , frame ) ;
set_bit ( frame , & cam - > flags ) ;
clear_bit ( CF_DMA_ACTIVE , & cam - > flags ) ;
if ( cam - > next_buf < 0 )
cam - > next_buf = frame ;
cam - > buf_seq [ frame ] = + + ( cam - > sequence ) ;
switch ( cam - > state ) {
/*
* If in single read mode , try going speculative .
*/
case S_SINGLEREAD :
cam - > state = S_SPECREAD ;
cam - > specframes = 0 ;
wake_up ( & cam - > iowait ) ;
break ;
/*
* If we are already doing speculative reads , and nobody is
* reading them , just stop .
*/
case S_SPECREAD :
if ( + + ( cam - > specframes ) > = cam - > nbufs ) {
cafe_ctlr_stop ( cam ) ;
cafe_ctlr_irq_disable ( cam ) ;
cam - > state = S_IDLE ;
}
wake_up ( & cam - > iowait ) ;
break ;
/*
* For the streaming case , we defer the real work to the
* camera tasklet .
*
* FIXME : if the application is not consuming the buffers ,
* we should eventually put things on hold and restart in
* vidioc_dqbuf ( ) .
*/
case S_STREAMING :
tasklet_schedule ( & cam - > s_tasklet ) ;
break ;
default :
cam_err ( cam , " Frame interrupt in non-operational state \n " ) ;
break ;
}
}
static void cafe_frame_irq ( struct cafe_camera * cam , unsigned int irqs )
{
unsigned int frame ;
cafe_reg_write ( cam , REG_IRQSTAT , FRAMEIRQS ) ; /* Clear'em all */
/*
* Handle any frame completions . There really should
* not be more than one of these , or we have fallen
* far behind .
*/
for ( frame = 0 ; frame < cam - > nbufs ; frame + + )
if ( irqs & ( IRQ_EOF0 < < frame ) )
cafe_frame_complete ( cam , frame ) ;
/*
* If a frame starts , note that we have DMA active . This
* code assumes that we won ' t get multiple frame interrupts
* at once ; may want to rethink that .
*/
if ( irqs & ( IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2 ) )
set_bit ( CF_DMA_ACTIVE , & cam - > flags ) ;
}
static irqreturn_t cafe_irq ( int irq , void * data )
{
struct cafe_camera * cam = data ;
unsigned int irqs ;
spin_lock ( & cam - > dev_lock ) ;
irqs = cafe_reg_read ( cam , REG_IRQSTAT ) ;
if ( ( irqs & ALLIRQS ) = = 0 ) {
spin_unlock ( & cam - > dev_lock ) ;
return IRQ_NONE ;
}
if ( irqs & FRAMEIRQS )
cafe_frame_irq ( cam , irqs ) ;
if ( irqs & TWSIIRQS ) {
cafe_reg_write ( cam , REG_IRQSTAT , TWSIIRQS ) ;
wake_up ( & cam - > smbus_wait ) ;
}
spin_unlock ( & cam - > dev_lock ) ;
return IRQ_HANDLED ;
}
/* -------------------------------------------------------------------------- */
/*
* PCI interface stuff .
*/
static int cafe_pci_probe ( struct pci_dev * pdev ,
const struct pci_device_id * id )
{
int ret ;
struct cafe_camera * cam ;
2008-09-03 09:49:20 +01:00
2006-11-04 09:25:53 -03:00
/*
* Start putting together one of our big camera structures .
*/
ret = - ENOMEM ;
cam = kzalloc ( sizeof ( struct cafe_camera ) , GFP_KERNEL ) ;
if ( cam = = NULL )
goto out ;
2009-03-18 13:13:09 -03:00
ret = v4l2_device_register ( & pdev - > dev , & cam - > v4l2_dev ) ;
if ( ret )
goto out_free ;
2006-11-04 09:25:53 -03:00
mutex_init ( & cam - > s_mutex ) ;
mutex_lock ( & cam - > s_mutex ) ;
spin_lock_init ( & cam - > dev_lock ) ;
cam - > state = S_NOTREADY ;
cafe_set_config_needed ( cam , 1 ) ;
init_waitqueue_head ( & cam - > smbus_wait ) ;
init_waitqueue_head ( & cam - > iowait ) ;
cam - > pdev = pdev ;
cam - > pix_format = cafe_def_pix_format ;
INIT_LIST_HEAD ( & cam - > dev_list ) ;
INIT_LIST_HEAD ( & cam - > sb_avail ) ;
INIT_LIST_HEAD ( & cam - > sb_full ) ;
tasklet_init ( & cam - > s_tasklet , cafe_frame_tasklet , ( unsigned long ) cam ) ;
/*
* Get set up on the PCI bus .
*/
ret = pci_enable_device ( pdev ) ;
if ( ret )
2009-03-18 13:13:09 -03:00
goto out_unreg ;
2006-11-04 09:25:53 -03:00
pci_set_master ( pdev ) ;
ret = - EIO ;
cam - > regs = pci_iomap ( pdev , 0 , 0 ) ;
if ( ! cam - > regs ) {
printk ( KERN_ERR " Unable to ioremap cafe-ccic regs \n " ) ;
2009-03-18 13:13:09 -03:00
goto out_unreg ;
2006-11-04 09:25:53 -03:00
}
ret = request_irq ( pdev - > irq , cafe_irq , IRQF_SHARED , " cafe-ccic " , cam ) ;
if ( ret )
goto out_iounmap ;
2007-05-22 00:37:58 -03:00
/*
* Initialize the controller and leave it powered up . It will
* stay that way until the sensor driver shows up .
*/
2006-11-04 09:25:53 -03:00
cafe_ctlr_init ( cam ) ;
cafe_ctlr_power_up ( cam ) ;
/*
2007-05-22 00:37:58 -03:00
* Set up I2C / SMBUS communications . We have to drop the mutex here
* because the sensor could attach in this call chain , leading to
* unsightly deadlocks .
2006-11-04 09:25:53 -03:00
*/
mutex_unlock ( & cam - > s_mutex ) ; /* attach can deadlock */
ret = cafe_smbus_setup ( cam ) ;
if ( ret )
goto out_freeirq ;
2009-03-18 13:16:44 -03:00
cam - > sensor_addr = 0x42 ;
2009-04-01 03:57:53 -03:00
cam - > sensor = v4l2_i2c_new_subdev ( & cam - > v4l2_dev , & cam - > i2c_adapter ,
2009-08-10 02:49:08 -03:00
" ov7670 " , " ov7670 " , cam - > sensor_addr , NULL ) ;
2009-03-18 13:16:44 -03:00
if ( cam - > sensor = = NULL ) {
ret = - ENODEV ;
goto out_smbus ;
}
ret = cafe_cam_init ( cam ) ;
if ( ret )
goto out_smbus ;
2006-11-04 09:25:53 -03:00
/*
* Get the v4l2 setup done .
*/
mutex_lock ( & cam - > s_mutex ) ;
2009-03-18 13:13:09 -03:00
cam - > vdev = cafe_v4l_template ;
cam - > vdev . debug = 0 ;
/* cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/
cam - > vdev . v4l2_dev = & cam - > v4l2_dev ;
ret = video_register_device ( & cam - > vdev , VFL_TYPE_GRABBER , - 1 ) ;
2006-11-04 09:25:53 -03:00
if ( ret )
goto out_smbus ;
2009-03-18 13:13:09 -03:00
video_set_drvdata ( & cam - > vdev , cam ) ;
2006-11-04 09:25:53 -03:00
/*
* If so requested , try to get our DMA buffers now .
*/
2007-09-19 02:44:18 -03:00
if ( ! alloc_bufs_at_read ) {
2006-11-04 09:25:53 -03:00
if ( cafe_alloc_dma_bufs ( cam , 1 ) )
cam_warn ( cam , " Unable to alloc DMA buffers at load "
" will try again later. " ) ;
}
mutex_unlock ( & cam - > s_mutex ) ;
return 0 ;
2009-03-18 13:13:09 -03:00
out_smbus :
2006-11-04 09:25:53 -03:00
cafe_smbus_shutdown ( cam ) ;
2009-03-18 13:13:09 -03:00
out_freeirq :
2006-11-04 09:25:53 -03:00
cafe_ctlr_power_down ( cam ) ;
free_irq ( pdev - > irq , cam ) ;
2009-03-18 13:13:09 -03:00
out_iounmap :
2006-11-04 09:25:53 -03:00
pci_iounmap ( pdev , cam - > regs ) ;
2009-03-18 13:13:09 -03:00
out_free :
v4l2_device_unregister ( & cam - > v4l2_dev ) ;
out_unreg :
2006-11-04 09:25:53 -03:00
kfree ( cam ) ;
2009-03-18 13:13:09 -03:00
out :
2006-11-04 09:25:53 -03:00
return ret ;
}
/*
* Shut down an initialized device
*/
static void cafe_shutdown ( struct cafe_camera * cam )
{
/* FIXME: Make sure we take care of everything here */
if ( cam - > n_sbufs > 0 )
/* What if they are still mapped? Shouldn't be, but... */
cafe_free_sio_buffers ( cam ) ;
cafe_ctlr_stop_dma ( cam ) ;
cafe_ctlr_power_down ( cam ) ;
cafe_smbus_shutdown ( cam ) ;
cafe_free_dma_bufs ( cam ) ;
free_irq ( cam - > pdev - > irq , cam ) ;
pci_iounmap ( cam - > pdev , cam - > regs ) ;
2009-03-18 13:13:09 -03:00
video_unregister_device ( & cam - > vdev ) ;
2006-11-04 09:25:53 -03:00
}
static void cafe_pci_remove ( struct pci_dev * pdev )
{
2009-03-18 13:13:09 -03:00
struct v4l2_device * v4l2_dev = dev_get_drvdata ( & pdev - > dev ) ;
struct cafe_camera * cam = to_cam ( v4l2_dev ) ;
2006-11-04 09:25:53 -03:00
if ( cam = = NULL ) {
2006-12-20 09:34:32 -03:00
printk ( KERN_WARNING " pci_remove on unknown pdev %p \n " , pdev ) ;
2006-11-04 09:25:53 -03:00
return ;
}
mutex_lock ( & cam - > s_mutex ) ;
if ( cam - > users > 0 )
cam_warn ( cam , " Removing a device with users! \n " ) ;
cafe_shutdown ( cam ) ;
2009-03-18 13:13:09 -03:00
v4l2_device_unregister ( & cam - > v4l2_dev ) ;
kfree ( cam ) ;
2006-11-04 09:25:53 -03:00
/* No unlock - it no longer exists */
}
2007-03-25 11:36:28 -03:00
# ifdef CONFIG_PM
/*
* Basic power management .
*/
static int cafe_pci_suspend ( struct pci_dev * pdev , pm_message_t state )
{
2009-03-18 13:13:09 -03:00
struct v4l2_device * v4l2_dev = dev_get_drvdata ( & pdev - > dev ) ;
struct cafe_camera * cam = to_cam ( v4l2_dev ) ;
2007-03-25 11:36:28 -03:00
int ret ;
2007-10-23 17:30:27 -03:00
enum cafe_state cstate ;
2007-03-25 11:36:28 -03:00
ret = pci_save_state ( pdev ) ;
if ( ret )
return ret ;
2007-10-23 17:30:27 -03:00
cstate = cam - > state ; /* HACK - stop_dma sets to idle */
2007-03-25 11:36:28 -03:00
cafe_ctlr_stop_dma ( cam ) ;
cafe_ctlr_power_down ( cam ) ;
pci_disable_device ( pdev ) ;
2007-10-23 17:30:27 -03:00
cam - > state = cstate ;
2007-03-25 11:36:28 -03:00
return 0 ;
}
static int cafe_pci_resume ( struct pci_dev * pdev )
{
2009-03-18 13:13:09 -03:00
struct v4l2_device * v4l2_dev = dev_get_drvdata ( & pdev - > dev ) ;
struct cafe_camera * cam = to_cam ( v4l2_dev ) ;
2007-03-25 11:36:28 -03:00
int ret = 0 ;
ret = pci_restore_state ( pdev ) ;
if ( ret )
return ret ;
2007-04-25 00:20:13 -03:00
ret = pci_enable_device ( pdev ) ;
2007-08-17 01:01:33 -03:00
2007-04-25 00:20:13 -03:00
if ( ret ) {
cam_warn ( cam , " Unable to re-enable device on resume! \n " ) ;
return ret ;
}
2007-03-25 11:36:28 -03:00
cafe_ctlr_init ( cam ) ;
2007-08-17 01:01:33 -03:00
cafe_ctlr_power_down ( cam ) ;
mutex_lock ( & cam - > s_mutex ) ;
if ( cam - > users > 0 ) {
cafe_ctlr_power_up ( cam ) ;
__cafe_cam_reset ( cam ) ;
}
mutex_unlock ( & cam - > s_mutex ) ;
2007-03-25 11:36:28 -03:00
set_bit ( CF_CONFIG_NEEDED , & cam - > flags ) ;
if ( cam - > state = = S_SPECREAD )
cam - > state = S_IDLE ; /* Don't bother restarting */
else if ( cam - > state = = S_SINGLEREAD | | cam - > state = = S_STREAMING )
ret = cafe_read_setup ( cam , cam - > state ) ;
return ret ;
}
# endif /* CONFIG_PM */
2006-11-04 09:25:53 -03:00
static struct pci_device_id cafe_ids [ ] = {
2008-09-03 09:49:20 +01:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL ,
PCI_DEVICE_ID_MARVELL_88ALP01_CCIC ) } ,
2006-11-04 09:25:53 -03:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , cafe_ids ) ;
static struct pci_driver cafe_pci_driver = {
. name = " cafe1000-ccic " ,
. id_table = cafe_ids ,
. probe = cafe_pci_probe ,
. remove = cafe_pci_remove ,
2007-03-25 11:36:28 -03:00
# ifdef CONFIG_PM
. suspend = cafe_pci_suspend ,
. resume = cafe_pci_resume ,
# endif
2006-11-04 09:25:53 -03:00
} ;
static int __init cafe_init ( void )
{
int ret ;
printk ( KERN_NOTICE " Marvell M88ALP01 'CAFE' Camera Controller version %d \n " ,
CAFE_VERSION ) ;
ret = pci_register_driver ( & cafe_pci_driver ) ;
if ( ret ) {
printk ( KERN_ERR " Unable to register cafe_ccic driver \n " ) ;
goto out ;
}
ret = 0 ;
out :
return ret ;
}
static void __exit cafe_exit ( void )
{
pci_unregister_driver ( & cafe_pci_driver ) ;
}
module_init ( cafe_init ) ;
module_exit ( cafe_exit ) ;