From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from newsmtp5.atmel.com ([204.2.163.5]:39642 "EHLO sjogate2.atmel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755907Ab0FKJ2g (ORCPT ); Fri, 11 Jun 2010 05:28:36 -0400 Message-ID: <4C120197.7000106@atmel.com> Date: Fri, 11 Jun 2010 11:27:51 +0200 From: Sedji Gaouaou MIME-Version: 1.0 To: video4linux-list@redhat.com, Linux Media Mailing List , mchehab@redhat.com, Andy Walls Subject: Re: [PATCH] Atmel IMAGE SENSOR INTERFACE (ISI) driver. References: <1276094787-11214-1-git-send-email-sedji.gaouaou@atmel.com> In-Reply-To: <1276094787-11214-1-git-send-email-sedji.gaouaou@atmel.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit Sender: linux-media-owner@vger.kernel.org List-ID: Hi, No comments about this patch? Regards, Sedji Le 6/9/2010 4:46 PM, Sedji Gaouaou a écrit : > Hi, > > Here is the first try for the atmel video driver. > Basically it has 2 video entries: > 1) One for the capture. It will only allow you to grab one frame > 2) One for the streaming part. > > Memoy allocation needs to be contiguous, and so is done at probe time. > For the streaming part no actual interupt is needed as the ISI handles link > list of buffers. > > I am still facing some issues with the v4l2_i2c_new_subdev_board function which > retunrs an error, but as we fix a video format I don't really need to be able > to set up the sensor format(done at probe time). > > This driver will only work or the at91sam9g45 and at91sam9m10 as it is a new > version of the Image Sensor Interface IP. > > Regards, > Sedji > > --- > drivers/media/video/atmel-isi.c | 1789 +++++++++++++++++++++++++++++++++++++++ > include/media/atmel-isi.h | 460 ++++++++++ > 2 files changed, 2249 insertions(+), 0 deletions(-) > create mode 100644 drivers/media/video/atmel-isi.c > create mode 100644 include/media/atmel-isi.h > > diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c > new file mode 100644 > index 0000000..1348830 > --- /dev/null > +++ b/drivers/media/video/atmel-isi.c > @@ -0,0 +1,1789 @@ > +/* > + * Copyright (c) 2007 Atmel Corporation > + * > + * Based on the bttv driver for Bt848 with respective copyright holders > + * > + * 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. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include > + > +#define ATMEL_ISI_VERSION KERNEL_VERSION(0, 1, 0) > + > +/* Default ISI capture buffer size */ > +#define ISI_CAPTURE_BUFFER_SIZE (800*600*2) > +/* Default ISI video frame size ie qvga */ > +#define ISI_VIDEO_BUFFER_SIZE (320*240*2) > +/* Default number of ISI video buffers */ > +/*(if qvga we can use 4 buffers)*/ > +#define ISI_VIDEO_BUFFERS 4 > +/* Interrupt mask for a single capture */ > +#define ISI_V2_CAPTURE_MASK (ISI_BIT(V2_VSYNC) \ > + | ISI_BIT(V2_CXFR_DONE) | ISI_BIT(V2_PXFR_DONE)) > +/* ISI capture buffer size */ > +static int capture_buffer_size = ISI_CAPTURE_BUFFER_SIZE; > +/* Number of buffers used for streaming video */ > +static int video_buffers = ISI_VIDEO_BUFFERS; > +static int video_buffer_size = ISI_VIDEO_BUFFER_SIZE; > + > +static int input_format = ATMEL_ISI_PIXFMT_CbYCrY; > +static u8 has_emb_sync, emb_crc_sync, hsync_act_low; > +static u8 vsync_act_low, pclk_act_falling, isi_full_mode; > +/* Preview path horizontal size */ > +static int prev_hsize = 320; > +/* Preview path vertical size */ > +static int prev_vsize = 240; > + > +/* Input image horizontal size */ > +static int image_hsize = 320; > +/* Input image vertical size */ > +static int image_vsize = 240; > + > +static struct timeval start_time; > +/* Frame rate scaler > + * 1 = capture every second frame > + * 2 = capture every third frame > + * ... > + * */ > +static int frame_rate_scaler; > + > +/* Set this value if we want to pretend a specific V4L2 output format > + * This format is for the capturing interface > + */ > +static int capture_v4l2_fmt = V4L2_PIX_FMT_YUYV; > + > +/* Set this value if we want to pretend a specific V4L2 output format > + * This format is for the streaming interface > + */ > +static int streaming_v4l2_fmt = V4L2_PIX_FMT_YUYV; > + > +/* Declare static vars that will be used as parameters */ > +/* 0<-> dev/video0, 1<-> dev/video1, -1<-> first free */ > +static int video_nr = -1; > + > +MODULE_PARM_DESC(video_buffers, "Number of frame buffers used for streaming"); > +module_param(video_buffers, int, 0664); > +MODULE_PARM_DESC(capture_buffer_size, "Capture buffer size"); > +module_param(capture_buffer_size, int, 0664); > +MODULE_PARM_DESC(image_hsize, "Horizontal size of input image"); > +module_param(image_hsize, int, 0664); > +MODULE_PARM_DESC(image_vsize, "Vertical size of input image"); > +module_param(image_vsize, int, 0664); > +MODULE_PARM_DESC(frame_rate_scaler, "Frame rate scaler"); > +module_param(frame_rate_scaler, int, 0664); > +MODULE_PARM_DESC(prev_hsize, "Horizontal image size of preview path output"); > +module_param(prev_hsize, int, 0664); > +MODULE_PARM_DESC(prev_vsize, "Vertical image size of preview path output"); > +module_param(prev_vsize, int, 0664); > +module_param(video_nr, int, 0444); > + > +/* Single frame capturing states */ > +enum { > + STATE_IDLE = 0, > + STATE_CAPTURE_READY, > + STATE_CAPTURE_WAIT_SOF, > + STATE_CAPTURE_IN_PROGRESS, > + STATE_CAPTURE_DONE, > + STATE_CAPTURE_ERROR, > +}; > + > +/* Frame buffer states > + * FRAME_UNUSED Frame(buffer) is not used by the ISI module -> an application > + * can usually read out data in this state > + * FRAME_QUEUED An application has queued the buffer in the incoming queue > + * FRAME_DONE The ISI module has filled the buffer with data and placed is on > + * the outgoing queue > + * FRAME_ERROR Not used at the moment > + * */ > +enum frame_status { > + FRAME_UNUSED, > + FRAME_QUEUED, > + FRAME_DONE, > + FRAME_ERROR, > +}; > +/* Frame buffer descriptor > + * Used by the ISI module as a linked list for the DMA controller. > + */ > +struct fbd { > + /* Physical address of the frame buffer */ > + dma_addr_t fb_address; > +#if defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT91SAM9M10) > + /* DMA Control Register(new: only in HISI2) */ > + u32 dma_ctrl; > +#endif > + /* Physical address of the next fbd */ > + dma_addr_t next_fbd_address; > +}; > + > +/* Frame buffer data > + */ > +struct frame_buffer { > + /* Frame buffer descriptor > + * Used by the ISI DMA controller to provide linked list DMA operation > + */ > + struct fbd fb_desc; > + /* Pointer to the start of the frame buffer */ > + void *frame_buffer; > + /* Timestamp of the captured frame */ > + struct timeval timestamp; > + /* Frame number of the frame */ > + unsigned long sequence; > + /* Buffer number*/ > + int index; > + /* Bytes used in the buffer for data, needed as buffers are always > + * aligned to pages and thus may be bigger than the amount of data*/ > + int bytes_used; > + /* Mmap count > + * Counter to measure how often this buffer is mmapped > + */ > + int mmap_count; > + /* Buffer status */ > + enum frame_status status; > +}; > + > +struct atmel_isi { > + /* ISI module spin lock. Protects against concurrent access of variables > + * that are shared with the ISR */ > + spinlock_t lock; > + void __iomem *regs; > + /* Pointer to the start of the fbd list */ > + dma_addr_t fbd_list_start; > + /* Frame buffers */ > + struct frame_buffer video_buffer[ISI_VIDEO_BUFFERS]; > + /* Frame buffer currently used by the ISI module */ > + struct frame_buffer *current_buffer; > + /* Size of a frame buffer */ > + size_t capture_buffer_size; > + /* Streaming status > + * If set ISI is in streaming mode */ > + int streaming; > + /* Queue for incoming buffers > + * The buffer number (index) is stored in the fifo as reference > + */ > + int head, tail; > + /* State of the ISI module in capturing mode */ > + int state; > + /* Pointer to ISI buffer */ > + void *capture_buf; > + /* Physical address of the capture buffer */ > + dma_addr_t capture_phys; > + /* Size of the ISI buffer */ > + size_t capture_buf_size; > + /* Capture/streaming wait queue */ > + wait_queue_head_t capture_wq; > + > + struct atmel_isi_format format; > + struct atmel_isi_format streaming_format; > + > + struct mutex mutex; > + /* User counter for the streaming interface */ > + int stream_users; > + /* User counter of the capture interface */ > + int capture_users; > + > + /* v4l2 device */ > + struct device *dev; > + struct v4l2_device v4l2_dev; > + /* sub devices */ > + struct v4l2_subdev *sd; > + /* Video device for capturing */ > + struct video_device cdev; > + /* Video device for streaming */ > + struct video_device vdev; > + > + /* i2c subdevice board info */ > + struct i2c_board_info board_info; > + struct i2c_adapter *i2c_adapter; > + > + struct completion reset_complete; > + struct clk *pclk; > + struct clk *hclk; > + struct platform_device *pdev; > + unsigned int irq; > +}; > + > +#define to_atmel_isi(vdev) container_of(vdev, struct atmel_isi, vdev) > + > +struct atmel_isi_fh { > + struct atmel_isi *isi; > + unsigned int read_off; > +}; > + > + > +static void atmel_isi_set_default_format(struct atmel_isi *isi) > +{ > + > + isi->format.pix.width = (u32)min((u32)2048l, (u32)image_hsize); > + isi->format.pix.height = (u32)min((u32)2048l, (u32)image_vsize); > + > + /* Set capture format if we have explicitely specified one */ > + if (capture_v4l2_fmt) { > + isi->format.pix.pixelformat = capture_v4l2_fmt; > + } else { > + /* Codec path output format */ > + isi->format.pix.pixelformat = V4L2_PIX_FMT_YVYU; > + } > + > + /* The ISI module codec path tries to output YUV 4:2:2 > + * Therefore two pixels will be in a 32bit word */ > + isi->format.pix.bytesperline = ALIGN(isi->format.pix.width * 2, 4); > + isi->format.pix.sizeimage = isi->format.pix.bytesperline * > + isi->format.pix.height; > + > + pr_debug("set default format: width=%d height=%d\n", > + isi->format.pix.width, isi->format.pix.height); > + > + isi->streaming_format.pix.width = isi->format.pix.width; > + isi->streaming_format.pix.height = isi->format.pix.height; > + isi->streaming_format.pix.bytesperline = isi->format.pix.bytesperline; > + isi->streaming_format.pix.sizeimage = isi->format.pix.sizeimage; > + > + /* Set streaming format if we have explicitely specified one */ > + if (streaming_v4l2_fmt) { > + isi->streaming_format.pix.pixelformat = streaming_v4l2_fmt; > + } else { > + /* Preview path output format > + * Would be logically V4L2_PIX_FMT_BGR555X > + * but this format does not exist in the specification > + * So for now we pretend V4L2_PIX_FMT_RGB555X > + * Also the Greyscale format does not fit on top of the V4L2 > + * format but for now we just return it. > + */ > + if (input_format == ATMEL_ISI_PIXFMT_GREY) > + isi->streaming_format.pix.pixelformat = > + V4L2_PIX_FMT_GREY; > + else > + isi->streaming_format.pix.pixelformat = > + V4L2_PIX_FMT_RGB555X; > + } > + > + if (input_format) { > + isi->format.input_format = input_format; > + /* Not needed but for completeness*/ > + isi->streaming_format.input_format = input_format; > + } > + > +} > + > +static int atmel_isi_init_hardware(struct atmel_isi *isi) > +{ > + u32 cfg2, cfg1, cr, ctrl; > + > + cr = 0; > + switch (isi->format.input_format) { > + case ATMEL_ISI_PIXFMT_GREY: > + cr = ISI_BIT(GRAYSCALE); > + break; > + case ATMEL_ISI_PIXFMT_YCrYCb: > + cr = ISI_BF(V2_YCC_SWAP, 0); > + break; > + case ATMEL_ISI_PIXFMT_YCbYCr: > + cr = ISI_BF(V2_YCC_SWAP, 1); > + break; > + case ATMEL_ISI_PIXFMT_CrYCbY: > + cr = ISI_BF(V2_YCC_SWAP, 2); > + break; > + case ATMEL_ISI_PIXFMT_CbYCrY: > + cr = ISI_BF(YCC_SWAP, 3); > + break; > + case ATMEL_ISI_PIXFMT_RGB24: > + cr = ISI_BIT(V2_COL_SPACE) | ISI_BF(V2_RGB_CFG, 0); > + break; > + case ATMEL_ISI_PIXFMT_BGR24: > + cr = ISI_BIT(V2_COL_SPACE) | ISI_BF(V2_RGB_CFG, 1); > + break; > + case ATMEL_ISI_PIXFMT_RGB16: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_MODE) > + | ISI_BF(V2_RGB_CFG, 0)); > + break; > + case ATMEL_ISI_PIXFMT_BGR16: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_MODE) > + | ISI_BF(V2_RGB_CFG, 1)); > + break; > + case ATMEL_ISI_PIXFMT_GRB16: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_MODE) > + | ISI_BF(V2_RGB_CFG, 2)); > + break; > + case ATMEL_ISI_PIXFMT_GBR16: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_MODE) > + | ISI_BF(V2_RGB_CFG, 3)); > + break; > + case ATMEL_ISI_PIXFMT_RGB24_REV: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_SWAP) > + | ISI_BF(V2_RGB_CFG, 0)); > + break; > + case ATMEL_ISI_PIXFMT_BGR24_REV: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_SWAP) > + | ISI_BF(V2_RGB_CFG, 1)); > + break; > + case ATMEL_ISI_PIXFMT_RGB16_REV: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_SWAP) > + | ISI_BIT(V2_RGB_MODE) | ISI_BF(V2_RGB_CFG, 0)); > + break; > + case ATMEL_ISI_PIXFMT_BGR16_REV: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_SWAP) > + | ISI_BIT(V2_RGB_MODE) | ISI_BF(V2_RGB_CFG, 1)); > + break; > + case ATMEL_ISI_PIXFMT_GRB16_REV: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_SWAP) > + | ISI_BIT(V2_RGB_MODE) | ISI_BF(V2_RGB_CFG, 2)); > + break; > + case ATMEL_ISI_PIXFMT_GBR16_REV: > + cr = (ISI_BIT(V2_COL_SPACE) | ISI_BIT(V2_RGB_SWAP) > + | ISI_BIT(V2_RGB_MODE) | ISI_BF(V2_RGB_CFG, 3)); > + break; > + default: > + return -EINVAL; > + } > + > + cfg1 = ISI_BF(V2_EMB_SYNC, (has_emb_sync)) > + | ISI_BF(V2_HSYNC_POL, hsync_act_low) > + | ISI_BF(V2_VSYNC_POL, vsync_act_low) > + | ISI_BF(V2_PIXCLK_POL, pclk_act_falling) > + | ISI_BF(V2_FULL, isi_full_mode); > + > + ctrl = ISI_BIT(DIS); > + > + isi_writel(isi, V2_CFG1, cfg1); > + isi_writel(isi, V2_CTRL, ctrl); > + /* Check if module properly disable */ > + while (isi_readl(isi, V2_STATUS)& ISI_BIT(V2_DIS_DONE)) > + cpu_relax(); > + > + cfg2 = isi_readl(isi, V2_CFG2); > + cfg2 |= cr; > + cfg2 = ISI_BFINS(V2_IM_VSIZE, isi->format.pix.height - 1, cfg2); > + cfg2 = ISI_BFINS(V2_IM_HSIZE, isi->format.pix.width - 1, cfg2); > + > + isi_writel(isi, V2_CFG2, cfg2); > + > + return 0; > +} > + > +static int atmel_isi_start_capture(struct atmel_isi *isi) > +{ > + u32 cr, sr = 0; > + int ret; > + > + spin_lock_irq(&isi->lock); > + isi->state = STATE_IDLE; > + > + /* clear any pending SOF interrupt */ > + sr = isi_readl(isi, V2_STATUS); > + /*<=> SOF in previous ISI */ > + isi_writel(isi, V2_INTEN, ISI_BIT(V2_VSYNC)); > + isi_writel(isi, V2_CTRL, isi_readl(isi, V2_CTRL) | ISI_BIT(V2_EN)); > + > + spin_unlock_irq(&isi->lock); > + > + pr_debug("isi: waiting for SOF\n"); > + > + ret = wait_event_interruptible(isi->capture_wq, > + isi->state != STATE_IDLE); > + if (ret) > + return ret; > + > + if (isi->state != STATE_CAPTURE_READY) > + return -EIO; > + > + /* > + * Do a codec request. Next SOF indicates start of capture, > + * the one after that indicates end of capture. > + */ > + pr_debug("isi: starting capture\n"); > + > + /* Enable */ > + isi_writel(isi, V2_DMA_CHER, ISI_BIT(V2_DMA_C_CH_EN)); > + isi_writel(isi, V2_DMA_C_ADDR, isi->capture_phys); > + > + spin_lock_irq(&isi->lock); > + isi->state = STATE_CAPTURE_WAIT_SOF; > + /* Check if already in a frame */ > + while (isi_readl(isi, V2_STATUS)& ISI_BIT(V2_CDC)) > + cpu_relax(); > + cr = isi_readl(isi, V2_CTRL); > + cr |= ISI_BIT(V2_CDC); > + isi_writel(isi, V2_CTRL, cr); > + isi_writel(isi, V2_INTEN, ISI_V2_CAPTURE_MASK); > + > + spin_unlock_irq(&isi->lock); > + > + return 0; > +} > + > +static void atmel_isi_capture_done(struct atmel_isi *isi, > + int state) > +{ > + u32 cr; > + > + cr = isi_readl(isi, V2_CTRL); > + cr&= ~ISI_BIT(V2_CDC); > + isi_writel(isi, V2_CTRL, cr); > + > + isi->state = state; > + wake_up_interruptible(&isi->capture_wq); > + isi_writel(isi, V2_INTDIS, ISI_V2_CAPTURE_MASK); > +} > + > +static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi, > + int sequence) > +{ > + return IRQ_HANDLED; > +} > + > +/* isi interrupt service routine */ > +static irqreturn_t isi_interrupt(int irq, void *dev_id) > +{ > + struct atmel_isi *isi = dev_id; > + u32 status, mask, pending; > + irqreturn_t ret = IRQ_NONE; > + static int sequence; > + > + spin_lock(&isi->lock); > + > + status = isi_readl(isi, V2_STATUS); > + mask = isi_readl(isi, V2_INTMASK); > + pending = status& mask; > + > + if (isi->streaming) { > + if (likely(pending& (ISI_BIT(V2_CXFR_DONE)))) { > + sequence++; > + ret = atmel_isi_handle_streaming(isi, sequence); > + } > + } else { > + while (pending) { > + if (pending& > + (ISI_BIT(V2_C_OVR) | ISI_BIT(V2_FR_OVR))) { > + atmel_isi_capture_done(isi, > + STATE_CAPTURE_ERROR); > + pr_debug("%s: FIFO overrun (status=0x%x)\n", > + isi->vdev.name, status); > + } else if (pending& > + (ISI_BIT(V2_VSYNC) | ISI_BIT(V2_CDC))) { > + switch (isi->state) { > + case STATE_IDLE: > + isi->state = STATE_CAPTURE_READY; > + wake_up_interruptible(&isi->capture_wq); > + break; > + case STATE_CAPTURE_READY: > + break; > + case STATE_CAPTURE_WAIT_SOF: > + isi->state = STATE_CAPTURE_IN_PROGRESS; > + break; > + } > + } > + if (pending& > + (ISI_BIT(V2_CXFR_DONE) | ISI_BIT(V2_PXFR_DONE))) { > + if (isi->state == STATE_CAPTURE_IN_PROGRESS) > + atmel_isi_capture_done(isi, > + STATE_CAPTURE_DONE); > + } > + > + if (pending& ISI_BIT(V2_SRST)) { > + complete(&isi->reset_complete); > + isi_writel(isi, V2_INTDIS, ISI_BIT(V2_SRST)); > + } > + > + status = isi_readl(isi, V2_STATUS); > + mask = isi_readl(isi, V2_INTMASK); > + pending = status& mask; > + ret = IRQ_HANDLED; > + } > + } > + spin_unlock(&isi->lock); > + > + return ret; > +} > +/* ------------------------------------------------------------------------ > + * IOCTL videoc handling > + * ----------------------------------------------------------------------*/ > + > +/* --------Capture ioctls ------------------------------------------------*/ > +/* Device capabilities callback function. > + */ > +static int atmel_isi_capture_querycap(struct file *file, void *priv, > + struct v4l2_capability *cap) > +{ > + strcpy(cap->driver, "atmel-isi"); > + strcpy(cap->card, "Atmel Image Sensor Interface"); > + cap->version = ATMEL_ISI_VERSION; > + /* V4L2_CAP_VIDEO_CAPTURE -> This is a capture device > + * V4L2_CAP_READWRITE -> read/write interface used > + */ > + cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE > + | V4L2_CAP_READWRITE > + ); > + return 0; > +} > + > +/* Input enumeration callback function. > + * Enumerates available input devices. > + * This can be called many times from the V4L2-layer by > + * incrementing the index to get all avaliable input devices. > + */ > +static int atmel_isi_capture_enum_input(struct file *file, void *priv, > + struct v4l2_input *input) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + > + /* Just one input (ISI) is available */ > + if (input->index != 0) > + return -EINVAL; > + > + /* Set input name as camera name */ > + strlcpy(input->name, "atmel-isi stream", sizeof(input->name)); > + input->type = V4L2_INPUT_TYPE_CAMERA; > + > + /* Set to this value just because this should be set to a > + * defined value > + */ > + input->std = V4L2_STD_PAL; > + > + return 0; > +} > +/* Selects an input device. > + * One input device (ISI) currently supported. > + */ > +static int atmel_isi_capture_s_input(struct file *file, void *priv, > + unsigned int index) > +{ > + if (index != 0) > + return -EINVAL; > + return 0; > +} > + > +/* Gets current input device. > + */ > +static int atmel_isi_capture_g_input(struct file *file, void *priv, > + unsigned int *index) > +{ > + *index = 0; > + return 0; > +} > + > +/* Format callback function > + * Returns a v4l2_fmtdesc structure with according values to a > + * index. > + * This function is called from user space until it returns > + * -EINVAL. > + */ > +static int atmel_isi_capture_enum_fmt_cap(struct file *file, void *priv, > + struct v4l2_fmtdesc *fmt) > +{ > + if (fmt->index != 0) > + return -EINVAL; > + > + /* if we want to pretend another ISI output > + * this is usefull if we input an other input format from a camera > + * than specified in the ISI -> makes it possible to swap bytes > + * in the ISI output format but messes up the preview path output > + */ > + if (capture_v4l2_fmt) { > + fmt->pixelformat = capture_v4l2_fmt; > + } else { > + /* This is the format the ISI tries to output */ > + strcpy(fmt->description, "YCbYCr (YUYV) 4:2:2"); > + fmt->pixelformat = V4L2_PIX_FMT_YUYV; > + } > + > + return 0; > +} > + > +static int atmel_isi_capture_try_fmt_cap(struct file *file, void *priv, > + struct v4l2_format *vfmt) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + /* Just return the current format for now */ > + memcpy(&vfmt->fmt.pix,&isi->format.pix, > + sizeof(struct v4l2_pix_format)); > + > + return 0; > +} > + > +/* Gets current hardware configuration > + * For capture devices the pixel format settings are > + * important. > + */ > +static int atmel_isi_capture_g_fmt_cap(struct file *file, void *priv, > + struct v4l2_format *vfmt) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + > + /* Return current pixel format */ > + memcpy(&vfmt->fmt.pix,&isi->format.pix, > + sizeof(struct v4l2_pix_format)); > + > + return 0; > +} > + > +static int atmel_isi_capture_s_fmt_cap(struct file *file, void *priv, > + struct v4l2_format *vfmt) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + int ret = 0; > + > + /* We have a fixed format so just copy the current format > + * back > + */ > + memcpy(&vfmt->fmt.pix,&isi->format.pix, > + sizeof(struct v4l2_pix_format)); > + > + return ret; > +} > + > +/* ------------ Preview path ioctls ------------------------------*/ > +/* Device capabilities callback function. > + */ > +static int atmel_isi_streaming_querycap(struct file *file, void *priv, > + struct v4l2_capability *cap) > +{ > + strcpy(cap->driver, "atmel-isi"); > + strcpy(cap->card, "Atmel Image Sensor Interface"); > + cap->version = ATMEL_ISI_VERSION; > + /* V4L2_CAP_VIDEO_CAPTURE -> This is a capture device > + * V4L2_CAP_READWRITE -> read/write interface used > + * V4L2_CAP_STREAMING -> ioctl + mmap interface used > + */ > + cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE > + | V4L2_CAP_READWRITE > + | V4L2_CAP_STREAMING > + ); > + return 0; > +} > +/* Input enumeration callback function. > + * Enumerates available input devices. > + * This can be called many times from the V4L2-layer by > + * incrementing the index to get all avaliable input devices. > + */ > +static int atmel_isi_streaming_enum_input(struct file *file, void *priv, > + struct v4l2_input *input) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + > + /* Just one input (ISI) is available */ > + if (input->index != 0) > + return -EINVAL; > + > + /* Set input name as camera name */ > + strlcpy(input->name, "atmel-isi", sizeof(input->name)); > + input->type = V4L2_INPUT_TYPE_CAMERA; > + > + /* Set to this value just because this should be set to a > + * defined value > + */ > + input->std = V4L2_STD_PAL; > + > + return 0; > +} > +/* Selects an input device. > + * One input device (ISI) currently supported. > + */ > +static int atmel_isi_streaming_s_input(struct file *file, void *priv, > + unsigned int index) > +{ > + if (index != 0) > + return -EINVAL; > + > + return 0; > +} > +/* Gets current input device. > + */ > +static int atmel_isi_streaming_g_input(struct file *file, void *priv, > + unsigned int *index) > +{ > + *index = 0; > + return 0; > +} > + > +/* Format callback function > + * Returns a v4l2_fmtdesc structure with according values to a > + * index. > + * This function is called from user space until it returns > + * -EINVAL. > + */ > +static int atmel_isi_streaming_enum_fmt_cap(struct file *file, void *priv, > + struct v4l2_fmtdesc *fmt) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + > + if (fmt->index != 0) > + return -EINVAL; > + > + /* TODO: Return all possible formats > + * This depends on ISI and camera. > + * A enum_fmt function or a data structure should be > + * added to the camera driver. > + * For now just one format supported > + */ > + if (streaming_v4l2_fmt) > + strcpy(fmt->description, "Pretended format"); > + else > + strcpy(fmt->description, "Normal format"); > + > + /* The pretended and normal format are already set earlier */ > + fmt->pixelformat = isi->streaming_format.pix.pixelformat; > + > + return 0; > +} > +static int atmel_isi_streaming_try_fmt_cap(struct file *file, void *priv, > + struct v4l2_format *vfmt) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + > + /* FIXME For now we just return the current format*/ > + memcpy(&vfmt->fmt.pix,&isi->streaming_format.pix, > + sizeof(struct v4l2_pix_format)); > + return 0; > +} > +/* Gets current hardware configuration > + * For capture devices the pixel format settings are > + * important. > + */ > +static int atmel_isi_streaming_g_fmt_cap(struct file *file, void *priv, > + struct v4l2_format *vfmt) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + > + /*Copy current pixel format structure to user space*/ > + memcpy(&vfmt->fmt.pix,&isi->streaming_format.pix, > + sizeof(struct v4l2_pix_format)); > + > + return 0; > +} > +static int atmel_isi_streaming_s_fmt_cap(struct file *file, void *priv, > + struct v4l2_format *vfmt) > +{ > + struct atmel_isi_fh *fh = priv; > + struct atmel_isi *isi = fh->isi; > + int ret = 0; > + > + if (vfmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) { > + /* Just return the current format as we do not support > + * format switching */ > + pr_debug("S_FMT: format not supported(only YUV)\n"); > + memcpy(&vfmt->fmt.pix,&isi->streaming_format.pix, > + sizeof(struct v4l2_pix_format)); > + } else { > + /* Set the sensor accordingly */ > + memcpy(&isi->format.pix,&vfmt->fmt.pix, > + sizeof(struct v4l2_pix_format)); > + v4l2_subdev_call(isi->sd, video, s_fmt, vfmt); > + } > + > + return ret; > +} > +/* Checks if control is supported in driver > + * No controls currently supported yet > + */ > +static int atmel_isi_streaming_queryctrl(struct file *file, void *priv, > + struct v4l2_queryctrl *qc) > +{ > + switch (qc->id) { > + case V4L2_CID_BRIGHTNESS: > + strcpy(qc->name, "Brightness"); > + qc->minimum = 0; > + qc->maximum = 100; > + qc->step = 1; > + qc->default_value = 50; > + qc->flags = 0; > + break; > + default: > + return -EINVAL; > + } > + return 0; > +} > +static int atmel_isi_streaming_g_ctrl(struct file *file, void *priv, > + struct v4l2_control *ctrl) > +{ > + switch (ctrl->id) { > + case V4L2_CID_BRIGHTNESS: > + ctrl->value = 0; > + break; > + default: > + return -EINVAL; > + } > + return 0; > +} > +static int atmel_isi_streaming_s_ctrl(struct file *file, void *priv, > + struct v4l2_control *ctrl) > +{ > + switch (ctrl->id) { > + case V4L2_CID_BRIGHTNESS: > + break; > + default: > + return -EINVAL; > + } > + return 0; > +} > +static int atmel_isi_reqbufs(struct file *file, void *private_data, > + struct v4l2_requestbuffers *req) > +{ > + /* Only memory mapped buffers supported*/ > + if (req->memory != V4L2_MEMORY_MMAP) { > + pr_debug("atmel_isi: buffer format not supported\n"); > + return -EINVAL; > + } > + pr_debug("atmel_isi: Requested %d buffers. Using %d buffers\n", > + req->count, video_buffers); > + /* buffer number is fixed for now as it is difficult to get > + * that memory at runtime */ > + req->count = video_buffers; > + memset(&req->reserved, 0, sizeof(req->reserved)); > + return 0; > +} > + > +static int atmel_isi_querybuf(struct file *file, void *private_data, > + struct v4l2_buffer *buf) > +{ > + struct atmel_isi_fh *fh = private_data; > + struct atmel_isi *isi = fh->isi; > + struct frame_buffer *buffer; > + > + if (unlikely(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) > + return -EINVAL; > + if (unlikely(buf->index>= video_buffers)) > + return -EINVAL; > + > + buffer =&(isi->video_buffer[buf->index]); > + > + buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > + buf->length = video_buffer_size; > + buf->memory = V4L2_MEMORY_MMAP; > + > + /* set index as mmap reference to the buffer */ > + buf->m.offset = buf->index<< PAGE_SHIFT; > + > + switch (buffer->status) { > + case FRAME_UNUSED: > + case FRAME_ERROR: > + case FRAME_QUEUED: > + buf->flags |= V4L2_BUF_FLAG_QUEUED; > + buf->bytesused = buffer->bytes_used; > + break; > + case FRAME_DONE: > + buf->flags |= V4L2_BUF_FLAG_DONE; > + buf->bytesused = buffer->bytes_used; > + buf->sequence = buffer->sequence; > + buf->timestamp = buffer->timestamp; > + break; > + } > + > + buf->field = V4L2_FIELD_NONE; /* no interlacing stuff */ > + > + if (buffer->mmap_count) > + buf->flags |= V4L2_BUF_FLAG_MAPPED; > + else > + buf->flags&= ~V4L2_BUF_FLAG_MAPPED; > + > + pr_debug("atmel_isi: querybuf index:%d offset:%d\n", > + buf->index, buf->m.offset); > + > + return 0; > +} > + > +static int atmel_isi_qbuf(struct file *file, void *private_data, > + struct v4l2_buffer *buf) > +{ > + struct atmel_isi_fh *fh = private_data; > + struct atmel_isi *isi = fh->isi; > + struct frame_buffer *buffer, *next_buffer; > + u32 old_ctrl; > + > + if (unlikely(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) > + return -EINVAL; > + > + if (unlikely(buf->index>= video_buffers || buf->index< 0)) { > + pr_debug("Buffer index is not valid index=%d\n", buf->index); > + return -EINVAL; > + } > + > + if (unlikely(buf->memory != V4L2_MEMORY_MMAP)) { > + pr_debug("Buffer is not of MEMORY_MMAP type\n"); > + return -EINVAL; > + } > + > + buffer =&(isi->video_buffer[isi->tail]); > + isi->tail++; > + if (isi->tail == (video_buffers)) > + isi->tail = 0; > + next_buffer =&(isi->video_buffer[isi->tail]); > + > + /* disable fetch on next buff */ > + next_buffer->fb_desc.dma_ctrl&= ~ISI_BIT(V2_DMA_FETCH); > + buffer->fb_desc.dma_ctrl |= ISI_BIT(V2_DMA_FETCH); > + > + /* Restart the ISI transfert if suspended */ > + old_ctrl = isi_readl(isi, V2_DMA_C_CTRL); > + isi_writel(isi, V2_DMA_C_CTRL, ISI_BIT(V2_DMA_FETCH) | old_ctrl); > + isi_writel(isi, V2_DMA_CHER, ISI_BIT(V2_DMA_C_CH_EN)); > + > + mutex_lock(&isi->mutex); > + buf->flags |= V4L2_BUF_FLAG_QUEUED; > + buf->flags&= ~V4L2_BUF_FLAG_DONE; > + buffer->status = FRAME_QUEUED; > + > + mutex_unlock(&isi->mutex); > + > + return 0; > +} > + > +static int atmel_isi_dqbuf(struct file *file, void *private_data, > + struct v4l2_buffer *buf) > +{ > + struct atmel_isi_fh *fh = private_data; > + struct atmel_isi *isi = fh->isi; > + struct frame_buffer *buffer; > + static int sequence; > + > + if (unlikely(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) > + return -EINVAL; > + > + buffer =&(isi->video_buffer[isi->head]); > + /* TEST if C_DONE == 1 ie isi transfer */ > + if ((buffer->fb_desc.dma_ctrl& ISI_BIT(V2_DMA_DONE)) == 0) { > + pr_debug("In dqbuf: Buffer not ready\n"); > + return -EAGAIN; > + } else { > + buffer->status = FRAME_DONE; > + } > + > + buffer->fb_desc.dma_ctrl&= ~ISI_BIT(V2_DMA_DONE) ; > + > + if (unlikely(buffer->status == FRAME_QUEUED)) { > + if (isi->streaming == 0) > + return 0; > + pr_debug("isi: error, dequeued buffer not ready\n"); > + return -EINVAL; > + } > + > + mutex_lock(&isi->mutex); > + buf->index = isi->head; > + buf->bytesused = buffer->bytes_used; > + do_gettimeofday(&buf->timestamp); > + buf->timestamp.tv_sec -= start_time.tv_sec; > + buf->timestamp.tv_usec -= start_time.tv_usec; > + buf->sequence = sequence++; > + buf->m.offset = (isi->head)<< PAGE_SHIFT; > + buffer->status = FRAME_UNUSED; > + buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; > + buf->length = video_buffer_size; > + buf->field = V4L2_FIELD_NONE; > + buf->memory = V4L2_MEMORY_MMAP; > + mutex_unlock(&isi->mutex); > + > + isi->head++; > + if ((isi->head) == (video_buffers)) > + isi->head = 0; > + > + return 0; > +} > +static int atmel_isi_streamon(struct file *file, void *private_data, > + enum v4l2_buf_type type) > +{ > + struct atmel_isi_fh *fh = private_data; > + struct atmel_isi *isi = fh->isi; > + int i; > + struct frame_buffer *buffer; > + u32 cfg1, ctrl; > + > + if (unlikely(type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) > + return -EINVAL; > + > + /* reset ISI transfert desc */ > + for (i = 0; i< (video_buffers - 1); i++) > + isi->video_buffer[i].fb_desc.dma_ctrl = > + ISI_BIT(V2_DMA_FETCH) | ISI_BIT(V2_DMA_WB); > + > + /* ISI will stop at this point(last buffer of the queue) */ > + isi->video_buffer[i].fb_desc.dma_ctrl = ISI_BIT(V2_DMA_WB); > + > + buffer =&(isi->video_buffer[isi->head]); > + > + spin_lock_irq(&isi->lock); > + isi->streaming = 1; > + > + ctrl = isi_readl(isi, V2_CTRL); > + cfg1 = isi_readl(isi, V2_CFG1); > + /* Disable irq: cxfr for the codec path, pxfr for the preview path */ > + isi_writel(isi, V2_INTDIS, > + ISI_BIT(V2_CXFR_DONE) | ISI_BIT(V2_PXFR_DONE)); > + > + /* Enable codec path */ > + ctrl |= ISI_BIT(V2_CDC); > + > + /* Write the address of the first frame buffer in the C_ADDR reg > + * write the address of the first descriptor(link list of buffer) > + * in the C_DSCR reg, and enable dma channel. > + */ > + isi_writel(isi, V2_DMA_C_DSCR, (__pa(&(buffer->fb_desc)))); > + isi_writel(isi, V2_DMA_C_CTRL, > + ISI_BIT(V2_DMA_FETCH) | ISI_BIT(V2_DMA_DONE)); > + isi_writel(isi, V2_DMA_CHER, ISI_BIT(V2_DMA_C_CH_EN)); > + > + /* Enable linked list */ > + cfg1 |= ISI_BF(V2_FRATE, frame_rate_scaler) | ISI_BIT(V2_DISCR); > + > + /* Enable ISI module*/ > + ctrl |= ISI_BIT(V2_ENABLE); > + isi_writel(isi, V2_CTRL, ctrl); > + isi_writel(isi, V2_CFG1, cfg1); > + > + /* To properly set the timestamp we need to record the time at start > + * up*/ > + do_gettimeofday(&start_time); > + > + spin_unlock_irq(&isi->lock); > + > + return 0; > +} > + > +static int atmel_isi_streamoff(struct file *file, void *private_data, > + enum v4l2_buf_type type) > +{ > + struct atmel_isi_fh *fh = private_data; > + struct atmel_isi *isi = fh->isi; > + int reqnr; > + > + if (unlikely(type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) > + return -EINVAL; > + > + spin_lock_irq(&isi->lock); > + isi->streaming = 0; > + > + /* Disble codec path */ > + isi_writel(isi, V2_CTRL, isi_readl(isi, V2_CTRL)& (~ISI_BIT(V2_CDC))); > + /* Disable interrupts */ > + isi_writel(isi, V2_INTDIS, > + ISI_BIT(V2_CXFR_DONE) | ISI_BIT(V2_PXFR_DONE)); > + /* Disable ISI module*/ > + isi_writel(isi, V2_CTRL, isi_readl(isi, V2_CTRL) | ISI_BIT(V2_DIS)); > + > + spin_unlock_irq(&isi->lock); > + > + for (reqnr = 0; reqnr< video_buffers; reqnr++) > + isi->video_buffer[reqnr].status = FRAME_UNUSED; > + > + return 0; > +} > +static int atmel_isi_g_parm(struct file *file, void *f, > + struct v4l2_streamparm *parm) > +{ > + int err = 0; > + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) > + return -EINVAL; > + > + return err; > +} > +/*----------------------------------------------------------------------------*/ > + > +static int atmel_isi_init(struct atmel_isi *isi) > +{ > + unsigned long timeout; > + > + /* > + * Reset the controller and wait for completion. > + * The reset will only succeed if we have a > + * pixel clock from the camera. > + */ > + init_completion(&isi->reset_complete); > + > + isi_writel(isi, V2_INTEN, ISI_BIT(V2_SRST)); > + isi_writel(isi, V2_CTRL, ISI_BIT(V2_SRST)); > + > + timeout = wait_for_completion_timeout(&isi->reset_complete, > + msecs_to_jiffies(100)); > + if (timeout == 0) > + return -ETIMEDOUT; > + > + isi_writel(isi, V2_INTDIS, ~0UL); > + > + atmel_isi_set_default_format(isi); > + > + atmel_isi_init_hardware(isi); > + > + return 0; > +} > + > +static int atmel_isi_capture_close(struct file *file) > +{ > + struct atmel_isi_fh *fh = file->private_data; > + struct atmel_isi *isi = fh->isi; > + u32 cr; > + > + mutex_lock(&isi->mutex); > + > + isi->capture_users--; > + kfree(fh); > + > + /* Stop camera and ISI if driver has no users */ > + if (!isi->stream_users) { > + > + spin_lock_irq(&isi->lock); > + > + cr = isi_readl(isi, V2_CTRL); > + cr |= ISI_BIT(V2_DIS); > + isi_writel(isi, V2_CTRL, cr); > + > + spin_unlock_irq(&isi->lock); > + } > + mutex_unlock(&isi->mutex); > + > + return 0; > +} > + > +static int atmel_isi_capture_open(struct file *file) > +{ > + struct video_device *vdev = video_devdata(file); > + struct atmel_isi *isi = container_of(vdev, struct atmel_isi, cdev); > + struct atmel_isi_fh *fh; > + int ret = -EBUSY; > + > + pr_debug("%s: opened\n", isi->cdev.name); > + > + mutex_lock(&isi->mutex); > + > + if (isi->capture_users) { > + pr_debug("%s: open(): device busy\n", isi->cdev.name); > + goto out; > + } > + > + /* If the streaming interface has no users too we do a > + * init of the hardware and software configuration. > + */ > + if (isi->stream_users == 0) { > + ret = atmel_isi_init(isi); > + if (ret) > + goto out; > + } > + > + ret = -ENOMEM; > + fh = kzalloc(sizeof(struct atmel_isi_fh), GFP_KERNEL); > + if (!fh) { > + pr_debug("%s: open(): out of memory\n", isi->cdev.name); > + goto out; > + } > + > + > + fh->isi = isi; > + file->private_data = fh; > + isi->capture_users++; > + > + ret = 0; > + > +out: > + mutex_unlock(&isi->mutex); > + return ret; > +} > + > +static ssize_t atmel_isi_capture_read(struct file *file, char __user *data, > + size_t count, loff_t *ppos) > +{ > + struct atmel_isi_fh *fh = file->private_data; > + struct atmel_isi *isi = fh->isi; > + int state; > + int ret; > + > + state = STATE_IDLE; > + > + pr_debug("isi: read %zu bytes read_off=%u state=%u sizeimage=%u\n", > + count, fh->read_off, state, isi->format.pix.sizeimage); > + > + atmel_isi_start_capture(isi); > + > + ret = wait_event_interruptible(isi->capture_wq, > + (isi->state == STATE_CAPTURE_DONE) > + || (isi->state == STATE_CAPTURE_ERROR)); > + > + if (ret) > + return ret; > + > + if (isi->state == STATE_CAPTURE_ERROR) { > + isi->state = STATE_IDLE; > + return -EIO; > + } > + > + fh->read_off = 0; > + > + count = min(count, (size_t)isi->format.pix.sizeimage - fh->read_off); > + ret = copy_to_user(data, isi->capture_buf + fh->read_off, count); > + if (ret) > + return -EFAULT; > + > + fh->read_off += count; > + if (fh->read_off>= isi->format.pix.sizeimage) > + isi->state = STATE_IDLE; > + > + return count; > +} > + > +static void atmel_isi_capture_release(struct video_device *vdev) > +{ > + pr_debug("%s: release\n", vdev->name); > +} > +/* ----------------- Streaming interface -------------------------------------*/ > +static void atmel_isi_vm_open(struct vm_area_struct *vma) > +{ > + struct frame_buffer *buffer = > + (struct frame_buffer *) vma->vm_private_data; > + buffer->mmap_count++; > + pr_debug("atmel_isi: vm_open count=%d\n", buffer->mmap_count); > +} > + > +static void atmel_isi_vm_close(struct vm_area_struct *vma) > +{ > + struct frame_buffer *buffer = > + (struct frame_buffer *) vma->vm_private_data; > + pr_debug("atmel_isi: vm_close count=%d\n", buffer->mmap_count); > + buffer->mmap_count--; > + if (buffer->mmap_count< 0) > + printk(KERN_INFO "atmel_isi: mmap_count went negative\n"); > +} > + > +static struct vm_operations_struct atmel_isi_vm_ops = { > + .open = atmel_isi_vm_open, > + .close = atmel_isi_vm_close, > +}; > + > +static int atmel_isi_mmap(struct file *file, struct vm_area_struct *vma) > +{ > + unsigned long pfn; > + int ret; > + struct atmel_isi_fh *fh = file->private_data; > + struct atmel_isi *isi = fh->isi; > + struct frame_buffer *buffer =&(isi->video_buffer[vma->vm_pgoff]); > + unsigned long size = vma->vm_end - vma->vm_start; > + > + pr_debug("atmel_isi: mmap called pgoff=%ld size=%ld \n", > + vma->vm_pgoff, size); > + > + if (size> video_buffer_size) { > + pr_debug("atmel_isi: mmap requested buffer is to large\n"); > + return -EINVAL; > + } > + if (vma->vm_pgoff> video_buffers) { > + pr_debug("atmel_isi: invalid mmap page offset\n"); > + return -EINVAL; > + } > + pfn = isi->video_buffer[vma->vm_pgoff].fb_desc.fb_address>> PAGE_SHIFT; > + > + ret = remap_pfn_range(vma, vma->vm_start, pfn, > + vma->vm_end - vma->vm_start, vma->vm_page_prot); > + if (ret) > + return ret; > + > + vma->vm_ops =&atmel_isi_vm_ops; > + vma->vm_flags |= VM_DONTEXPAND; /* fixed size */ > + vma->vm_flags |= VM_RESERVED;/* do not swap out */ > + vma->vm_flags |= VM_DONTCOPY; > + vma->vm_flags |= VM_SHARED; > + vma->vm_private_data = (void *) buffer; > + atmel_isi_vm_open(vma); > + > + pr_debug("atmel_isi: vma start=0x%08lx, size=%ld phys=%ld \n", > + (unsigned long) vma->vm_start, > + (unsigned long) vma->vm_end - (unsigned long) vma->vm_start, > + pfn<< PAGE_SHIFT); > + > + return 0; > +} > + > +static int atmel_isi_stream_close(struct file *file) > +{ > + struct atmel_isi_fh *fh = file->private_data; > + struct atmel_isi *isi = fh->isi; > + u32 cr; > + > + mutex_lock(&isi->mutex); > + > + isi->stream_users--; > + kfree(fh); > + > + /* Stop camera and ISI if driver has no users */ > + if (!isi->capture_users) { > + spin_lock_irq(&isi->lock); > + cr = isi_readl(isi, V2_CTRL); > + cr |= ISI_BIT(V2_DIS); > + isi_writel(isi, V2_CTRL, cr); > + spin_unlock_irq(&isi->lock); > + } > + > + mutex_unlock(&isi->mutex); > + > + return 0; > +} > + > +static int atmel_isi_stream_open(struct file *file) > +{ > + struct video_device *vdev = video_devdata(file); > + struct atmel_isi *isi = to_atmel_isi(vdev); > + struct atmel_isi_fh *fh; > + int ret = -EBUSY; > + > + mutex_lock(&isi->mutex); > + /* Just one user is allowed for the streaming device*/ > + if (isi->stream_users) { > + pr_debug("%s: open(): device busy\n", vdev->name); > + goto out; > + } > + > + /* If the capture interface is unused too we do a > + * init of hardware/software configuration > + */ > + if (isi->capture_users == 0) { > + ret = atmel_isi_init(isi); > + if (ret) > + goto out; > + } > + > + ret = -ENOMEM; > + fh = kzalloc(sizeof(struct atmel_isi_fh), GFP_KERNEL); > + if (!fh) { > + pr_debug("%s: open(): out of memory\n", vdev->name); > + goto out; > + } > + > + fh->isi = isi; > + file->private_data = fh; > + isi->stream_users++; > + > + ret = 0; > + > +out: > + mutex_unlock(&isi->mutex); > + return ret; > +} > + > +static void atmel_isi_stream_release(struct video_device *vdev) > +{ > + struct atmel_isi *isi = to_atmel_isi(vdev); > + pr_debug("%s: release\n", vdev->name); > + kfree(isi); > +} > +/* -----------------------------------------------------------------------*/ > +/* Streaming v4l2 device file operations */ > +static struct v4l2_file_operations atmel_isi_streaming_fops = { > + .owner = THIS_MODULE, > + .ioctl = video_ioctl2, > + .open = atmel_isi_stream_open, > + .release = atmel_isi_stream_close, > + .mmap = atmel_isi_mmap, > +}; > +/* Capture v4l2 device file operations */ > +static struct v4l2_file_operations atmel_isi_capture_fops = { > + .owner = THIS_MODULE, > + .open = atmel_isi_capture_open, > + .release = atmel_isi_capture_close, > + .read = atmel_isi_capture_read, > + .ioctl = video_ioctl2, > +}; > + > +static int __exit atmel_isi_remove(struct platform_device *pdev) > +{ > + struct atmel_isi *isi = platform_get_drvdata(pdev); > + int i; > + > + kfree(&isi->sd); > + v4l2_device_unregister(&isi->v4l2_dev); > + video_unregister_device(&isi->cdev); > + video_unregister_device(&isi->vdev); > + > + platform_set_drvdata(pdev, NULL); > + > + /* release capture buffer */ > + dma_free_coherent(&pdev->dev, capture_buffer_size, > + isi->capture_buf, isi->capture_phys); > + > + /* release frame buffers */ > + for (i = 0; i< video_buffers; i++) { > + dma_free_coherent(&pdev->dev, > + video_buffer_size, > + isi->video_buffer[i].frame_buffer, > + isi->video_buffer[i].fb_desc.fb_address); > + } > + > + free_irq(isi->irq, isi); > + iounmap(isi->regs); > + clk_disable(isi->hclk); > + clk_disable(isi->pclk); > + clk_put(isi->hclk); > + clk_put(isi->pclk); > + > + /* > + * Don't free isi here -- it will be taken care of by the > + * release() callback. > + */ > + > + return 0; > +} > + > + > +static const struct v4l2_ioctl_ops atmel_isi_capture_ioctl_ops = { > + .vidioc_querycap = atmel_isi_capture_querycap, > + .vidioc_enum_fmt_vid_cap = atmel_isi_capture_enum_fmt_cap, > + .vidioc_g_fmt_vid_cap = atmel_isi_capture_g_fmt_cap, > + .vidioc_try_fmt_vid_cap = atmel_isi_capture_try_fmt_cap, > + .vidioc_s_fmt_vid_cap = atmel_isi_capture_s_fmt_cap, > + .vidioc_reqbufs = atmel_isi_reqbufs, > + .vidioc_querybuf = atmel_isi_querybuf, > + .vidioc_qbuf = atmel_isi_qbuf, > + .vidioc_dqbuf = atmel_isi_dqbuf, > + .vidioc_enum_input = atmel_isi_capture_enum_input, > + .vidioc_g_input = atmel_isi_capture_g_input, > + .vidioc_s_input = atmel_isi_capture_s_input, > +}; > + > +static struct video_device atmel_isi_capture_template = { > + .fops =&atmel_isi_capture_fops, > + .minor = -1, > + .ioctl_ops =&atmel_isi_capture_ioctl_ops, > + .current_norm = V4L2_STD_PAL, > +}; > +static const struct v4l2_ioctl_ops atmel_isi_streaming_ioctl_ops = { > + .vidioc_querycap = atmel_isi_streaming_querycap, > + .vidioc_enum_fmt_vid_cap = atmel_isi_streaming_enum_fmt_cap, > + .vidioc_g_fmt_vid_cap = atmel_isi_streaming_g_fmt_cap, > + .vidioc_try_fmt_vid_cap = atmel_isi_streaming_try_fmt_cap, > + .vidioc_s_fmt_vid_cap = atmel_isi_streaming_s_fmt_cap, > + .vidioc_reqbufs = atmel_isi_reqbufs, > + .vidioc_querybuf = atmel_isi_querybuf, > + .vidioc_qbuf = atmel_isi_qbuf, > + .vidioc_dqbuf = atmel_isi_dqbuf, > + .vidioc_enum_input = atmel_isi_streaming_enum_input, > + .vidioc_g_input = atmel_isi_streaming_g_input, > + .vidioc_s_input = atmel_isi_streaming_s_input, > + .vidioc_queryctrl = atmel_isi_streaming_queryctrl, > + .vidioc_g_ctrl = atmel_isi_streaming_g_ctrl, > + .vidioc_s_ctrl = atmel_isi_streaming_s_ctrl, > + .vidioc_streamon = atmel_isi_streamon, > + .vidioc_streamoff = atmel_isi_streamoff, > + .vidioc_g_parm = atmel_isi_g_parm, > +}; > + > +static struct video_device atmel_isi_streaming_template = { > + .fops =&atmel_isi_streaming_fops, > + .minor = -1, > + .ioctl_ops =&atmel_isi_streaming_ioctl_ops, > + .current_norm = V4L2_STD_PAL, > +}; > + > + > +static int __init atmel_isi_probe(struct platform_device *pdev) > +{ > + unsigned int irq; > + struct atmel_isi *isi; > + struct clk *pclk; > + struct resource *regs; > + int ret; > + int i; > + int video_bytes_used = video_buffer_size; > + struct device *dev =&pdev->dev; > + struct isi_platform_data *pdata; > + struct i2c_adapter *i2c_adap; > + > + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!regs) > + return -ENXIO; > + > + pclk = clk_get(&pdev->dev, "isi_clk"); > + if (IS_ERR(pclk)) > + return PTR_ERR(pclk); > + > + clk_enable(pclk); > + > + isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL); > + if (!isi) { > + ret = -ENOMEM; > + dev_err(&pdev->dev, "can't allocate interface!\n"); > + goto err_alloc_isi; > + } > + > + isi->pclk = pclk; > + spin_lock_init(&isi->lock); > + mutex_init(&isi->mutex); > + init_waitqueue_head(&isi->capture_wq); > + > + /* Initialize v4l2 capture device */ > + isi->cdev = atmel_isi_capture_template; > + isi->cdev.release = atmel_isi_capture_release; > + strcpy(isi->cdev.name, "atmel_isi_capture"); > +#ifdef DEBUG > + isi->cdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; > +#endif > + > + /* Initialize v4l2 streaming device */ > + isi->vdev = atmel_isi_streaming_template; > + isi->vdev.release = atmel_isi_stream_release; > + strcpy(isi->vdev.name, "atmel_isi_streaming"); > +#ifdef DEBUG > + isi->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; > +#endif > + isi->regs = ioremap(regs->start, regs->end - regs->start + 1); > + if (!isi->regs) { > + ret = -ENOMEM; > + goto err_ioremap; > + } > + > + if (dev->platform_data) { > + pdata = (struct isi_platform_data *) dev->platform_data; > + image_hsize = pdata->image_hsize; > + image_vsize = pdata->image_vsize; > + > + /* load i2c info */ > + isi->board_info = pdata->board_info; > + > + if (pdata->prev_hsize) > + prev_hsize = pdata->prev_hsize; > + if (pdata->prev_vsize) > + prev_vsize = pdata->prev_vsize; > + if (pdata->pixfmt) > + input_format = pdata->pixfmt; > + else > + input_format = ATMEL_ISI_PIXFMT_YCbYCr; > + frame_rate_scaler = pdata->frate; > + if (pdata->capture_v4l2_fmt) > + capture_v4l2_fmt = pdata->capture_v4l2_fmt; > + if (pdata->streaming_v4l2_fmt) > + streaming_v4l2_fmt = pdata->streaming_v4l2_fmt; > + if (pdata->cr1_flags& ISI_HSYNC_ACT_LOW) > + hsync_act_low = 1; > + if (pdata->cr1_flags& ISI_VSYNC_ACT_LOW) > + vsync_act_low = 1; > + if (pdata->cr1_flags& ISI_PXCLK_ACT_FALLING) > + pclk_act_falling = 1; > + if (pdata->cr1_flags& ISI_EMB_SYNC) > + has_emb_sync = 1; > + if (pdata->cr1_flags& ISI_CRC_SYNC) > + emb_crc_sync = 1; > + if (pdata->cr1_flags& ISI_FULL) > + isi_full_mode = 1; > + } else { > + has_emb_sync = 0; > + emb_crc_sync = 0; > + hsync_act_low = 0; > + vsync_act_low = 0; > + pclk_act_falling = 0; > + isi_full_mode = 0; > + prev_hsize = 320; > + prev_vsize = 240; > + image_hsize = 320; > + image_vsize = 240; > + dev_info(&pdev->dev, > + "No config available using default values\n"); > + } > + > + video_buffer_size = prev_hsize * prev_vsize * 2; > + video_bytes_used = video_buffer_size; > + > + /* Round up buffer sizes to the next page if needed */ > + video_buffer_size = PAGE_ALIGN(video_buffer_size); > + capture_buffer_size = PAGE_ALIGN(capture_buffer_size); > + > + isi_writel(isi, V2_CTRL, ISI_BIT(V2_DIS)); > + /* Check if module disable */ > + while (isi_readl(isi, V2_STATUS)& ISI_BIT(V2_DIS)) > + cpu_relax(); > + > + irq = platform_get_irq(pdev, 0); > + ret = request_irq(irq, isi_interrupt, 0, "isi", isi); > + if (ret) { > + dev_err(&pdev->dev, "unable to request irq %d\n", irq); > + goto err_req_irq; > + } > + isi->irq = irq; > + > + /* Allocate ISI capture buffer */ > + isi->capture_buf = dma_alloc_coherent(&pdev->dev, > + capture_buffer_size, > + &isi->capture_phys, > + GFP_KERNEL); > + if (!isi->capture_buf) { > + ret = -ENOMEM; > + dev_err(&pdev->dev, "failed to allocate capture buffer\n"); > + goto err_alloc_cbuf; > + } > + > + /* Allocate and initialize video buffers */ > + for (i = 0 ; i< video_buffers; i++) { > + memset(&isi->video_buffer[i], 0, sizeof(struct frame_buffer)); > + isi->video_buffer[i].frame_buffer = > + dma_alloc_coherent(&pdev->dev, > + video_buffer_size, > + (dma_addr_t *) > + &(isi->video_buffer[i].fb_desc.fb_address), > + GFP_KERNEL); > + if (!isi->video_buffer[i].frame_buffer) { > + ret = -ENOMEM; > + dev_err(&pdev->dev, > + "failed to allocate video buffer\n"); > + goto err_alloc_vbuf; > + } > + > + isi->video_buffer[i].bytes_used = video_bytes_used; > + isi->video_buffer[i].status = FRAME_UNUSED; > + isi->video_buffer[i].index = i; > + } > + > + isi->fbd_list_start = __pa(&isi->video_buffer[0].fb_desc); > + for (i = 0 ; i< (video_buffers - 1); i++) { > + isi->video_buffer[i].fb_desc.next_fbd_address = > + __pa(&isi->video_buffer[i+1].fb_desc); > + } > + isi->video_buffer[i].fb_desc.next_fbd_address = > + __pa(&isi->video_buffer[0].fb_desc); > + > + /* Set head& tail of the TD */ > + isi->head = 0; > + isi->tail = video_buffers - 1; > + > + for (i = 0 ; i< video_buffers; i++) { > + dev_info(&pdev->dev, > + "video buffer: %d bytes at %p (phys %08lx)\n", > + video_buffer_size, > + isi->video_buffer[i].frame_buffer, > + (unsigned long) isi->video_buffer[i].fb_desc.fb_address); > + } > + > + dev_info(&pdev->dev, > + "capture buffer: %d bytes at %p (phys 0x%08x)\n", > + capture_buffer_size, isi->capture_buf, > + isi->capture_phys); > + > + ret = video_register_device(&isi->cdev, VFL_TYPE_GRABBER, video_nr); > + if (ret) { > + dev_err(&pdev->dev, "Registering capturing device failed\n"); > + video_device_release(&isi->cdev); > + kfree(dev); > + goto err_register1; > + } > + > + ret = video_register_device(&isi->vdev, VFL_TYPE_GRABBER, video_nr); > + if (ret) { > + dev_err(&pdev->dev, "Registering streaming device failed\n"); > + video_device_release(&isi->vdev); > + kfree(dev); > + goto err_register2; > + } > + > + ret = v4l2_device_register(dev,&isi->v4l2_dev); > + if (ret) { > + dev_err(&pdev->dev, > + "Unable to register v4l2 device.\n"); > + goto err_register_v4l2_device; > + } > + > + platform_set_drvdata(pdev, isi); > + > + /* Set the subdev info */ > + i2c_adap = i2c_get_adapter(0); > + isi->sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); > + /* Load up the subdevice */ > + isi->sd = > + v4l2_i2c_new_subdev_board(&isi->v4l2_dev, > + i2c_adap, > + "atmel_isi", > + &isi->board_info, > + NULL); > + if (isi->sd) { > + dev_err(&pdev->dev, > + "v4l2 sub device registered\n"); > + } else { > + dev_err(&pdev->dev, > + "v4l2 sub device register fails\n"); > + goto probe_sd_out; > + } > + > + dev_info(&pdev->dev, "Atmel ISI V4L2 device at 0x%08lx\n", > + (unsigned long)regs->start); > + > + return 0; > + > +probe_sd_out: > + kfree(isi->sd); > +err_register_v4l2_device: > + v4l2_device_unregister(&isi->v4l2_dev); > +err_register2: > + video_unregister_device(&isi->vdev); > +err_register1: > + video_unregister_device(&isi->cdev); > +err_alloc_vbuf: > + while (i--) > + dma_free_coherent(&pdev->dev, video_buffer_size, > + isi->video_buffer[i].frame_buffer, > + isi->video_buffer[i].fb_desc.fb_address); > +err_alloc_cbuf: > + dma_free_coherent(&pdev->dev, capture_buffer_size, > + isi->capture_buf, > + isi->capture_phys); > + free_irq(isi->irq, isi); > +err_req_irq: > + iounmap(isi->regs); > +err_ioremap: > + kfree(isi); > +err_alloc_isi: > + clk_disable(pclk); > + > + return ret; > + > +} > + > +static struct platform_driver atmel_isi_driver = { > + .probe = atmel_isi_probe, > + .remove = __exit_p(atmel_isi_remove), > + .driver = { > + .name = "atmel_isi", > + .owner = THIS_MODULE, > + }, > +}; > + > +static int __init atmel_isi_init_module(void) > +{ > + return platform_driver_probe(&atmel_isi_driver,&atmel_isi_probe); > +} > + > + > +static void __exit atmel_isi_exit(void) > +{ > + platform_driver_unregister(&atmel_isi_driver); > +} > + > + > +module_init(atmel_isi_init_module); > +module_exit(atmel_isi_exit); > + > +MODULE_AUTHOR("Lars Häring"); > +MODULE_DESCRIPTION("The V4L2 driver for atmel Linux"); > +MODULE_LICENSE("GPL"); > +MODULE_SUPPORTED_DEVICE("video"); > diff --git a/include/media/atmel-isi.h b/include/media/atmel-isi.h > new file mode 100644 > index 0000000..1776fea > --- /dev/null > +++ b/include/media/atmel-isi.h > @@ -0,0 +1,460 @@ > +/* > + * Register definitions for the Atmel Image Sensor Interface. > + * > + * Copyright (C) 2006 Atmel Corporation > + * > + * 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. > + */ > +#ifndef __ASM_AVR32_ISI_H__ > +#define __ASM_AVR32_ISI_H__ > + > +#include > +#include > + > +#include > +#include > +#include > + > +/* ISI register offsets */ > +#define ISI_CR1 0x0000 > +#define ISI_CR2 0x0004 > +#define ISI_SR 0x0008 > +#define ISI_IER 0x000c > +#define ISI_IDR 0x0010 > +#define ISI_IMR 0x0014 > +#define ISI_PSIZE 0x0020 > +#define ISI_PDECF 0x0024 > +#define ISI_PPFBD 0x0028 > +#define ISI_CDBA 0x002c > +#define ISI_Y2R_SET0 0x0030 > +#define ISI_Y2R_SET1 0x0034 > +#define ISI_R2Y_SET0 0x0038 > +#define ISI_R2Y_SET1 0x003c > +#define ISI_R2Y_SET2 0x0040 > + > +/* ISI_V2 register offsets */ > +#define ISI_V2_CFG1 0x0000 > +#define ISI_V2_CFG2 0x0004 > +#define ISI_V2_PSIZE 0x0008 > +#define ISI_V2_PDECF 0x000c > +#define ISI_V2_Y2R_SET0 0x0010 > +#define ISI_V2_Y2R_SET1 0x0014 > +#define ISI_V2_R2Y_SET0 0x0018 > +#define ISI_V2_R2Y_SET1 0x001C > +#define ISI_V2_R2Y_SET2 0x0020 > +#define ISI_V2_CTRL 0x0024 > +#define ISI_V2_STATUS 0x0028 > +#define ISI_V2_INTEN 0x002C > +#define ISI_V2_INTDIS 0x0030 > +#define ISI_V2_INTMASK 0x0034 > +#define ISI_V2_DMA_CHER 0x0038 > +#define ISI_V2_DMA_CHDR 0x003C > +#define ISI_V2_DMA_CHSR 0x0040 > +#define ISI_V2_DMA_P_ADDR 0x0044 > +#define ISI_V2_DMA_P_CTRL 0x0048 > +#define ISI_V2_DMA_P_DSCR 0x004C > +#define ISI_V2_DMA_C_ADDR 0x0050 > +#define ISI_V2_DMA_C_CTRL 0x0054 > +#define ISI_V2_DMA_C_DSCR 0x0058 > + > +/* Bitfields in CR1 */ > +#define ISI_RST_OFFSET 0 > +#define ISI_RST_SIZE 1 > +#define ISI_DIS_OFFSET 1 > +#define ISI_DIS_SIZE 1 > +#define ISI_HSYNC_POL_OFFSET 2 > +#define ISI_HSYNC_POL_SIZE 1 > +#define ISI_VSYNC_POL_OFFSET 3 > +#define ISI_VSYNC_POL_SIZE 1 > +#define ISI_PIXCLK_POL_OFFSET 4 > +#define ISI_PIXCLK_POL_SIZE 1 > +#define ISI_EMB_SYNC_OFFSET 6 > +#define ISI_EMB_SYNC_SIZE 1 > +#define ISI_CRC_SYNC_OFFSET 7 > +#define ISI_CRC_SYNC_SIZE 1 > +#define ISI_FRATE_OFFSET 8 > +#define ISI_FRATE_SIZE 3 > +#define ISI_FULL_OFFSET 12 > +#define ISI_FULL_SIZE 1 > +#define ISI_THMASK_OFFSET 13 > +#define ISI_THMASK_SIZE 2 > +#define ISI_CODEC_ON_OFFSET 15 > +#define ISI_CODEC_ON_SIZE 1 > +#define ISI_SLD_OFFSET 16 > +#define ISI_SLD_SIZE 8 > +#define ISI_SFD_OFFSET 24 > +#define ISI_SFD_SIZE 8 > + > +/* Bitfields in CFG1 */ > +#define ISI_V2_HSYNC_POL_OFFSET 2 > +#define ISI_V2_HSYNC_POL_SIZE 1 > +#define ISI_V2_VSYNC_POL_OFFSET 3 > +#define ISI_V2_VSYNC_POL_SIZE 1 > +#define ISI_V2_PIXCLK_POL_OFFSET 4 > +#define ISI_V2_PIXCLK_POL_SIZE 1 > +#define ISI_V2_EMB_SYNC_OFFSET 6 > +#define ISI_V2_EMB_SYNC_SIZE 1 > +#define ISI_V2_CRC_SYNC_OFFSET 7 > +#define ISI_V2_CRC_SYNC_SIZE 1 > +#define ISI_V2_FRATE_OFFSET 8 > +#define ISI_V2_FRATE_SIZE 3 > +#define ISI_V2_DISCR_OFFSET 11 > +#define ISI_V2_DISCR_SIZE 1 > +#define ISI_V2_FULL_OFFSET 12 > +#define ISI_V2_FULL_SIZE 1 > +#define ISI_V2_THMASK_OFFSET 13 > +#define ISI_V2_THMASK_SIZE 2 > +#define ISI_V2_SLD_OFFSET 16 > +#define ISI_V2_SLD_SIZE 8 > +#define ISI_V2_SFD_OFFSET 24 > +#define ISI_V2_SFD_SIZE 8 > + > +/* Bitfields in CR2 */ > +#define ISI_IM_VSIZE_OFFSET 0 > +#define ISI_IM_VSIZE_SIZE 11 > +#define ISI_GS_MODE_OFFSET 11 > +#define ISI_GS_MODE_SIZE 1 > +#define ISI_RGB_MODE_OFFSET 12 > +#define ISI_RGB_MODE_SIZE 1 > +#define ISI_GRAYSCALE_OFFSET 13 > +#define ISI_GRAYSCALE_SIZE 1 > +#define ISI_RGB_SWAP_OFFSET 14 > +#define ISI_RGB_SWAP_SIZE 1 > +#define ISI_COL_SPACE_OFFSET 15 > +#define ISI_COL_SPACE_SIZE 1 > +#define ISI_IM_HSIZE_OFFSET 16 > +#define ISI_IM_HSIZE_SIZE 11 > +#define ISI_YCC_SWAP_OFFSET 28 > +#define ISI_YCC_SWAP_SIZE 2 > +#define ISI_RGB_CFG_OFFSET 30 > +#define ISI_RGB_CFG_SIZE 2 > + > +/* Bitfields in CFG2 */ > +#define ISI_V2_IM_VSIZE_OFFSET 0 > +#define ISI_V2_IM_VSIZE_SIZE 11 > +#define ISI_V2_GS_MODE_OFFSET 11 > +#define ISI_V2_GS_MODE_SIZE 1 > +#define ISI_V2_RGB_MODE_OFFSET 12 > +#define ISI_V2_RGB_MODE_SIZE 1 > +#define ISI_V2_GRAYSCALE_OFFSET 13 > +#define ISI_V2_GRAYSCALE_SIZE 1 > +#define ISI_V2_RGB_SWAP_OFFSET 14 > +#define ISI_V2_RGB_SWAP_SIZE 1 > +#define ISI_V2_COL_SPACE_OFFSET 15 > +#define ISI_V2_COL_SPACE_SIZE 1 > +#define ISI_V2_IM_HSIZE_OFFSET 16 > +#define ISI_V2_IM_HSIZE_SIZE 11 > +#define ISI_V2_YCC_SWAP_OFFSET 28 > +#define ISI_V2_YCC_SWAP_SIZE 2 > +#define ISI_V2_RGB_CFG_OFFSET 30 > +#define ISI_V2_RGB_CFG_SIZE 2 > + > +/* Bitfields in CTRL */ > +#define ISI_V2_EN_OFFSET 0 > +#define ISI_V2_EN_SIZE 1 > +#define ISI_V2_DIS_OFFSET 1 > +#define ISI_V2_DIS_SIZE 1 > +#define ISI_V2_SRST_OFFSET 2 > +#define ISI_V2_SRST_SIZE 1 > +#define ISI_V2_CDC_OFFSET 8 > +#define ISI_V2_CDC_SIZE 1 > + > +/* Bitfields in SR/IER/IDR/IMR */ > +#define ISI_SOF_OFFSET 0 > +#define ISI_SOF_SIZE 1 > +#define ISI_SOFTRST_OFFSET 2 > +#define ISI_SOFTRST_SIZE 1 > +#define ISI_CDC_STATUS_OFFSET 3 > +#define ISI_CDC_STATUS_SIZE 1 > +#define ISI_CRC_ERR_OFFSET 4 > +#define ISI_CRC_ERR_SIZE 1 > +#define ISI_FO_C_OVF_OFFSET 5 > +#define ISI_FO_C_OVF_SIZE 1 > +#define ISI_FO_P_OVF_OFFSET 6 > +#define ISI_FO_P_OVF_SIZE 1 > +#define ISI_FO_P_EMP_OFFSET 7 > +#define ISI_FO_P_EMP_SIZE 1 > +#define ISI_FO_C_EMP_OFFSET 8 > +#define ISI_FO_C_EMP_SIZE 1 > +#define ISI_FR_OVR_OFFSET 9 > +#define ISI_FR_OVR_SIZE 1 > + > +/* Bitfields in SR/IER/IDR/IMR(ISI_V2) */ > +#define ISI_V2_ENABLE_OFFSET 0 > +#define ISI_V2_ENABLE_SIZE 1 > +#define ISI_V2_DIS_DONE_OFFSET 1 > +#define ISI_V2_DIS_DONE_SIZE 1 > +#define ISI_V2_SRST_OFFSET 2 > +#define ISI_V2_SRST_SIZE 1 > +#define ISI_V2_CDC_STATUS_OFFSET 8 > +#define ISI_V2_CDC_STATUS_SIZE 1 > +#define ISI_V2_VSYNC_OFFSET 10 > +#define ISI_V2_VSYNC_SIZE 1 > +#define ISI_V2_PXFR_DONE_OFFSET 16 > +#define ISI_V2_PXFR_DONE_SIZE 1 > +#define ISI_V2_CXFR_DONE_OFFSET 17 > +#define ISI_V2_CXFR_DONE_SIZE 1 > +#define ISI_V2_P_OVR_OFFSET 24 > +#define ISI_V2_P_OVR_SIZE 1 > +#define ISI_V2_C_OVR_OFFSET 25 > +#define ISI_V2_C_OVR_SIZE 1 > +#define ISI_V2_CRC_ERR_OFFSET 26 > +#define ISI_V2_CRC_ERR_SIZE 1 > +#define ISI_V2_FR_OVR_OFFSET 27 > +#define ISI_V2_FR_OVR_SIZE 1 > + > +/* Bitfields in PSIZE */ > +#define ISI_PREV_VSIZE_OFFSET 0 > +#define ISI_PREV_VSIZE_SIZE 10 > +#define ISI_PREV_HSIZE_OFFSET 16 > +#define ISI_PREV_HSIZE_SIZE 10 > + > +/* Bitfields in PSIZE(ISI_V2) */ > +#define ISI_V2_PREV_VSIZE_OFFSET 0 > +#define ISI_V2_PREV_VSIZE_SIZE 10 > +#define ISI_V2_PREV_HSIZE_OFFSET 16 > +#define ISI_V2_PREV_HSIZE_SIZE 10 > + > +/* Bitfields in PCDEF */ > +#define ISI_DEC_FACTOR_OFFSET 0 > +#define ISI_DEC_FACTOR_SIZE 8 > + > +/* Bitfields in PCDEF */ > +#define ISI_V2_DEC_FACTOR_OFFSET 0 > +#define ISI_V2_DEC_FACTOR_SIZE 8 > + > +/* Bitfields in PPFBD */ > +#define ISI_PREV_FBD_ADDR_OFFSET 0 > +#define ISI_PREV_FBD_ADDR_SIZE 32 > + > +/* Bitfields in CDBA */ > +#define ISI_CODEC_DMA_ADDR_OFFSET 0 > +#define ISI_CODEC_DMA_ADDR_SIZE 32 > + > +/* Bitfields in DMA_C_ADDR */ > +#define ISI_V2_DMA_ADDR_OFFSET 0 > +#define ISI_V2_DMA_ADDR_SIZE 32 > + > +/* Bitfields in DMA_C_CTRL& in DMA_P_CTRL */ > +#define ISI_V2_DMA_FETCH_OFFSET 0 > +#define ISI_V2_DMA_FETCH_SIZE 1 > +#define ISI_V2_DMA_WB_OFFSET 1 > +#define ISI_V2_DMA_WB_SIZE 1 > +#define ISI_V2_DMA_IEN_OFFSET 2 > +#define ISI_V2_DMA_IEN_SIZE 1 > +#define ISI_V2_DMA_DONE_OFFSET 3 > +#define ISI_V2_DMA_DONE_SIZE 1 > + > +/* Bitfields in DMA_CHER */ > +#define ISI_V2_DMA_P_CH_EN_OFFSET 0 > +#define ISI_V2_DMA_P_CH_EN_SIZE 1 > +#define ISI_V2_DMA_C_CH_EN_OFFSET 1 > +#define ISI_V2_DMA_C_CH_EN_SIZE 1 > + > +/* Bitfields in Y2R_SET0 */ > +#define ISI_Y2R_SET0_C3_OFFSET 24 > +#define ISI_Y2R_SET0_C3_SIZE 8 > + > +/* Bitfields in Y2R_SET0(ISI_V2) */ > +#define ISI_V2_Y2R_SET0_C3_OFFSET 24 > +#define ISI_V2_Y2R_SET0_C3_SIZE 8 > + > +/* Bitfields in Y2R_SET1 */ > +#define ISI_Y2R_SET1_C4_OFFSET 0 > +#define ISI_Y2R_SET1_C4_SIZE 9 > +#define ISI_YOFF_OFFSET 12 > +#define ISI_YOFF_SIZE 1 > +#define ISI_CROFF_OFFSET 13 > +#define ISI_CROFF_SIZE 1 > +#define ISI_CBOFF_OFFSET 14 > +#define ISI_CBOFF_SIZE 1 > + > +/* Bitfields in Y2R_SET1(ISI_V2) */ > +#define ISI_V2_Y2R_SET1_C4_OFFSET 0 > +#define ISI_V2_Y2R_SET1_C4_SIZE 9 > +#define ISI_V2_YOFF_OFFSET 12 > +#define ISI_V2_YOFF_SIZE 1 > +#define ISI_V2_CROFF_OFFSET 13 > +#define ISI_V2_CROFF_SIZE 1 > +#define ISI_V2_CBOFF_OFFSET 14 > +#define ISI_V2_CBOFF_SIZE 1 > + > +/* Bitfields in R2Y_SET0 */ > +#define ISI_C0_OFFSET 0 > +#define ISI_C0_SIZE 8 > +#define ISI_C1_OFFSET 8 > +#define ISI_C1_SIZE 8 > +#define ISI_C2_OFFSET 16 > +#define ISI_C2_SIZE 8 > +#define ISI_ROFF_OFFSET 24 > +#define ISI_ROFF_SIZE 1 > + > +/* Bitfields in R2Y_SET0(ISI_V2) */ > +#define ISI_V2_C0_OFFSET 0 > +#define ISI_V2_C0_SIZE 8 > +#define ISI_V2_C1_OFFSET 8 > +#define ISI_V2_C1_SIZE 8 > +#define ISI_V2_C2_OFFSET 16 > +#define ISI_V2_C2_SIZE 8 > +#define ISI_V2_ROFF_OFFSET 24 > +#define ISI_V2_ROFF_SIZE 1 > + > +/* Bitfields in R2Y_SET1 */ > +#define ISI_R2Y_SET1_C3_OFFSET 0 > +#define ISI_R2Y_SET1_C3_SIZE 8 > +#define ISI_R2Y_SET1_C4_OFFSET 8 > +#define ISI_R2Y_SET1_C4_SIZE 8 > +#define ISI_C5_OFFSET 16 > +#define ISI_C5_SIZE 8 > +#define ISI_GOFF_OFFSET 24 > +#define ISI_GOFF_SIZE 1 > + > +/* Bitfields in R2Y_SET1(ISI_V2) */ > +#define ISI_V2_R2Y_SET1_C3_OFFSET 0 > +#define ISI_V2_R2Y_SET1_C3_SIZE 8 > +#define ISI_V2_R2Y_SET1_C4_OFFSET 8 > +#define ISI_V2_R2Y_SET1_C4_SIZE 8 > +#define ISI_V2_C5_OFFSET 16 > +#define ISI_V2_C5_SIZE 8 > +#define ISI_V2_GOFF_OFFSET 24 > +#define ISI_V2_GOFF_SIZE 1 > + > +/* Bitfields in R2Y_SET2 */ > +#define ISI_C6_OFFSET 0 > +#define ISI_C6_SIZE 8 > +#define ISI_C7_OFFSET 8 > +#define ISI_C7_SIZE 8 > +#define ISI_C8_OFFSET 16 > +#define ISI_C8_SIZE 8 > +#define ISI_BOFF_OFFSET 24 > +#define ISI_BOFF_SIZE 1 > + > +/* Bitfields in R2Y_SET2(ISI_V2) */ > +#define ISI_V2_C6_OFFSET 0 > +#define ISI_V2_C6_SIZE 8 > +#define ISI_V2_C7_OFFSET 8 > +#define ISI_V2_C7_SIZE 8 > +#define ISI_V2_C8_OFFSET 16 > +#define ISI_V2_C8_SIZE 8 > +#define ISI_V2_BOFF_OFFSET 24 > +#define ISI_V2_BOFF_SIZE 1 > + > +/* Constants for FRATE */ > +#define ISI_FRATE_CAPTURE_ALL 0 > + > +/* Constants for FRATE(ISI_V2) */ > +#define ISI_V2_FRATE_CAPTURE_ALL 0 > + > +/* Constants for YCC_SWAP */ > +#define ISI_YCC_SWAP_DEFAULT 0 > +#define ISI_YCC_SWAP_MODE_1 1 > +#define ISI_YCC_SWAP_MODE_2 2 > +#define ISI_YCC_SWAP_MODE_3 3 > + > +/* Constants for YCC_SWAP(ISI_V2) */ > +#define ISI_V2_YCC_SWAP_DEFAULT 0 > +#define ISI_V2_YCC_SWAP_MODE_1 1 > +#define ISI_V2_YCC_SWAP_MODE_2 2 > +#define ISI_V2_YCC_SWAP_MODE_3 3 > + > +/* Constants for RGB_CFG */ > +#define ISI_RGB_CFG_DEFAULT 0 > +#define ISI_RGB_CFG_MODE_1 1 > +#define ISI_RGB_CFG_MODE_2 2 > +#define ISI_RGB_CFG_MODE_3 3 > + > +/* Constants for RGB_CFG(ISI_V2) */ > +#define ISI_V2_RGB_CFG_DEFAULT 0 > +#define ISI_V2_RGB_CFG_MODE_1 1 > +#define ISI_V2_RGB_CFG_MODE_2 2 > +#define ISI_V2_RGB_CFG_MODE_3 3 > + > +/* Bit manipulation macros */ > +#define ISI_BIT(name) \ > + (1<< ISI_##name##_OFFSET) > +#define ISI_BF(name, value) \ > + (((value)& ((1<< ISI_##name##_SIZE) - 1)) \ > + << ISI_##name##_OFFSET) > +#define ISI_BFEXT(name, value) \ > + (((value)>> ISI_##name##_OFFSET) \ > + & ((1<< ISI_##name##_SIZE) - 1)) > +#define ISI_BFINS(name, value, old) \ > + (((old)& ~(((1<< ISI_##name##_SIZE) - 1) \ > + << ISI_##name##_OFFSET))\ > + | ISI_BF(name, value)) > + > +/* Register access macros */ > +#define isi_readl(port, reg) \ > + __raw_readl((port)->regs + ISI_##reg) > +#define isi_writel(port, reg, value) \ > + __raw_writel((value), (port)->regs + ISI_##reg) > + > +#define ATMEL_V4L2_VID_FLAGS (V4L2_CAP_VIDEO_OUTPUT) > + > +struct atmel_isi; > + > +enum atmel_isi_pixfmt { > + ATMEL_ISI_PIXFMT_GREY, /* Greyscale */ > + ATMEL_ISI_PIXFMT_CbYCrY, > + ATMEL_ISI_PIXFMT_CrYCbY, > + ATMEL_ISI_PIXFMT_YCbYCr, > + ATMEL_ISI_PIXFMT_YCrYCb, > + ATMEL_ISI_PIXFMT_RGB24, > + ATMEL_ISI_PIXFMT_BGR24, > + ATMEL_ISI_PIXFMT_RGB16, > + ATMEL_ISI_PIXFMT_BGR16, > + ATMEL_ISI_PIXFMT_GRB16, /* G[2:0] R[4:0]/B[4:0] G[5:3] */ > + ATMEL_ISI_PIXFMT_GBR16, /* G[2:0] B[4:0]/R[4:0] G[5:3] */ > + ATMEL_ISI_PIXFMT_RGB24_REV, > + ATMEL_ISI_PIXFMT_BGR24_REV, > + ATMEL_ISI_PIXFMT_RGB16_REV, > + ATMEL_ISI_PIXFMT_BGR16_REV, > + ATMEL_ISI_PIXFMT_GRB16_REV, /* G[2:0] R[4:0]/B[4:0] G[5:3] */ > + ATMEL_ISI_PIXFMT_GBR16_REV, /* G[2:0] B[4:0]/R[4:0] G[5:3] */ > +}; > + > +struct atmel_isi_format { > + struct v4l2_pix_format pix; > + enum atmel_isi_pixfmt input_format; > +}; > + > +struct isi_platform_data { > + u16 image_hsize; > + u16 image_vsize; > + u16 prev_hsize; > + u16 prev_vsize; > + u16 cr1_flags; > +#define ISI_HSYNC_ACT_LOW 0x01 > +#define ISI_VSYNC_ACT_LOW 0x02 > +#define ISI_PXCLK_ACT_FALLING 0x04 > +#define ISI_EMB_SYNC 0x08 > +#define ISI_CRC_SYNC 0x10 > +#define ISI_FULL 0x20 > + u8 gs_mode; > +#define ISI_GS_2PIX_PER_WORD 0x00 > +#define ISI_GS_1PIX_PER_WORD 0x01 > + u8 pixfmt; > + u8 sfd; > + u8 sld; > + u8 thmask; > +#define ISI_BURST_4_8_16 0x00 > +#define ISI_BURST_8_16 0x01 > +#define ISI_BURST_16 0x02 > + u8 frate; > +#define ISI_FRATE_DIV_2 0x01 > +#define ISI_FRATE_DIV_3 0x02 > +#define ISI_FRATE_DIV_4 0x03 > +#define ISI_FRATE_DIV_5 0x04 > +#define ISI_FRATE_DIV_6 0x05 > +#define ISI_FRATE_DIV_7 0x06 > +#define ISI_FRATE_DIV_8 0x07 > + int capture_v4l2_fmt; > + int streaming_v4l2_fmt; > + /* i2c needed for subdev struct */ > + struct i2c_board_info board_info; > +}; > + > +#endif /* __ASM_AVR32_ISI_H__ */ > +