diff options
Diffstat (limited to 'arch/arm/mach-s3c2440/camera')
21 files changed, 5664 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c2440/camera/Kconfig b/arch/arm/mach-s3c2440/camera/Kconfig new file mode 100644 index 00000000000..36f127df82f --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/Kconfig @@ -0,0 +1,7 @@ + +config S3C2440_CAMERA + bool "S3C24xx Camera interface" + depends on ARCH_S3C2410 + help + Camera driver for S3C2440 camera unit + diff --git a/arch/arm/mach-s3c2440/camera/Makefile b/arch/arm/mach-s3c2440/camera/Makefile new file mode 100644 index 00000000000..a46d3bedd84 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_S3C2440_CAMERA) += \ + videodev.o \ + imgsensor.o \ + videodrv.o \ + video-driver.o \ + camif.o \ + camif_fsm.o \ + qt-driver.o + diff --git a/arch/arm/mach-s3c2440/camera/bits.h b/arch/arm/mach-s3c2440/camera/bits.h new file mode 100644 index 00000000000..8d83c2e95b4 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/bits.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) Samsung Electroincs 2003 + * Author: SW.LEE <hitchcar@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __SW_BITS_H +#define __SW_BITS_H + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#endif diff --git a/arch/arm/mach-s3c2440/camera/cam_reg.h b/arch/arm/mach-s3c2440/camera/cam_reg.h new file mode 100644 index 00000000000..7247a4ea29f --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/cam_reg.h @@ -0,0 +1,220 @@ + /*---------------------------------------------------------- + * (C) 2004 Samsung Electronics + * SW.LEE < hitchcar@samsung.com> + * + ----------------------------------------------------------- */ + +#ifndef __FIMC20_CAMERA_H__ +#define __FIMC20_CAMERA_H__ + + +#ifdef CONFIG_ARCH_S3C24A0 +#define CAM_BASE_ADD 0x48000000 +#else /* S3C2440A */ +#define CAM_BASE_ADD 0x4F000000 +#endif + + +/* + * CAMERA IP + * P-port is used as RGB Capturing device which including scale and crop + * those who want to see(preview ) the image on display needs RGB image. + * + * C-port is used as YCbCr(4:2:0, 4:2:2) Capturing device which including the scale and crop + * the prefix of C-port have the meaning of "Codec" ex. mpeg4, h263.. which requries the + YCBCB format not RGB + */ + +#define CISRCFMT __REG(CAM_BASE_ADD+0x00) // RW Input Source Format +#define CIWDOFST __REG(CAM_BASE_ADD+0x04) // Window offset register +#define CIGCTRL __REG(CAM_BASE_ADD+0x08) // Global control register +#define CICOYSA0 __REG(CAM_BASE_ADD+0x18) // Y 1 st frame start address +#define CICOYSA1 __REG(CAM_BASE_ADD+0x1C) // Y 2 nd frame start address +#define CICOYSA2 __REG(CAM_BASE_ADD+0x20) // Y 3 rd frame start address +#define CICOYSA3 __REG(CAM_BASE_ADD+0x24) // Y 4 th frame start address +#define CICOCBSA0 __REG(CAM_BASE_ADD+0x28) // Cb 1 st frame start address +#define CICOCBSA1 __REG(CAM_BASE_ADD+0x2C) // Cb 2 nd frame start address +#define CICOCBSA2 __REG(CAM_BASE_ADD+0x30) // Cb 3 rd frame start address +#define CICOCBSA3 __REG(CAM_BASE_ADD+0x34) // Cb 4 th frame start address +#define CICOCRSA0 __REG(CAM_BASE_ADD+0x38) // Cr 1 st frame start address +#define CICOCRSA1 __REG(CAM_BASE_ADD+0x3C) // Cr 2 nd frame start address +#define CICOCRSA2 __REG(CAM_BASE_ADD+0x40) // Cr 3 rd frame start address +#define CICOCRSA3 __REG(CAM_BASE_ADD+0x44) // Cr 4 th frame start address +#define CICOTRGFMT __REG(CAM_BASE_ADD+0x48) // Target image format of codec +#define CICOCTRL __REG(CAM_BASE_ADD+0x4C) // Codec DMA control related +#define CICOSCPRERATIO __REG(CAM_BASE_ADD+0x50) // Codec pre-scaler ratio control +#define CICOSCPREDST __REG(CAM_BASE_ADD+0x54) // Codec pre-scaler destination +#define CICOSCCTRL __REG(CAM_BASE_ADD+0x58) // Codec main-scaler control +#define CICOTAREA __REG(CAM_BASE_ADD+0x5C) // Codec pre-scaler destination +#define CICOSTATUS __REG(CAM_BASE_ADD+0x64) // Codec path status +#define CIPRCLRSA0 __REG(CAM_BASE_ADD+0x6C) // RGB 1 st frame start address +#define CIPRCLRSA1 __REG(CAM_BASE_ADD+0x70) // RGB 2 nd frame start address +#define CIPRCLRSA2 __REG(CAM_BASE_ADD+0x74) // RGB 3 rd frame start address +#define CIPRCLRSA3 __REG(CAM_BASE_ADD+0x78) // RGB 4 th frame start address +#define CIPRTRGFMT __REG(CAM_BASE_ADD+0x7C) // Target image format of preview +#define CIPRCTRL __REG(CAM_BASE_ADD+0x80) // Preview DMA control related +#define CIPRSCPRERATIO __REG(CAM_BASE_ADD+0x84) // Preview pre-scaler ratio control +#define CIPRSCPREDST __REG(CAM_BASE_ADD+0x88) // Preview pre-scaler destination +#define CIPRSCCTRL __REG(CAM_BASE_ADD+0x8C) // Preview main-scaler control +#define CIPRTAREA __REG(CAM_BASE_ADD+0x90) // Preview pre-scaler destination +#define CIPRSTATUS __REG(CAM_BASE_ADD+0x98) // Preview path status +#define CIIMGCPT __REG(CAM_BASE_ADD+0xA0) // Image capture enable command + +#define CICOYSA(__x) __REG(CAM_BASE_ADD+0x18 + (__x)*4 ) +#define CICOCBSA(__x) __REG(CAM_BASE_ADD+0x28 + (__x)*4 ) +#define CICOCRSA(__x) __REG(CAM_BASE_ADD+0x38 + (__x)*4 ) +#define CIPRCLRSA(__x) __REG(CAM_BASE_ADD+0x6C + (__x)*4 ) + +/* CISRCFMT BitField */ +#define SRCFMT_ITU601 BIT31 +#define SRCFMT_ITU656 0 +#define SRCFMT_UVOFFSET_128 BIT30 +#define fCAM_SIZE_H Fld(13, 16) +#define fCAM_SIZE_V Fld(13, 0) +#define SOURCE_HSIZE(x) FInsrt((x), fCAM_SIZE_H) +#define SOURCE_VSIZE(x) FInsrt((x), fCAM_SIZE_V) + + +/* Window Option Register */ +#define WINOFEN BIT31 +#define CO_FIFO_Y BIT30 +#define CO_FIFO_CB BIT15 +#define CO_FIFO_CR BIT14 +#define PR_FIFO_CB BIT13 +#define PR_FIFO_CR BIT12 +#define fWINHOR Fld(11, 16) +#define fWINVER Fld(11, 0) +#define WINHOROFST(x) FInsrt((x), fWINHOR) +#define WINVEROFST(x) FInsrt((x), fWINVER) + +/* Global Control Register */ +#define GC_SWRST BIT31 +#define GC_CAMRST BIT30 +#define GC_INVPOLPCLK BIT26 +#define GC_INVPOLVSYNC BIT25 +#define GC_INVPOLHREF BIT24 + +/*-------------------------------------------------- + REGISTER BIT FIELD DEFINITION TO + YCBCR and RGB +----------------------------------------------------*/ +/* Codec Target Format Register */ +#define IN_YCBCR420 0 +#define IN_YCBCR422 BIT31 +#define OUT_YCBCR420 0 +#define OUT_YCBCR422 BIT30 + +#if 0 +#define FLIP_NORMAL 0 +#define FLIP_X (BIT14) +#define FLIP_Y (BIT15) +#define FLIP_MIRROR (BIT14|BIT15) +#endif + +/** BEGIN ************************************/ +/* Cotents: Common in both P and C port */ +#define fTARGET_HSIZE Fld(13,16) +#define TARGET_HSIZE(x) FInsrt((x), fTARGET_HSIZE) +#define fTARGET_VSIZE Fld(13,0) +#define TARGET_VSIZE(x) FInsrt((x), fTARGET_VSIZE) +#define FLIP_X_MIRROR BIT14 +#define FLIP_Y_MIRROR BIT15 +#define FLIP_180_MIRROR (BIT14 | BIT15) +/** END *************************************/ + +/* Codec DMA Control Register */ +#define fYBURST_M Fld(5,19) +#define fYBURST_R Fld(5,14) +#define fCBURST_M Fld(5,9) +#define fCBURST_R Fld(5,4) +#define YBURST_M(x) FInsrt((x), fYBURST_M) +#define CBURST_M(x) FInsrt((x), fCBURST_M) +#define YBURST_R(x) FInsrt((x), fYBURST_R) +#define CBURST_R(x) FInsrt((x), fCBURST_R) +#define LAST_IRQ_EN BIT2 /* Common in both P and C port */ +/* + * Check the done signal of capturing image for JPEG + * !!! AutoClear Bit + */ + + +/* (Codec, Preview ) Pre-Scaler Control Register 1 */ +#define fSHIFT Fld(4,28) +#define PRE_SHIFT(x) FInsrt((x), fSHIFT) +#define fRATIO_H Fld(7,16) +#define PRE_HRATIO(x) FInsrt((x), fRATIO_H) +#define fRATIO_V Fld(7,0) +#define PRE_VRATIO(x) FInsrt((x), fRATIO_V) + +/* (Codec, Preview ) Pre-Scaler Control Register 2*/ +#define fDST_WIDTH Fld(12,16) +#define fDST_HEIGHT Fld(12,0) +#define PRE_DST_WIDTH(x) FInsrt((x), fDST_WIDTH) +#define PRE_DST_HEIGHT(x) FInsrt((x), fDST_HEIGHT) + + +/* (Codec, Preview) Main-scaler control Register */ +#define S_METHOD BIT31 /* Sampling method only for P-port */ +#define SCALERSTART BIT15 +/* Codec scaler bypass for upper 2048x2048 + where ImgCptEn_CoSC and ImgCptEn_PrSC should be 0 +*/ + +#define SCALERBYPASS BIT31 +#define RGB_FMT24 BIT30 +#define RGB_FMT16 0 + +/* +#define SCALE_UP_H BIT29 +#define SCALE_UP_V BIT28 +*/ + +#define fMAIN_HRATIO Fld(9, 16) +#define MAIN_HRATIO(x) FInsrt((x), fMAIN_HRATIO) + +#define SCALER_START BIT15 + +#define fMAIN_VRATIO Fld(9, 0) +#define MAIN_VRATIO(x) FInsrt((x), fMAIN_VRATIO) + +/* (Codec, Preview ) DMA Target AREA Register */ +#define fCICOTAREA Fld(26,0) +#define TARGET_DMA_AREA(x) FInsrt((x), fCICOTAREA) + +/* Preview DMA Control Register */ +#define fRGBURST_M Fld(5,19) +#define fRGBURST_R Fld(5,14) +#define RGBURST_M(x) FInsrt((x), fRGBURST_M) +#define RGBURST_R(x) FInsrt((x), fRGBURST_R) + + +/* (Codec, Preview) Status Register */ +#define CO_OVERFLOW_Y BIT31 +#define CO_OVERFLOW_CB BIT30 +#define CO_OVERFLOW_CR BIT29 +#define PR_OVERFLOW_CB BIT31 +#define PR_OVERFLOW_CR BIT30 + +#define VSYNC BIT28 + +#define fFRAME_CNT Fld(2,26) +#define FRAME_CNT(x) FExtr((x),fFRAME_CNT) + +#define WIN_OFF_EN BIT25 +#define fFLIP_MODE Fld(2,23) +#define FLIP_MODE(x) EExtr((x), fFLIP_MODE) +#define CAP_STATUS_CAMIF BIT22 +#define CAP_STATUS_CODEC BIT21 +#define CAP_STATUS_PREVIEW BIT21 +#define VSYNC_A BIT20 +#define VSYNC_B BIT19 + +/* Image Capture Enable Regiser */ +#define CAMIF_CAP_ON BIT31 +#define CAMIF_CAP_CODEC_ON BIT30 +#define CAMIF_CAP_PREVIEW_ON BIT29 + + + + +#endif /* S3C2440_CAMER_H */ diff --git a/arch/arm/mach-s3c2440/camera/camif.c b/arch/arm/mach-s3c2440/camera/camif.c new file mode 100644 index 00000000000..36d4cccdfbf --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/camif.c @@ -0,0 +1,978 @@ +/* + * Copyright (C) 2004 Samsung Electronics + * SW.LEE <hitchcar@samsung.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License 2. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/irq.h> +#include <linux/tqueue.h> +#include <linux/locks.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/miscdevice.h> +#include <linux/wait.h> +#include <linux/miscdevice.h> +#include <asm/io.h> +#include <asm/semaphore.h> +#include <asm/hardware.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_ARCH_S3C24A0A +#include <asm/arch/S3C24A0.h> +#include <asm/arch/clocks.h> +#else +#include <asm/arch/S3C2440.h> +#include <asm/arch/clocks.h> +#endif + +#include "cam_reg.h" +//#define SW_DEBUG +#include "camif.h" +#include "videodev.h" +#include "miscdevice.h" + + +static int camif_dma_burst(camif_cfg_t *); +static int camif_scaler(camif_cfg_t *); + +static const char *camif_version = + "$Id: camif.c,v 1.10 2004/06/04 04:24:14 swlee Exp $"; + +/* For SXGA Image */ +#define RESERVE_MEM 15*1024*1024 +#define YUV_MEM 10*1024*1024 +#define RGB_MEM (RESERVE_MEM - YUV_MEM) + +static int camif_malloc(camif_cfg_t *cfg) +{ + unsigned int t_size; + unsigned int daon = cfg->target_x *cfg->target_y; + + if(cfg->dma_type & CAMIF_CODEC) { + if (cfg->fmt & CAMIF_OUT_YCBCR420) { + t_size = daon * 3 / 2 ; + } + else { t_size = daon * 2; /* CAMIF_OUT_YCBCR422 */ } + t_size = t_size *cfg->pp_num; + +#ifndef SAMSUNG_SXGA_CAM + cfg->pp_virt_buf = consistent_alloc(GFP_KERNEL, t_size, &cfg->pp_phys_buf); +#else + printk(KERN_INFO "Reserving High RAM Addresses \n"); + cfg->pp_phys_buf = PHYS_OFFSET + (MEM_SIZE - RESERVE_MEM); + cfg->pp_virt_buf = ioremap_nocache(cfg->pp_phys_buf,YUV_MEM); +#endif + + if ( !cfg->pp_virt_buf ) { + printk(KERN_ERR"CAMERA:Failed to request YCBCR MEM\n"); + return -ENOMEM; + } + memset(cfg->pp_virt_buf, 0, t_size); + cfg->pp_totalsize = t_size; + return 0; + } + if ( cfg->dma_type & CAMIF_PREVIEW ) { + if (cfg->fmt & CAMIF_RGB16) + t_size = daon * 2; /* 4byte per two pixel*/ + else { + assert(cfg->fmt & CAMIF_RGB24); + t_size = daon * 4; /* 4byte per one pixel */ + } + t_size = t_size * cfg->pp_num; +#ifndef SAMSUNG_SXGA_CAM + cfg->pp_virt_buf = consistent_alloc(GFP_KERNEL, t_size, &cfg->pp_phys_buf); +#else + printk(KERN_INFO "Reserving High RAM Addresses \n"); + cfg->pp_phys_buf = PHYS_OFFSET + (MEM_SIZE - RESERVE_MEM ) + YUV_MEM; + cfg->pp_virt_buf = ioremap_nocache(cfg->pp_phys_buf,RGB_MEM); +#endif + if ( !cfg->pp_virt_buf ) { + printk(KERN_ERR"CAMERA:Failed to request RGB MEM\n"); + return -ENOMEM; + } + memset(cfg->pp_virt_buf, 0, t_size); + cfg->pp_totalsize = t_size; + return 0; + } + + return 0; /* Never come. */ +} + +static int camif_demalloc(camif_cfg_t *cfg) +{ +#ifndef SAMSUNG_SXGA_CAM + if ( cfg->pp_virt_buf ) { + consistent_free(cfg->pp_virt_buf,cfg->pp_totalsize,cfg->pp_phys_buf); + cfg->pp_virt_buf = 0; + } +#else + iounmap(cfg->pp_virt_buf); + cfg->pp_virt_buf = 0; +#endif + return 0; +} + +/* + * advise a person to use this func in ISR + * index value indicates the next frame count to be used + */ +int camif_g_frame_num(camif_cfg_t *cfg) +{ + int index = 0; + + if (cfg->dma_type & CAMIF_CODEC ) { + index = FRAME_CNT(CICOSTATUS); + DPRINTK("CAMIF_CODEC frame %d \n", index); + } + else { + assert(cfg->dma_type & CAMIF_PREVIEW ); + index = FRAME_CNT(CIPRSTATUS); + DPRINTK("CAMIF_PREVIEW frame %d 0x%08X \n", index, CIPRSTATUS); + } + cfg->now_frame_num = (index + 2) % 4; /* When 4 PingPong */ + return index; /* meaningless */ +} + +static int camif_pp_codec(camif_cfg_t *cfg) +{ + u32 i, c_size; /* Cb,Cr size */ + u32 one_p_size; + u32 daon = cfg->target_x * cfg->target_y; + if (cfg->fmt & CAMIF_OUT_YCBCR420) { + c_size = daon /4; + } + else { + assert(cfg->fmt & CAMIF_OUT_YCBCR422); + c_size = daon /2; + } + switch ( cfg->pp_num ) { + case 1 : + for ( i =0 ; i < 4; i=i+1) { + cfg->img_buf[i].virt_y = cfg->pp_virt_buf; + cfg->img_buf[i].phys_y = cfg->pp_phys_buf; + cfg->img_buf[i].virt_cb = cfg->pp_virt_buf + daon; + cfg->img_buf[i].phys_cb = cfg->pp_phys_buf + daon; + cfg->img_buf[i].virt_cr = cfg->pp_virt_buf + daon + c_size; + cfg->img_buf[i].phys_cr = cfg->pp_phys_buf + daon + c_size; + CICOYSA(i) = cfg->img_buf[i].phys_y; + CICOCBSA(i) = cfg->img_buf[i].phys_cb; + CICOCRSA(i) = cfg->img_buf[i].phys_cr; + } + break; + case 2: +#define TRY (( i%2 ) ? 1 :0) + one_p_size = daon + 2*c_size; + for (i = 0; i < 4 ; i++) { + cfg->img_buf[i].virt_y = cfg->pp_virt_buf + TRY * one_p_size; + cfg->img_buf[i].phys_y = cfg->pp_phys_buf + TRY * one_p_size; + cfg->img_buf[i].virt_cb = cfg->pp_virt_buf + daon + TRY * one_p_size; + cfg->img_buf[i].phys_cb = cfg->pp_phys_buf + daon + TRY * one_p_size; + cfg->img_buf[i].virt_cr = cfg->pp_virt_buf + daon + c_size + TRY * one_p_size; + cfg->img_buf[i].phys_cr = cfg->pp_phys_buf + daon + c_size + TRY * one_p_size; + CICOYSA(i) = cfg->img_buf[i].phys_y; + CICOCBSA(i) = cfg->img_buf[i].phys_cb; + CICOCRSA(i) = cfg->img_buf[i].phys_cr; + } + break; + case 4: + one_p_size = daon + 2*c_size; + for (i = 0; i < 4 ; i++) { + cfg->img_buf[i].virt_y = cfg->pp_virt_buf + i * one_p_size; + cfg->img_buf[i].phys_y = cfg->pp_phys_buf + i * one_p_size; + cfg->img_buf[i].virt_cb = cfg->pp_virt_buf + daon + i * one_p_size; + cfg->img_buf[i].phys_cb = cfg->pp_phys_buf + daon + i * one_p_size; + cfg->img_buf[i].virt_cr = cfg->pp_virt_buf + daon + c_size + i * one_p_size; + cfg->img_buf[i].phys_cr = cfg->pp_phys_buf + daon + c_size + i * one_p_size; + CICOYSA(i) = cfg->img_buf[i].phys_y; + CICOCBSA(i) = cfg->img_buf[i].phys_cb; + CICOCRSA(i) = cfg->img_buf[i].phys_cr; + } + break; + default: + printk("Invalid PingPong Number %d \n",cfg->pp_num); + panic("halt\n"); + } + return 0; +} + +/* RGB Buffer Allocation */ +static int camif_pp_preview(camif_cfg_t *cfg) +{ + int i; + u32 daon = cfg->target_x * cfg->target_y; + + if(cfg->fmt & CAMIF_RGB24) + daon = daon * 4 ; + else { + assert (cfg->fmt & CAMIF_RGB16); + daon = daon *2; + } + switch ( cfg->pp_num ) { + case 1: + for ( i = 0; i < 4 ; i++ ) { + cfg->img_buf[i].virt_rgb = cfg->pp_virt_buf ; + cfg->img_buf[i].phys_rgb = cfg->pp_phys_buf ; + CIPRCLRSA(i) = cfg->img_buf[i].phys_rgb; + } + break; + case 2: + for ( i = 0; i < 4 ; i++) { + cfg->img_buf[i].virt_rgb = cfg->pp_virt_buf + TRY * daon; + cfg->img_buf[i].phys_rgb = cfg->pp_phys_buf + TRY * daon; + CIPRCLRSA(i) = cfg->img_buf[i].phys_rgb; + } + break; + case 4: + for ( i = 0; i < 4 ; i++) { + cfg->img_buf[i].virt_rgb = cfg->pp_virt_buf + i * daon; + cfg->img_buf[i].phys_rgb = cfg->pp_phys_buf + i * daon; + CIPRCLRSA(i) = cfg->img_buf[i].phys_rgb; + } + break; + default: + printk("Invalid PingPong Number %d \n",cfg->pp_num); + panic("halt\n"); + } + return 0; +} + +static int camif_pingpong(camif_cfg_t *cfg) +{ + if (cfg->dma_type & CAMIF_CODEC ) { + camif_pp_codec(cfg); + } + + if ( cfg->dma_type & CAMIF_PREVIEW) { + camif_pp_preview(cfg); + } + return 0; +} + + +/*********** Image Convert *******************************/ +/* Return Format + * Supported by Hardware + * V4L2_PIX_FMT_YUV420, + * V4L2_PIX_FMT_YUV422P, + * V4L2_PIX_FMT_BGR32 (BGR4) + * ----------------------------------- + * V4L2_PIX_FMT_RGB565(X) + * Currenly 2byte --> BGR656 Format + * S3C2440A,S3C24A0 supports vairants with reversed FMT_RGB565 + i.e blue toward the least, red towards the most significant bit + -- by SW.LEE + */ + + +/* + * After calling camif_g_frame_num, + * this func must be called + */ +u8 * camif_g_frame(camif_cfg_t *cfg) +{ + u8 * ret = NULL; + int cnt = cfg->now_frame_num; + + if(cfg->dma_type & CAMIF_PREVIEW) { + ret = cfg->img_buf[cnt].virt_rgb; + } + if (cfg->dma_type & CAMIF_CODEC) { + ret = cfg->img_buf[cnt].virt_y; + } + return ret; +} + +/* This function must be called in module initial time */ +static int camif_source_fmt(camif_gc_t *gc) +{ + u32 cmd = 0; + + /* Configure CISRCFMT --Source Format */ + if (gc->itu_fmt & CAMIF_ITU601) { + cmd = CAMIF_ITU601; + } + else { + assert ( gc->itu_fmt & CAMIF_ITU656); + cmd = CAMIF_ITU656; + } + cmd |= SOURCE_HSIZE(gc->source_x)| SOURCE_VSIZE(gc->source_y); + /* Order422 */ + cmd |= gc->order422; + CISRCFMT = cmd; + + return 0 ; +} + + +/* + * Codec Input YCBCR422 will be Fixed + */ +static int camif_target_fmt(camif_cfg_t *cfg) +{ + u32 cmd = 0; + + if (cfg->dma_type & CAMIF_CODEC) { + /* YCBCR setting */ + cmd = TARGET_HSIZE(cfg->target_x)| TARGET_VSIZE(cfg->target_y); + if ( cfg->fmt & CAMIF_OUT_YCBCR420 ) { + cmd |= OUT_YCBCR420|IN_YCBCR422; + } + else { + assert(cfg->fmt & CAMIF_OUT_YCBCR422); + cmd |= OUT_YCBCR422|IN_YCBCR422; + } + CICOTRGFMT = cmd | cfg->flip; + } + else { + assert(cfg->dma_type & CAMIF_PREVIEW); + CIPRTRGFMT = + TARGET_HSIZE(cfg->target_x)|TARGET_VSIZE(cfg->target_y)|cfg->flip; + } + return 0; +} + +void camif_change_flip(camif_cfg_t *cfg) +{ + u32 cmd = 0; + + if (cfg->dma_type & CAMIF_CODEC ) { + /* YCBCR setting */ + cmd = CICOTRGFMT; + cmd &= ~(BIT14|BIT15); /* Clear FLIP Mode */ + cmd |= cfg->flip; + CICOTRGFMT = cmd; + } + else { + cmd = CIPRTRGFMT; + cmd &= ~(BIT14|BIT15); + cmd |= cfg->flip; + CICOTRGFMT = cmd; + } +} + + + +/* Must: + * Before calling this function, + * you must use "camif_dynamic_open" + * If you want to enable both CODEC and preview + * you must do it at the same time. + */ +int camif_capture_start(camif_cfg_t *cfg) +{ + u32 n_cmd = 0; /* Next Command */ + + switch(cfg->exec) { + case CAMIF_BOTH_DMA_ON: + camif_reset(CAMIF_RESET,0); /* Flush Camera Core Buffer */ + CIPRSCCTRL |= SCALERSTART; + CICOSCCTRL |= SCALERSTART; + n_cmd = CAMIF_CAP_PREVIEW_ON|CAMIF_CAP_CODEC_ON; + break; + case CAMIF_DMA_ON: + camif_reset(CAMIF_RESET,0); /* Flush Camera Core Buffer */ + if (cfg->dma_type&CAMIF_CODEC) { + CICOSCCTRL |= SCALERSTART; + n_cmd = CAMIF_CAP_CODEC_ON; + }else { + CIPRSCCTRL |= SCALERSTART; + n_cmd = CAMIF_CAP_PREVIEW_ON; + } + + /* wait until Sync Time expires */ + /* First settting, to wait VSYNC fall */ + /* By VESA spec,in 640x480 @60Hz + MAX Delay Time is around 64us which "while" has.*/ + while(VSYNC & CICOSTATUS); + break; + default: + break; + } + CIIMGCPT = n_cmd|CAMIF_CAP_ON; + return 0; +} + + +int camif_capture_stop(camif_cfg_t *cfg) +{ + u32 n_cmd = CIIMGCPT; /* Next Command */ + + switch(cfg->exec) { + case CAMIF_BOTH_DMA_OFF: + CIPRSCCTRL &= ~SCALERSTART; + CICOSCCTRL &= ~SCALERSTART; + n_cmd = 0; + break; + case CAMIF_DMA_OFF_L_IRQ: /* fall thru */ + case CAMIF_DMA_OFF: + if (cfg->dma_type&CAMIF_CODEC) { + CICOSCCTRL &= ~SCALERSTART; + n_cmd &= ~CAMIF_CAP_CODEC_ON; + if (!(n_cmd & CAMIF_CAP_PREVIEW_ON)) + n_cmd = 0; + }else { + CIPRSCCTRL &= ~SCALERSTART; + n_cmd &= ~CAMIF_CAP_PREVIEW_ON; + if (!(n_cmd & CAMIF_CAP_CODEC_ON)) + n_cmd = 0; + } + break; + default: + panic("Unexpected \n"); + } + CIIMGCPT = n_cmd; + if(cfg->exec == CAMIF_DMA_OFF_L_IRQ) { /* Last IRQ */ + if (cfg->dma_type & CAMIF_CODEC) + CICOCTRL |= LAST_IRQ_EN; + else + CIPRCTRL |= LAST_IRQ_EN; + } +#if 0 + else { /* to make internal state machine of CAMERA stop */ + camif_reset(CAMIF_RESET, 0); + } +#endif + return 0; +} + + +/* LastIRQEn is autoclear */ +void camif_last_irq_en(camif_cfg_t *cfg) +{ + if(cfg->exec == CAMIF_BOTH_DMA_ON) { + CIPRCTRL |= LAST_IRQ_EN; + CICOCTRL |= LAST_IRQ_EN; + } + else { + if (cfg->dma_type & CAMIF_CODEC) + CICOCTRL |= LAST_IRQ_EN; + else + CIPRCTRL |= LAST_IRQ_EN; + } +} + +static int +camif_scaler_internal(u32 srcWidth, u32 dstWidth, u32 *ratio, u32 *shift) +{ + if(srcWidth>=64*dstWidth){ + printk(KERN_ERR"CAMERA:out of prescaler range: srcWidth /dstWidth = %d(< 64)\n", + srcWidth/dstWidth); + return 1; + } + else if(srcWidth>=32*dstWidth){ + *ratio=32; + *shift=5; + } + else if(srcWidth>=16*dstWidth){ + *ratio=16; + *shift=4; + } + else if(srcWidth>=8*dstWidth){ + *ratio=8; + *shift=3; + } + else if(srcWidth>=4*dstWidth){ + *ratio=4; + *shift=2; + } + else if(srcWidth>=2*dstWidth){ + *ratio=2; + *shift=1; + } + else { + *ratio=1; + *shift=0; + } + return 0; +} + + +int camif_g_fifo_status(camif_cfg_t *cfg) +{ + u32 reg; + + if (cfg->dma_type & CAMIF_CODEC) { + u32 flag = CO_OVERFLOW_Y|CO_OVERFLOW_CB|CO_OVERFLOW_CR; + reg = CICOSTATUS; + if (reg & flag) { + printk("CODEC: FIFO error(0x%08x) and corrected\n",reg); + /* FIFO Error Count ++ */ + CIWDOFST |= CO_FIFO_Y|CO_FIFO_CB|CO_FIFO_CR; + CIWDOFST &= ~(CO_FIFO_Y|CO_FIFO_CB|CO_FIFO_CR); + return 1; /* Error */ + } + } + if (cfg->dma_type & CAMIF_PREVIEW) { + u32 flag = PR_OVERFLOW_CB|PR_OVERFLOW_CR; + reg = CIPRSTATUS; + if (reg & flag) { + printk("PREVIEW:FIFO error(0x%08x) and corrected\n",reg); + CIWDOFST |= PR_FIFO_CB|PR_FIFO_CR; + CIWDOFST &= ~(CO_FIFO_Y|CO_FIFO_CB|CO_FIFO_CR); + /* FIFO Error Count ++ */ + return 1; /* Error */ + } + } + return 0; /* No Error */ +} + + +/* Policy: + * if codec or preview define the win offset, + * other must follow that value. + */ +int camif_win_offset(camif_gc_t *gc ) +{ + u32 h = gc->win_hor_ofst; + u32 v = gc->win_ver_ofst; + + /*Clear Overflow */ + CIWDOFST = CO_FIFO_Y|CO_FIFO_CB|CO_FIFO_CR|PR_FIFO_CB|PR_FIFO_CB; + CIWDOFST = 0; /* ? Dummy */ + if (!h && !v) { + CIWDOFST = 0; + return 0; + } + CIWDOFST = WINOFEN | WINHOROFST(h) | WINVEROFST(v); + return 0; +} + +/* + * when you change the resolution in a specific camera, + * sometimes, it is necessary to change the polarity + * -- SW.LEE + */ +static void camif_polarity(camif_gc_t *gc) +{ + u32 cmd = CIGCTRL; + + cmd = cmd & ~(BIT26|BIT25|BIT24); /* clear polarity */ + if (gc->polarity_pclk) + cmd |= GC_INVPOLPCLK; + if (gc->polarity_vsync) + cmd |= GC_INVPOLVSYNC; + if (gc->polarity_href) + cmd |= GC_INVPOLHREF; + CIGCTRL |= cmd; +} + + +int camif_dynamic_open(camif_cfg_t *cfg) +{ + camif_win_offset(cfg->gc); + camif_polarity(cfg->gc); + + if(camif_scaler(cfg)) { + printk(KERN_ERR "CAMERA:Preview Scaler, Change WinHorOfset or Target Size\n"); + return 1; + } + camif_target_fmt(cfg); + if (camif_dma_burst(cfg)) { + printk(KERN_ERR "CAMERA:DMA Busrt Length Error \n"); + return 1; + } + if(camif_malloc(cfg) ) { + printk(KERN_ERR " Instead of using consistent_alloc()\n" + " lease use dedicated memory allocation for DMA memory\n"); + return -1; + } + camif_pingpong(cfg); + return 0; +} + +int camif_dynamic_close(camif_cfg_t *cfg) +{ + camif_demalloc(cfg); + return 0; +} + +static int camif_target_area(camif_cfg_t *cfg) +{ + u32 rect = cfg->target_x * cfg->target_y; + if (cfg->dma_type & CAMIF_CODEC ) { + CICOTAREA = rect; + } + if (cfg->dma_type & CAMIF_PREVIEW) { + CIPRTAREA = rect; + } + return 0; +} + +static int inline camif_hw_reg(camif_cfg_t *cfg) +{ + u32 cmd = 0; + + if (cfg->dma_type & CAMIF_CODEC) { + CICOSCPRERATIO = PRE_SHIFT(cfg->sc.shfactor) + |PRE_HRATIO(cfg->sc.prehratio)|PRE_VRATIO(cfg->sc.prevratio); + CICOSCPREDST = + PRE_DST_WIDTH(cfg->sc.predst_x)|PRE_DST_HEIGHT(cfg->sc.predst_y); + + /* Differ from Preview */ + if (cfg->sc.scalerbypass) + cmd |= SCALERBYPASS; + if (cfg->sc.scaleup_h & cfg->sc.scaleup_v) + cmd |= BIT30|BIT29; + CICOSCCTRL = cmd | MAIN_HRATIO(cfg->sc.mainhratio) + |MAIN_VRATIO(cfg->sc.mainvratio); + return 0; + } + else if (cfg->dma_type & CAMIF_PREVIEW) { + CIPRSCPRERATIO = PRE_SHIFT(cfg->sc.shfactor) + |PRE_HRATIO(cfg->sc.prehratio)|PRE_VRATIO(cfg->sc.prevratio); + CIPRSCPREDST = + PRE_DST_WIDTH(cfg->sc.predst_x)|PRE_DST_HEIGHT(cfg->sc.predst_y); + /* Differ from Codec */ + if (cfg->fmt & CAMIF_RGB24) { + cmd |= RGB_FMT24; + } + else { + /* RGB16 */; + } + if (cfg->sc.scaleup_h & cfg->sc.scaleup_v) + cmd |= BIT29|BIT28; + CIPRSCCTRL = cmd |MAIN_HRATIO(cfg->sc.mainhratio)|S_METHOD + |MAIN_VRATIO(cfg->sc.mainvratio); + }else { + panic("CAMERA:DMA_TYPE Wrong \n"); + } + + return 0; +} + + +/* Configure Pre-scaler control & main scaler control register */ +static int camif_scaler(camif_cfg_t *cfg) +{ + int tx = cfg->target_x,ty=cfg->target_y; + int sx, sy; + + if (tx <= 0 || ty<= 0) panic("CAMERA: Invalid target size \n"); + + sx = cfg->gc->source_x - 2*cfg->gc->win_hor_ofst; + sy = cfg->gc->source_y - 2*cfg->gc->win_ver_ofst; + if (sx <= 0 || sy<= 0) panic("CAMERA: Invalid source size \n"); + cfg->sc.modified_src_x = sx; + cfg->sc.modified_src_y = sy; + + /* Pre-scaler control register 1 */ + camif_scaler_internal(sx,tx,&cfg->sc.prehratio,&cfg->sc.hfactor); + camif_scaler_internal(sy,ty,&cfg->sc.prevratio,&cfg->sc.vfactor); + + if (cfg->dma_type & CAMIF_PREVIEW) { + if ( (sx /cfg->sc.prehratio) <= 640 ) {} + else { + printk(KERN_INFO "CAMERA: Internal Preview line buffer is 640 pixels\n"); + return 1; /* Error */ + } + } + + cfg->sc.shfactor = 10-(cfg->sc.hfactor+cfg->sc.vfactor); + /* Pre-scaler control register 2 */ + cfg->sc.predst_x = sx / cfg->sc.prehratio; + cfg->sc.predst_y = sy / cfg->sc.prevratio; + + /* Main-scaler control register */ + cfg->sc.mainhratio = (sx << 8)/(tx << cfg->sc.hfactor); + cfg->sc.mainvratio = (sy << 8)/(ty << cfg->sc.vfactor); + DPRINTK(" sx %d, sy %d tx %d ty %d \n",sx,sy,tx,ty); + DPRINTK(" hfactor %d vfactor %d \n",cfg->sc.hfactor,cfg->sc.vfactor); + + cfg->sc.scaleup_h = (sx <= tx) ? 1: 0; + cfg->sc.scaleup_v = (sy <= ty) ? 1: 0; + if ( cfg->sc.scaleup_h != cfg->sc.scaleup_v) + printk(KERN_ERR "scaleup_h must be same to scaleup_v \n"); + camif_hw_reg(cfg); + camif_target_area(cfg); + return 0; +} + +/****************************************************** + CalculateBurstSize - Calculate the busrt lengths + Description: + - dstHSize: the number of the byte of H Size. +********************************************************/ +static void camif_g_bsize(u32 hsize, u32 *mburst, u32 *rburst) +{ + u32 tmp; + + tmp = (hsize/4) % 16; + switch(tmp) { + case 0: + *mburst=16; + *rburst=16; + break; + case 4: + *mburst=16; + *rburst=4; + break; + case 8: + *mburst=16; + *rburst=8; + break; + default: + tmp=(hsize/4)%8; + switch(tmp) { + case 0: + *mburst=8; + *rburst=8; + break; + case 4: + *mburst=8; + *rburst=4; + default: + *mburst=4; + tmp=(hsize/4)%4; + *rburst= (tmp) ? tmp: 4; + break; + } + break; + } +} + +/* SXGA 1028x1024*/ +/* XGA 1024x768 */ +/* SVGA 800x600 */ +/* VGA 640x480 */ +/* CIF 352x288 */ +/* QVGA 320x240 */ +/* QCIF 176x144 */ +/* ret val + 1 : DMA Size Error +*/ +#define BURST_ERR 1 +static int camif_dma_burst(camif_cfg_t *cfg) +{ + int width = cfg->target_x; + + if (cfg->dma_type & CAMIF_CODEC ) { + u32 yburst_m, yburst_r; + u32 cburst_m, cburst_r; + /* CODEC DMA WIDHT is multiple of 16 */ + if (width %16 != 0 ) return BURST_ERR; /* DMA Burst Length Error */ + camif_g_bsize(width,&yburst_m,&yburst_r); + camif_g_bsize(width/2,&cburst_m,&cburst_r); + CICOCTRL =YBURST_M(yburst_m)|CBURST_M(cburst_m) + |YBURST_R(yburst_r)|CBURST_R(cburst_r); + } + + if (cfg->dma_type & CAMIF_PREVIEW) { + u32 rgburst_m, rgburst_r; + if(cfg->fmt == CAMIF_RGB24) { + if (width %2 != 0 ) return BURST_ERR; /* DMA Burst Length Error */ + camif_g_bsize(width*4,&rgburst_m,&rgburst_r); + } + else { /* CAMIF_RGB16 */ + if ((width/2) %2 != 0 ) return BURST_ERR; /* DMA Burst Length Error */ + camif_g_bsize(width*2,&rgburst_m,&rgburst_r); + } + CIPRCTRL = RGBURST_M(rgburst_m) | RGBURST_R(rgburst_r); + } + return 0; +} + +static int camif_gpio_init(void) +{ +#ifdef CONFIG_ARCH_S3C24A0A + /* S3C24A0A has the dedicated signal pins for Camera */ +#else + set_gpio_ctrl(GPIO_CAMDATA0); + set_gpio_ctrl(GPIO_CAMDATA1); + set_gpio_ctrl(GPIO_CAMDATA2); + set_gpio_ctrl(GPIO_CAMDATA3); + set_gpio_ctrl(GPIO_CAMDATA4); + set_gpio_ctrl(GPIO_CAMDATA5); + set_gpio_ctrl(GPIO_CAMDATA6); + set_gpio_ctrl(GPIO_CAMDATA7); + set_gpio_ctrl(GPIO_CAMPCLKIN); + set_gpio_ctrl(GPIO_CAMVSYNC); + set_gpio_ctrl(GPIO_CAMHREF); + set_gpio_ctrl(GPIO_CAMPCLKOUT); + set_gpio_ctrl(GPIO_CAMRESET); +#endif + return 0; +} + + +#define ROUND_ADD 0x100000 + +#ifdef CONFIG_ARCH_S3C24A0A +int camif_clock_init(camif_gc_t *gc) +{ + unsigned int upll, camclk_div, camclk; + + if (!gc) camclk = 24000000; + else { + camclk = gc->camclk; + if (camclk > 48000000) + printk(KERN_ERR "Wrong Camera Clock\n"); + } + + CLKCON |= CLKCON_CAM_UPLL | CLKCON_CAM_HCLK; + upll = get_bus_clk(GET_UPLL); + printk(KERN_INFO "CAMERA:Default UPLL %08d and Assing 96Mhz to UPLL\n",upll); + UPLLCON = FInsrt(56, fPLL_MDIV) | FInsrt(2, fPLL_PDIV)| FInsrt(1, fPLL_SDIV); + upll = get_bus_clk(GET_UPLL); + + camclk_div = (upll+ROUND_ADD) / camclk - 1; + CLKDIVN = (CLKDIVN & 0xFF) | CLKDIVN_CAM(camclk_div); + printk(KERN_INFO"CAMERA:upll %d MACRO 0x%08X CLKDIVN 0x%08X \n", + upll, CLKDIVN_CAM(camclk_div),CLKDIVN); + CIIMGCPT = 0; /* Dummy ? */ + return 0; +} +#else +int camif_clock_init(camif_gc_t *gc) +{ + unsigned int upll, camclk_div, camclk; + if (!gc) camclk = 24000000; + else { + camclk = gc->camclk; + if (camclk > 48000000) + printk(KERN_ERR "Wrong Camera Clock\n"); + } + + CLKCON |= CLKCON_CAMIF; + upll = elfin_get_bus_clk(GET_UPLL); + printk(KERN_INFO "CAMERA:Default UPLL %08d and Assing 96Mhz to UPLL\n",upll); + { + UPLLCON = FInsrt(60, fPLL_MDIV) | FInsrt(4, fPLL_PDIV)| FInsrt(1, fPLL_SDIV); + CLKDIVN |= DIVN_UPLL; /* For USB */ + upll = elfin_get_bus_clk(GET_UPLL); + } + + camclk_div = (upll+ROUND_ADD) /(camclk * 2) -1; + CAMDIVN = CAMCLK_SET_DIV|(camclk_div&0xf); + printk(KERN_INFO "CAMERA:upll %08d cam_clk %08d CAMDIVN 0x%08x \n",upll,camclk, CAMDIVN); + CIIMGCPT = 0; /* Dummy ? */ + return 0; +} +#endif + +/* + Reset Camera IP in CPU + Reset External Sensor + */ +void camif_reset(int is, int delay) +{ + switch (is) { + case CAMIF_RESET: + CIGCTRL |= GC_SWRST; + mdelay(1); + CIGCTRL &= ~GC_SWRST; + break; + case CAMIF_EX_RESET_AH: /*Active High */ + CIGCTRL &= ~GC_CAMRST; + udelay(200); + CIGCTRL |= GC_CAMRST; + udelay(delay); + CIGCTRL &= ~GC_CAMRST; + break; + case CAMIF_EX_RESET_AL: /*Active Low */ + CIGCTRL |= GC_CAMRST; + udelay(200); + CIGCTRL &= ~GC_CAMRST; + udelay(delay); + CIGCTRL |= GC_CAMRST; + break; + default: + break; + } +} + +/* For Camera Operation, + * we can give the high priority to REQ2 of ARBITER1 + */ + +/* Please move me into proper place + * camif_gc_t is not because "rmmod imgsenor" will delete the instance of camif_gc_t + */ +static u32 old_priority; + +static void camif_bus_priority(int flag) +{ + if (flag) { +#ifdef CONFIG_ARCH_S3C24A0A + old_priority = PRIORITY0; + PRIORITY0 = PRIORITY_I_FIX; + PRIORITY1 = PRIORITY_I_FIX; + +#else + old_priority = PRIORITY; + PRIORITY &= ~(3<<7); + PRIORITY |= (1<<7); /* Arbiter 1, REQ2 first */ + PRIORITY &= ~(1<<1); /* Disable Priority Rotate */ +#endif + } + else { +#ifdef CONFIG_ARCH_S3C24A0A + PRIORITY0 = old_priority; + PRIORITY1 = old_priority; +#else + PRIORITY = old_priority; +#endif + } +} + +static void inline camif_clock_off(void) +{ + CIIMGCPT = 0; +#if defined (CONFIG_ARCH_S3C24A0A) + CLKCON &= ~CLKCON_CAM_UPLL; + CLKCON &= ~CLKCON_CAM_HCLK; +#else + CLKCON &= ~CLKCON_CAMIF; +#endif +} + + +/* Init external image sensor + * Before make some value into image senor, + * you must set up the pixel clock. + */ +void camif_setup_sensor(void) +{ + camif_reset(CAMIF_RESET, 0); + camif_gpio_init(); + camif_clock_init(NULL); +/* Sometimes ,Before loading I2C module, we need the reset signal */ +#ifdef CONFIG_ARCH_S3C24A0A + camif_reset(CAMIF_EX_RESET_AL,1000); +#else + camif_reset(CAMIF_EX_RESET_AH,1000); +#endif +} + +void camif_hw_close(camif_cfg_t *cfg) +{ + camif_bus_priority(0); + camif_clock_off(); +} + +void camif_hw_open(camif_gc_t *gc) +{ + camif_source_fmt(gc); + camif_win_offset(gc); + camif_bus_priority(1); +} + + + +/* + * Local variables: + * tab-width: 8 + * c-indent-level: 8 + * c-basic-offset: 8 + * c-set-style: "K&R" + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/camif.h b/arch/arm/mach-s3c2440/camera/camif.h new file mode 100644 index 00000000000..8b4f9aaf688 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/camif.h @@ -0,0 +1,304 @@ +/* + FIMC2.0 Camera Header File + + Copyright (C) 2003 Samsung Electronics (SW.LEE: hitchcar@samsung.com) + + Author : SW.LEE <hitchcar@samsung.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +* +*/ + + +#ifndef __FIMC20_CAMIF_H_ +#define __FIMC20_CAMIF_H_ + +#ifdef __KERNEL__ + +#include "bits.h" +#include "videodev.h" +#include <asm/types.h> +#include <linux/i2c.h> + +#endif /* __KERNEL__ */ + +#ifndef O_NONCAP +#define O_NONCAP O_TRUNC +#endif + +/* Codec or Preview Status */ +#define CAMIF_STARTED BIT1 +#define CAMIF_STOPPED BIT2 +#define CAMIF_INT_HAPPEN BIT3 + +/* Codec or Preview : Interrupt FSM */ +#define CAMIF_1nd_INT BIT7 +#define CAMIF_Xnd_INT BIT8 +#define CAMIF_Ynd_INT BIT9 +#define CAMIF_Znd_INT BIT10 +#define CAMIF_NORMAL_INT BIT11 +#define CAMIF_DUMMY_INT BIT12 +#define CAMIF_PENDING_INT 0 + + +/* CAMIF RESET Definition */ +#define CAMIF_RESET BIT0 +#define CAMIF_EX_RESET_AL BIT1 /* Active Low */ +#define CAMIF_EX_RESET_AH BIT2 /* Active High */ + + +enum camif_itu_fmt { + CAMIF_ITU601 = BIT31, + CAMIF_ITU656 = 0 +}; + +/* It is possbie to use two device simultaneously */ +enum camif_dma_type { + CAMIF_PREVIEW = BIT0, + CAMIF_CODEC = BIT1, +}; + +enum camif_order422 { + CAMIF_YCBYCR = 0, + CAMIF_YCRYCB = BIT14, + CAMIF_CBYCRY = BIT15, + CAMIF_CRYCBY = BIT14 | BIT15 +}; + +enum flip_mode { + CAMIF_FLIP = 0, + CAMIF_FLIP_X = BIT14, + CAMIF_FLIP_Y = BIT15, + CAMIF_FLIP_MIRROR = BIT14 |BIT15, +}; + +enum camif_codec_fmt { + /* Codec part */ + CAMIF_IN_YCBCR420 = BIT0, /* Currently IN_YCBCR format fixed */ + CAMIF_IN_YCBCR422 = BIT1, + CAMIF_OUT_YCBCR420 = BIT4, + CAMIF_OUT_YCBCR422 = BIT5, + /* Preview Part */ + CAMIF_RGB16 = BIT2, + CAMIF_RGB24 = BIT3, +}; + +enum camif_capturing { + CAMIF_BOTH_DMA_ON = BIT4, + CAMIF_DMA_ON = BIT3, + CAMIF_BOTH_DMA_OFF = BIT1, + CAMIF_DMA_OFF = BIT0, + /*------------------------*/ + CAMIF_DMA_OFF_L_IRQ= BIT5, +}; + +typedef struct camif_performance +{ + int frames; + int framesdropped; + __u64 bytesin; + __u64 bytesout; + __u32 reserved[4]; +} camif_perf_t; + + +typedef struct { + dma_addr_t phys_y; + dma_addr_t phys_cb; + dma_addr_t phys_cr; + u8 *virt_y; + u8 *virt_cb; + u8 *virt_cr; + dma_addr_t phys_rgb; + u8 *virt_rgb; +}img_buf_t; + + +/* this structure convers the CIWDOFFST, prescaler, mainscaler */ +typedef struct { + u32 modified_src_x; /* After windows applyed to source_x */ + u32 modified_src_y; + u32 hfactor; + u32 vfactor; + u32 shfactor; /* SHfactor = 10 - ( hfactor + vfactor ) */ + u32 prehratio; + u32 prevratio; + u32 predst_x; + u32 predst_y; + u32 scaleup_h; + u32 scaleup_v; + u32 mainhratio; + u32 mainvratio; + u32 scalerbypass; /* only codec */ +} scaler_t; + + +enum v4l2_status { + CAMIF_V4L2_INIT = BIT0, + CAMIF_v4L2_DIRTY = BIT1, +}; + + +/* Global Status Definition */ +#define PWANT2START BIT0 +#define CWANT2START BIT1 +#define BOTH_STARTED (PWANT2START|CWANT2START) +#define PNOTWORKING BIT4 +#define C_WORKING BIT5 + +typedef struct { + struct semaphore lock; + enum camif_itu_fmt itu_fmt; + enum camif_order422 order422; + u32 win_hor_ofst; + u32 win_ver_ofst; + u32 camclk; /* External Image Sensor Camera Clock */ + u32 source_x; + u32 source_y; + u32 polarity_pclk; + u32 polarity_vsync; + u32 polarity_href; + struct i2c_client *sensor; + u32 user; /* MAX 2 (codec, preview) */ + u32 old_priority; /* BUS PRIORITY register */ + u32 status; + u32 init_sensor;/* initializing sensor */ + void *other; /* Codec camif_cfg_t */ + u32 reset_type; /* External Sensor Reset Type */ + u32 reset_udelay; +} camif_gc_t; /* gobal control register */ + + +/* when App want to change v4l2 parameter, + * we instantly store it into v4l2_t v2 + * and then reflect it to hardware + */ +typedef struct v4l2 { + struct v4l2_fmtdesc *fmtdesc; + struct v4l2_pix_format fmt; /* current pixel format */ + struct v4l2_input input; + struct video_picture picture; + enum v4l2_status status; + int used_fmt ; /* used format index */ +} v4l2_t; + + +typedef struct camif_c_t { + struct video_device *v; + /* V4L2 param only for v4l2 driver */ + v4l2_t v2; + camif_gc_t *gc; /* Common between Codec and Preview */ + /* logical parameter */ + wait_queue_head_t waitq; + u32 status; /* Start/Stop */ + u32 fsm; /* Start/Stop */ + u32 open_count; /* duplicated */ + int irq; + char shortname[16]; + u32 target_x; + u32 target_y; + scaler_t sc; + enum flip_mode flip; + enum camif_dma_type dma_type; + /* 4 pingpong Frame memory */ + u8 *pp_virt_buf; + dma_addr_t pp_phys_buf; + u32 pp_totalsize; + u32 pp_num; /* used pingpong memory number */ + img_buf_t img_buf[4]; + enum camif_codec_fmt fmt; + enum camif_capturing exec; + camif_perf_t perf; + u32 now_frame_num; + u32 auto_restart; /* Only For Preview */ +} camif_cfg_t; + +#ifdef SW_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + + +#ifdef SW_DEBUG +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#else +#define assert(expr) +#endif + + + +extern int camif_capture_start(camif_cfg_t *); +extern int camif_capture_stop(camif_cfg_t *); +extern int camif_g_frame_num(camif_cfg_t *); +extern u8 * camif_g_frame(camif_cfg_t *); +extern int camif_win_offset(camif_gc_t *); +extern void camif_hw_open(camif_gc_t *); +extern void camif_hw_close(camif_cfg_t *); +extern int camif_dynamic_open(camif_cfg_t *); +extern int camif_dynamic_close(camif_cfg_t *); +extern void camif_reset(int,int); +extern void camif_setup_sensor(void); +extern int camif_g_fifo_status(camif_cfg_t *); +extern void camif_last_irq_en(camif_cfg_t *); +extern void camif_change_flip(camif_cfg_t *); + + +/* Todo + * API Interface function to both Character and V4L2 Drivers + */ +extern int camif_do_write(struct file *,const char *, size_t, loff_t *); +extern int camif_do_ioctl(struct inode *, struct file *,unsigned int, void *); + + +/* + * API for Decoder (S5x532, OV7620..) + */ +void camif_register_decoder(struct i2c_client *); +void camif_unregister_decoder(struct i2c_client*); + + + +/* API for FSM */ +#define INSTANT_SKIP 0 +#define INSTANT_GO 1 + +extern ssize_t camif_p_1fsm_start(camif_cfg_t *); +extern ssize_t camif_p_2fsm_start(camif_cfg_t *); +extern ssize_t camif_4fsm_start(camif_cfg_t *); +extern ssize_t camif_p_stop(camif_cfg_t *); +extern int camif_enter_p_4fsm(camif_cfg_t *); +extern int camif_enter_c_4fsm(camif_cfg_t *); +extern int camif_enter_2fsm(camif_cfg_t *); +extern int camif_enter_1fsm(camif_cfg_t *); +extern int camif_check_preview(camif_cfg_t *); +extern int camif_callback_start(camif_cfg_t *); +extern int camif_clock_init(camif_gc_t *); + +/* + * V4L2 Part + */ +#define VID_HARDWARE_SAMSUNG_FIMC20 236 + + + + + +#endif + + +/* + * Local variables: + * tab-width: 8 + * c-indent-level: 8 + * c-basic-offset: 8 + * c-set-style: "K&R" + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/camif_fsm.c b/arch/arm/mach-s3c2440/camera/camif_fsm.c new file mode 100644 index 00000000000..3e2b71af338 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/camif_fsm.c @@ -0,0 +1,427 @@ +/* + Copyright (C) 2004 Samsung Electronics + SW.LEE <hitchcar@sec.samsung.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/signal.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/kmod.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <linux/pagemap.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/semaphore.h> +#include <linux/miscdevice.h> + +//#define SW_DEBUG + +#include "camif.h" +const char *fsm_version = + "$Id: camif_fsm.c,v 1.3 2004/04/27 10:26:28 swlee Exp $"; + + +/* + * FSM function is the place where Synchronization in not necessary + * because IRS calls this functions. + */ + +ssize_t camif_p_1fsm_start(camif_cfg_t *cfg) +{ + //camif_reset(CAMIF_RESET,0); + cfg->exec = CAMIF_DMA_ON; + camif_capture_start(cfg); + camif_last_irq_en(cfg); + cfg->status = CAMIF_STARTED; + cfg->fsm = CAMIF_1nd_INT; + return 0; +} + + +ssize_t camif_p_2fsm_start(camif_cfg_t *cfg) +{ + camif_reset(CAMIF_RESET,0);/* FIFO Count goes to zero */ + cfg->exec = CAMIF_DMA_ON; + camif_capture_start(cfg); + cfg->status = CAMIF_STARTED; + cfg->fsm = CAMIF_1nd_INT; + return 0; +} + + +ssize_t camif_4fsm_start(camif_cfg_t *cfg) +{ + camif_reset(CAMIF_RESET,0); /* FIFO Count goes to zero */ + cfg->exec = CAMIF_DMA_ON; + camif_capture_start(cfg); + cfg->status = CAMIF_STARTED; + cfg->fsm = CAMIF_1nd_INT; + cfg->perf.frames = 0; + return 0; +} + + +/* Policy: + cfg->perf.frames set in camif_fsm.c + cfg->status set in video-driver.c + */ + +/* + * Don't insert camif_reset(CAM_RESET, 0 ) into this func + */ +ssize_t camif_p_stop(camif_cfg_t *cfg) +{ + cfg->exec = CAMIF_DMA_OFF; +// cfg->status = CAMIF_STOPPED; + camif_capture_stop(cfg); + cfg->perf.frames = 0; /* Dupplicated ? */ + return 0; +} + +/* When C working, P asks C to play togehter */ +/* Only P must call this function */ +void camif_start_c_with_p (camif_cfg_t *cfg, camif_cfg_t *other) +{ +// cfg->gc->other = get_camif(CODEC_MINOR); + cfg->gc->other = other; + camif_start_p_with_c(cfg); +} + +static void camif_start_p_with_c(camif_cfg_t *cfg) +{ + camif_cfg_t *other = (camif_cfg_t *)cfg->gc->other; + /* Preview Stop */ + cfg->exec = CAMIF_DMA_OFF; + camif_capture_stop(cfg); + /* Start P and C */ + camif_reset(CAMIF_RESET, 0); + cfg->exec =CAMIF_BOTH_DMA_ON; + camif_capture_start(cfg); + cfg->fsm = CAMIF_1nd_INT; /* For Preview */ + if(!other) panic("Unexpected Error \n"); + other->fsm = CAMIF_1nd_INT; /* For Preview */ +} + +static void camif_auto_restart(camif_cfg_t *cfg) +{ +// if (cfg->dma_type & CAMIF_CODEC) return; + if (cfg->auto_restart) + camif_start_p_with_c(cfg); +} + + +/* Supposed that PREVIEW already running + * request PREVIEW to start with Codec + */ +static int camif_check_global(camif_cfg_t *cfg) +{ + int ret = 0; + + if (down_interruptible(&cfg->gc->lock)) + return -ERESTARTSYS; + if ( cfg->gc->status & CWANT2START ) { + cfg->gc->status &= ~CWANT2START; + cfg->auto_restart = 1; + ret = 1; + } + else { + ret = 0; /* There is no codec */ + cfg->auto_restart = 0; /* Duplicated ..Dummy */ + } + + up(&cfg->gc->lock); + + return ret; +} + +/* + * 1nd INT : Start Interrupt + * Xnd INT : enable Last IRQ : pingpong get the valid data + * Ynd INT : Stop Codec or Preview : pingpong get the valid data + * Znd INT : Last IRQ : valid data + */ +#define CHECK_FREQ 5 +int camif_enter_p_4fsm(camif_cfg_t *cfg) +{ + int ret = 0; + + cfg->perf.frames++; + if (cfg->fsm == CAMIF_NORMAL_INT) + if (cfg->perf.frames % CHECK_FREQ == 0) + ret = camif_check_global(cfg); + if (ret > 0) cfg->fsm = CAMIF_Xnd_INT; /* Codec wait for Preview */ + + switch (cfg->fsm) { + case CAMIF_1nd_INT: /* Start IRQ */ + cfg->fsm = CAMIF_NORMAL_INT; + ret = INSTANT_SKIP; + DPRINTK(KERN_INFO "1nd INT \n"); + break; + case CAMIF_NORMAL_INT: + cfg->status = CAMIF_INT_HAPPEN; + cfg->fsm = CAMIF_NORMAL_INT; + ret = INSTANT_GO; + DPRINTK(KERN_INFO "NORMAL INT \n"); + break; + case CAMIF_Xnd_INT: + camif_last_irq_en(cfg);/* IRQ for Enabling LAST IRQ */ + cfg->status = CAMIF_INT_HAPPEN; + cfg->fsm = CAMIF_Ynd_INT; + ret = INSTANT_GO; + DPRINTK(KERN_INFO "Xnd INT \n"); + break; + case CAMIF_Ynd_INT: /* Capture Stop */ + cfg->exec = CAMIF_DMA_OFF; + cfg->status = CAMIF_INT_HAPPEN; + camif_capture_stop(cfg); + cfg->fsm = CAMIF_Znd_INT; + ret = INSTANT_GO; + DPRINTK(KERN_INFO "Ynd INT \n"); + break; + case CAMIF_Znd_INT: /* LAST IRQ (Dummy IRQ */ + cfg->fsm = CAMIF_DUMMY_INT; + cfg->status = CAMIF_INT_HAPPEN; + ret = INSTANT_GO; + camif_auto_restart(cfg); /* Automatically Restart Camera */ + DPRINTK(KERN_INFO "Znd INT \n"); + break; + case CAMIF_DUMMY_INT: + cfg->status = CAMIF_STOPPED; /* Dupplicate ? */ + ret = INSTANT_SKIP; +// DPRINTK(KERN_INFO "Dummy INT \n"); + break; + default: + printk(KERN_INFO "Unexpect INT %d \n",cfg->fsm); + ret = INSTANT_SKIP; + break; + } + return ret; +} + + +/* + * NO autorestart included in this function + */ +int camif_enter_c_4fsm(camif_cfg_t *cfg) +{ + int ret; + + cfg->perf.frames++; +#if 0 + if ( (cfg->fsm==CAMIF_NORMAL_INT) + && (cfg->perf.frames>cfg->restart_limit-1) + ) + cfg->fsm = CAMIF_Xnd_INT; +#endif + switch (cfg->fsm) { + case CAMIF_1nd_INT: /* Start IRQ */ + cfg->fsm = CAMIF_NORMAL_INT; +// cfg->status = CAMIF_STARTED; /* need this to meet auto-restart */ + ret = INSTANT_SKIP; + DPRINTK(KERN_INFO "1nd INT \n"); + break; + case CAMIF_NORMAL_INT: + cfg->status = CAMIF_INT_HAPPEN; + cfg->fsm = CAMIF_NORMAL_INT; + ret = INSTANT_GO; + DPRINTK(KERN_INFO "NORMALd INT \n"); + break; + case CAMIF_Xnd_INT: + camif_last_irq_en(cfg);/* IRQ for Enabling LAST IRQ */ + cfg->status = CAMIF_INT_HAPPEN; + cfg->fsm = CAMIF_Ynd_INT; + ret = INSTANT_GO; + DPRINTK(KERN_INFO "Xnd INT \n"); + break; + case CAMIF_Ynd_INT: /* Capture Stop */ + cfg->exec = CAMIF_DMA_OFF; + cfg->status = CAMIF_INT_HAPPEN; + camif_capture_stop(cfg); + cfg->fsm = CAMIF_Znd_INT; + ret = INSTANT_GO; + DPRINTK(KERN_INFO "Ynd INT \n"); + break; + case CAMIF_Znd_INT: /* LAST IRQ (Dummy IRQ */ + cfg->fsm = CAMIF_DUMMY_INT; + cfg->status = CAMIF_INT_HAPPEN; + ret = INSTANT_GO; + DPRINTK(KERN_INFO "Znd INT \n"); + break; + case CAMIF_DUMMY_INT: + cfg->status = CAMIF_STOPPED; /* Dupplicate ? */ + ret = INSTANT_SKIP; + break; + default: + printk(KERN_INFO "Unexpect INT %d \n",cfg->fsm); + ret = INSTANT_SKIP; + break; + } + return ret; +} + +/* 4 Interrups State Machine is for two pingpong + * 1nd INT : Start Interrupt + * Xnd INT : enable Last IRQ : pingpong get the valid data + * Ynd INT : Stop Codec or Preview : pingpong get the valid data + * Znd INT : Last IRQ : valid data + * + * Note: + * Before calling this func, you must call camif_reset + */ + +int camif_enter_2fsm(camif_cfg_t *cfg) /* Codec FSM */ +{ + int ret; + + cfg->perf.frames++; + switch (cfg->fsm) { + case CAMIF_1nd_INT: /* Start IRQ */ + cfg->fsm = CAMIF_Xnd_INT; + ret = INSTANT_SKIP; +// printk(KERN_INFO "1nd INT \n"); + break; + case CAMIF_Xnd_INT: + camif_last_irq_en(cfg);/* IRQ for Enabling LAST IRQ */ + cfg->now_frame_num = 0; + cfg->status = CAMIF_INT_HAPPEN; + cfg->fsm = CAMIF_Ynd_INT; + ret = INSTANT_GO; +// printk(KERN_INFO "2nd INT \n"); + break; + case CAMIF_Ynd_INT: /* Capture Stop */ + cfg->exec = CAMIF_DMA_OFF; + cfg->now_frame_num = 1; + cfg->status = CAMIF_INT_HAPPEN; + camif_capture_stop(cfg); + cfg->fsm = CAMIF_Znd_INT; + ret = INSTANT_GO; +// printk(KERN_INFO "Ynd INT \n"); + break; + case CAMIF_Znd_INT: /* LAST IRQ (Dummy IRQ */ + cfg->now_frame_num = 0; +// cfg->fsm = CAMIF_DUMMY_INT; + cfg->status = CAMIF_INT_HAPPEN; + ret = INSTANT_GO; +// printk(KERN_INFO "Znd INT \n"); + break; + case CAMIF_DUMMY_INT: + cfg->status = CAMIF_STOPPED; /* Dupplicate ? */ + ret = INSTANT_SKIP; + printk(KERN_INFO "Dummy INT \n"); + break; + default: /* CAMIF_PENDING_INT */ + printk(KERN_INFO "Unexpect INT \n"); + ret = INSTANT_SKIP; + break; + } + return ret; +} + + +/* 2 Interrups State Machine is for one pingpong + * 1nd INT : Stop Codec or Preview : pingpong get the valid data + * 2nd INT : Last IRQ : dummy data + */ +int camif_enter_1fsm(camif_cfg_t *cfg) /* Codec FSM */ +{ + int ret; + + cfg->perf.frames++; + switch (cfg->fsm) { + case CAMIF_Ynd_INT: /* IRQ for Enabling LAST IRQ */ + cfg->exec = CAMIF_DMA_OFF; + camif_capture_stop(cfg); + cfg->fsm = CAMIF_Znd_INT; + ret = INSTANT_SKIP; + // printk(KERN_INFO "Ynd INT \n"); + break; + case CAMIF_Znd_INT: /* LAST IRQ (Dummy IRQ */ + cfg->fsm = CAMIF_DUMMY_INT; + cfg->status = CAMIF_INT_HAPPEN; + ret = INSTANT_GO; + // printk(KERN_INFO "Znd INT \n"); + break; + case CAMIF_DUMMY_INT: + cfg->status = CAMIF_STOPPED; /* Dupplicate ? */ + ret = INSTANT_SKIP; + printk(KERN_INFO "Dummy INT \n"); + break; + default: + printk(KERN_INFO "Unexpect INT \n"); + ret = INSTANT_SKIP; + break; + } + return ret; +} + + +/* + * GLOBAL STATUS CONTROL FUNCTION + * + */ + + +/* Supposed that PREVIEW already running + * request PREVIEW to start with Codec + */ +int camif_callback_start(camif_cfg_t *cfg) +{ + int doit = 1; + while (doit) { + if (down_interruptible(&cfg->gc->lock)) { + return -ERESTARTSYS; + } + cfg->gc->status = CWANT2START; + cfg->gc->other = cfg; + up(&cfg->gc->lock); + doit = 0; + } + return 0; +} + +/* + * Return status of Preview Machine + ret value : + 0: Preview is not working + X: Codec must follow PREVIEW start +*/ +int camif_check_preview(camif_cfg_t *cfg) +{ + int ret = 0; + + if (down_interruptible(&cfg->gc->lock)) { + ret = -ERESTARTSYS; + return ret; + } + if (cfg->gc->user == 1) ret = 0; + // else if (cfg->gc->status & PNOTWORKING) ret = 0; + else ret = 1; + up(&cfg->gc->lock); + return ret; +} + + + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/imgsensor.c b/arch/arm/mach-s3c2440/camera/imgsensor.c new file mode 100644 index 00000000000..44b7bee1929 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/imgsensor.c @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2004 Samsung Electronics + * SW.LEE <hitchcar@samsung.com> + * + * Copyright (C) 2000 Russell King : pcf8583.c + * + * 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. + * + * Driver for FIMC20 Camera Decoder + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/delay.h> + + +#ifdef CONFIG_ARCH_S3C24A0A +#else +#include <asm/arch/S3C2440.h> +#endif + +#define SW_DEBUG +#include "camif.h" +#include "sensor.h" + +#ifndef SAMSUNG_SXGA_CAM +#include "s5x532_rev36.h" +#else +#include "sxga.h" +#endif + +static const char *sensor_version = + "$Id: imgsensor.c,v 1.11 2004/06/10 12:45:40 swlee Exp $"; + + +static struct i2c_driver s5x532_driver; +static camif_gc_t data = { + itu_fmt: CAMIF_ITU601, + order422: CAMIF_YCBYCR, + camclk: 24000000, +#ifndef SAMSUNG_SXGA_CAM + source_x: 640, + source_y: 480, + win_hor_ofst: 112, + win_ver_ofst: 20, +#else + source_x: 1280, + source_y: 1024, + win_hor_ofst: 0, + win_ver_ofst: 0, +#endif + polarity_pclk:1, + polarity_href:0, +#ifdef CONFIG_ARCH_S3C24A0A + reset_type:CAMIF_EX_RESET_AL, /* Active Low */ +#else + reset_type:CAMIF_EX_RESET_AH, /* Ref board has inverted signal */ +#endif + reset_udelay:2000, +}; + +#define CAM_ID 0x5a + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { (CAM_ID>>1), I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c: normal_addr, + normal_i2c_range: ignore, + probe: ignore, + probe_range: ignore, + ignore: ignore, + ignore_range: ignore, + force: ignore, +}; + +s5x532_t s5x532_regs_mirror[S5X532_REGS]; + +unsigned char +s5x532_read(struct i2c_client *client,unsigned char subaddr) +{ + int ret; + unsigned char buf[1]; + struct i2c_msg msg ={ client->addr, 0, 1, buf}; + buf[0] = subaddr; + + ret = i2c_transfer(client->adapter,&msg, 1) == 1 ? 0 : -EIO; + if (ret == -EIO) { + printk(" I2C write Error \n"); + return -EIO; + } + + msg.flags = I2C_M_RD; + ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO; + + return buf[0]; +} + + +static int +s5x532_write(struct i2c_client *client, + unsigned char subaddr, unsigned char val) +{ + unsigned char buf[2]; + struct i2c_msg msg = { client->addr, 0, 2, buf}; + + buf[0]= subaddr; + buf[1]= val; + + return i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO; +} + +void inline s5x532_init(struct i2c_client *sam_client) +{ + int i; + + printk(KERN_ERR "s5x532_init \n"); + for (i = 0; i < S5X532_INIT_REGS; i++) { + s5x532_write(sam_client, + s5x532_reg[i].subaddr, s5x532_reg[i].value ); + } + +#ifdef YOU_WANT_TO_CHECK_IMG_SENSOR + for (i = 0; i < S5X532_INIT_REGS;i++) { + if ( s5x532_reg[i].subaddr == PAGE_ADDRESS ) { + s5x532_write(sam_client, + s5x532_reg[i].subaddr, s5x532_reg[i].value); + + printk(KERN_ERR "Page: Subaddr %02x = 0x%02x\n", + s5x532_reg[i].subaddr, s5x532_regs_mirror[i].value); + + + } else + { + s5x532_regs_mirror[i].subaddr = s5x532_reg[i].subaddr; + s5x532_regs_mirror[i].value = + s5x532_read(sam_client,s5x532_reg[i].subaddr); + printk(KERN_ERR "Subaddr %02x = 0x%02x\n", + s5x532_reg[i].subaddr, s5x532_regs_mirror[i].value); + } + } +#endif + +} + +static int +s5x532_attach(struct i2c_adapter *adap, int addr, unsigned short flags,int kind) +{ + struct i2c_client *c; + + c = kmalloc(sizeof(*c), GFP_KERNEL); + if (!c) return -ENOMEM; + + strcpy(c->name, "S5X532"); + c->id = s5x532_driver.id; + c->flags = I2C_CLIENT_ALLOW_USE; + c->addr = addr; + c->adapter = adap; + c->driver = &s5x532_driver; + c->data = &data; + data.sensor = c; + + camif_register_decoder(c); + return i2c_attach_client(c); +} + +static int s5x532_probe(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, s5x532_attach); +} + +static int s5x532_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + camif_unregister_decoder(client); + return 0; +} + +static int +s5x532_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + switch (cmd) { + case SENSOR_INIT: + s5x532_init(client); + printk(KERN_INFO "CAMERA: S5X532 Sensor initialized\n"); + break; + case USER_ADD: + MOD_INC_USE_COUNT; + break; + case USER_EXIT: + MOD_DEC_USE_COUNT; + break; +/* Todo + case SENSOR_BRIGHTNESS: + change_sensor(); + break; +*/ + default: + panic("Unexpect Sensor Command \n"); + break; + } + return 0; +} + +static struct i2c_driver s5x532_driver = { + name: "S5X532", + id: I2C_ALGO_S3C, + flags: I2C_DF_NOTIFY, + attach_adapter: s5x532_probe, + detach_client: s5x532_detach, + command: s5x532_command +}; + +static void iic_gpio_port(void) +{ +#ifdef CONFIG_ARCH_S3C24A0A +#else + GPECON &= ~(0xf <<28); + GPECON |= 0xa <<28; +#endif +} + +static __init int camif_sensor_init(void) +{ + iic_gpio_port(); + return i2c_add_driver(&s5x532_driver); +} + + +static __init void camif_sensor_exit(void) +{ + i2c_del_driver(&s5x532_driver); +} + +module_init(camif_sensor_init) +module_exit(camif_sensor_exit) + +MODULE_AUTHOR("SW.LEE <hitchcar@sec.samsung.com>"); +MODULE_DESCRIPTION("I2C Client Driver For Fimc2.0 MISC Driver"); +MODULE_LICENSE("GPL"); + + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/miscdevice.h b/arch/arm/mach-s3c2440/camera/miscdevice.h new file mode 100644 index 00000000000..2e1cfbcdfef --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/miscdevice.h @@ -0,0 +1,18 @@ + + /*---------------------------------------------------------- + * (C) 2004 Samsung Electronics + * SW.LEE < hitchcar@samsung.com> + * + ----------------------------------------------------------- */ + +#ifndef _LINUX_S3C_MISCDEVICE_H +#define _LINUX_S3C_MISCDEVICE_H + +#define CODEC_MINOR 212 +#define PREVIEW_MINOR 213 + + + + + +#endif diff --git a/arch/arm/mach-s3c2440/camera/qt-driver.c b/arch/arm/mach-s3c2440/camera/qt-driver.c new file mode 100644 index 00000000000..0c5dd40cf2c --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/qt-driver.c @@ -0,0 +1,169 @@ +/* + * SW.LEE <hitchcar@samsung.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License 2. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/signal.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/kmod.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/irq.h> +#include <asm/semaphore.h> +#include <linux/miscdevice.h> + +//#define SW_DEBUG + +#include "camif.h" +#include "videodev.h" +#include "miscdevice.h" +#include "cam_reg.h" +#include "sensor.h" +#include "userapp.h" + + +/************************* Sharp Zarus API ************************** +* refering to Camera Driver API for SL-5000D/SL-5600 revision 1.00 +* April 11, 2002. + SW.LEE <hitchcar@sec.samsung.com> + I want to use Sharp Camera Application. +* +*/ + +#define READ_MODE_STATUS 0x1 +#define READ_MODE_IMAGE 0x0 +#define CAPTURE_SPEED +#define H_FLIP +#define V_FLIP +typedef enum sharp_readmode +{ + IMAGE = 0, STATUS = 1, + FASTER = 0, BETTER = 2, + XNOFLIP = 0, XFLIP = 4, + YNOFLIP = 0, YFLIP = 8, + AUTOMATICFLIP = -1 +} ReadMode_t; + + +static struct sharp_param_t { + ReadMode_t readMode; + char CameraStatus[4]; +} sharp_param = { STATUS, {'s','m','c','A'}}; + + +camif_param_t qt_parm = { 640,480,240,320,16,0}; + +static void setReadMode(const char *b,size_t count) +{ + int i = *(b+2) - 48 ; + if ( 4 == count ) { + i = (*(b+3) - 48) + i * 10; + } + + // DPRINTK(" setReadMode %s conversion value %d \n",b , i); + if ( i & STATUS ) { + // DPRINTK(" STATUS MODE \n"); + sharp_param.readMode = i; + } + else { + // DPRINTK(" IMAGE MODE \n"); + sharp_param.readMode = i; + } +} + + + + +extern ssize_t camif_p_read(struct file *, char *, size_t , loff_t *); + +ssize_t z_read(struct file *f, char *buf, size_t count, loff_t *pos) +{ + size_t end; + + if (sharp_param.readMode & STATUS ) { + buf[0] = sharp_param.CameraStatus[0]; + buf[1] = sharp_param.CameraStatus[1]; + buf[2] = sharp_param.CameraStatus[2]; + buf[3] = sharp_param.CameraStatus[3]; + end = 4; + return end; + } + else { /* Image ReadMode */ + /* + if (( sharp_param.readMode & (BETTER|X FLIP|YFLIP))) + DPRINTK(" Not Supporting BETTER|XFLIP|YFLIP\n"); + */ + return camif_p_read(f,buf,count,pos); + } +} + +static void z_config(camif_cfg_t *cfg,int x, int y) +{ + cfg->target_x = x; + cfg->target_y = y; + cfg->fmt = CAMIF_RGB16; + if (camif_dynamic_open(cfg)) { + panic(" Eror Happens \n"); + } +} + + +ssize_t z_write(struct file *f, const char *b, size_t c, loff_t *pos) +{ + int array[5]; + int zoom = 1; + camif_cfg_t *cfg; + + cfg = get_camif(MINOR(f->f_dentry->d_inode->i_rdev)); +// DPRINTK(" param %s count %d \n",b, c ); + + switch(*b) { + case 'M': + setReadMode(b, c); + break; + case 'B': /* Clear the latch flag of shutter button */ + DPRINTK(" clear latch flag of camera's shutter button\n"); + sharp_param.CameraStatus[0]='s'; + break; + case 'Y': /* I don't know how to set Shutter pressed */ + DPRINTK(" set latch flag n"); + sharp_param.CameraStatus[0]='S'; + break; + case 'S': /* Camera Image Resolution */ + case 'R': /* Donot support Rotation */ + DPRINTK(" param %s count %d \n",b, c ); + get_options((char *)(b+2), 5, array); + if ( array[3] == 512 ) zoom = 2; + z_config(cfg, array[1] * zoom , array[2] * zoom ); + camif_4fsm_start(cfg); + break; + case 'C': + DPRINTK(" param %s count %d \n",b, c ); + DPRINTK(" Start the camera to capture \n"); + sharp_param.CameraStatus[2]='C'; + camif_4fsm_start(cfg); + break; + default: + printk("Unexpected param %s count %d \n",b, c ); + } + + return c; +} + diff --git a/arch/arm/mach-s3c2440/camera/qt.h b/arch/arm/mach-s3c2440/camera/qt.h new file mode 100644 index 00000000000..e58368a22f0 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/qt.h @@ -0,0 +1,18 @@ +/* + * SW.LEE <hitchcar@samsung.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License 2. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef __Z_API_H_ +#define __Z_API_H_ + +extern ssize_t z_read(struct file *f, char *buf, size_t count, loff_t *pos); +extern ssize_t z_write(struct file *f, const char *b, size_t c, loff_t *pos); + + + +#endif + diff --git a/arch/arm/mach-s3c2440/camera/s5x532.h b/arch/arm/mach-s3c2440/camera/s5x532.h new file mode 100644 index 00000000000..12725f4271d --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/s5x532.h @@ -0,0 +1,143 @@ +/* + * 2004 (C) Samsung Electronics + * SW.LEE <hitchcar@sec.samsung.com> + * This file is subject to the terms and conditions of the GNU General Public + * License 2. See the file COPYING in the main directory of this archive + * for more details. + */ + + +#ifndef _SMDK2440_S5X532_H_ +#define _SMDK2440_S5X532_H_ + + +#define CHIP_DELAY 0xFF + +typedef struct samsung_t{ + unsigned char subaddr; + unsigned char value; + unsigned char page; +} s5x532_t; + +s5x532_t s5x532_reg[] = { + // page 5 + {0xec,0x05}, + {0x08,0x55,0x5}, + {0x0a,0x75,0x5}, + {0x0c,0x90,0x5}, + {0x0e,0x18,0x5}, + {0x12,0x09,0x5}, + {0x14,0x9d,0x5}, + {0x16,0x90,0x5}, + {0x1a,0x18,0x5}, + {0x1c,0x0c,0x5}, + {0x1e,0x09,0x5}, + {0x20,0x06,0x5}, + {0x22,0x20,0x5}, + {0x2a,0x00,0x5}, + {0x2d,0x04,0x5}, + {0x12,0x24,0x5}, + // page 3 + {0xec,0x03,0x3}, + {0x0c,0x09,0x3}, + {0x6c,0x09,0x3}, + {0x2b,0x10,0x3}, // momo clock inversion + // page 2 + {0xec,0x02,0x2}, + {0x03,0x09,0x2}, + {0x05,0x08,0x2}, + {0x06,0x01,0x2}, + {0x07,0xf8,0x2}, + {0x15,0x25,0x2}, + {0x30,0x29,0x2}, + {0x36,0x12,0x2}, + {0x38,0x04,0x2}, + {0x1b,0x77,0x2}, // 24MHz : 0x77, 12MHz : 0x22 + {0x1c,0x77,0x2}, // 24MHz : 0x77, 12MHz : 0x22 + // page 1 + {0xec,0x01,0x1}, + {0x00,0x03,0x1}, // + {0x0a,0x08,0x1}, // 0x0-QQVGA, 0x06-CIF, 0x02-QCIF, 0x08-VGA, 0x04-QVGA, 0x0a-SXGA + {0x0c,0x00,0x1}, // Pattern selectio. 0-CIS, 1-Color bar, 2-Ramp, 3-Blue screen + {0x10,0x27,0x1}, + // 0x21-ITU-R656(CrYCbY), 0x25-ITU-R601(CrYCbY), 0x26-ITU-R601(YCbYCr) + {0x50,0x21,0x1}, // Hblank + {0x51,0x00,0x1}, // Hblank + {0x52,0xA1,0x1}, // Hblank + {0x53,0x02,0x1}, // Hblank + {0x54,0x01,0x1}, // Vblank + {0x55,0x00,0x1}, // Vblank + {0x56,0xE1,0x1}, // Vblank + {0x57,0x01,0x1}, // Vblank + {0x58,0x21,0x1}, // Hsync + {0x59,0x00,0x1}, // Hsync + {0x5a,0xA1,0x1}, // Hsync + {0x5b,0x02,0x1}, // Hsync + {0x5c,0x03,0x1}, // Vref + {0x5d,0x00,0x1}, // Vref + {0x5e,0x05,0x1}, // Vref + {0x5f,0x00,0x1}, // Vref + {0x70,0x0E,0x1}, + {0x71,0xD6,0x1}, + {0x72,0x30,0x1}, + {0x73,0xDB,0x1}, + {0x74,0x0E,0x1}, + {0x75,0xD6,0x1}, + {0x76,0x18,0x1}, + {0x77,0xF5,0x1}, + {0x78,0x0E,0x1}, + {0x79,0xD6,0x1}, + {0x7a,0x28,0x1}, + {0x7b,0xE6,0x1}, + {0x50,0x00,0x1}, + {0x5c,0x00,0x1}, + + // page 0 + {0xec,0x00,0x0}, + {0x79,0x01,0x0}, + {0x58,0x90,0x0}, + {0x59,0xA0,0x0}, + {0x5a,0x50,0x0}, + {0x5b,0x70,0x0}, + {0x5c,0xD0,0x0}, + {0x5d,0xC0,0x0}, + {0x5e,0x28,0x0}, + {0x5f,0x08,0x0}, + {0x50,0x90,0x0}, + {0x51,0xA0,0x0}, + {0x52,0x50,0x0}, + {0x53,0x70,0x0}, + {0x54,0xD0,0x0}, + {0x55,0xC0,0x0}, + {0x56,0x28,0x0}, + {0x57,0x00,0x0}, + {0x48,0x90,0x0}, + {0x49,0xA0,0x0}, + {0x4a,0x50,0x0}, + {0x4b,0x70,0x0}, + {0x4c,0xD0,0x0}, + {0x4d,0xC0,0x0}, + {0x4e,0x28,0x0}, + {0x4f,0x08,0x0}, + {0x72,0x82,0x0}, // main clock = 24MHz:0xd2, 16M:0x82, 12M:0x54 + {0x75,0x05,0x0} // absolute vertical mirror. junon + +}; + + +#define S5X532_INIT_REGS (sizeof(s5x532_reg)/sizeof(s5x532_reg[0])) +#define S5X532_RISC_REGS 0xEB +#define S5X532_ISP_REGS 0xFB /* S5C7323X */ +#define S5X532_CIS_REGS 0x2F /* S5K437LA03 */ + + +#define PAGE_ADDRESS 0xEC + +//#define S5X532_REGS (S5X532_RISC_REGS+S5X532_ISP_REGS+S5X532_CIS_REGS) +#define S5X532_REGS (0x1000) + + + +#endif + + diff --git a/arch/arm/mach-s3c2440/camera/s5x532_rev36.h b/arch/arm/mach-s3c2440/camera/s5x532_rev36.h new file mode 100644 index 00000000000..b662e9c38c8 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/s5x532_rev36.h @@ -0,0 +1,208 @@ +/* + * 2004 (C) Samsung Electronics + * SW.LEE <hitchcar@sec.samsung.com> + * This file is subject to the terms and conditions of the GNU General Public + * License 2. See the file COPYING in the main directory of this archive + * for more details. + */ + + +#ifndef _SMDK2440_S5X532_H_ +#define _SMDK2440_S5X532_H_ + + +#define CHIP_DELAY 0xFF + +typedef struct samsung_t{ + unsigned char subaddr; + unsigned char value; + unsigned char page; +} s5x532_t; + +s5x532_t s5x532_reg[] = { + + //=============== page0 ===============// + {0xec,0x00,0x00}, + {0x02,0x00,0x00}, + {0x14,0x60,0x00}, + {0x15,0x60,0x00}, + {0x16,0x60,0x00}, + {0x1b,0x20,0x00}, + {0x1c,0x20,0x00}, + {0x1d,0x20,0x00}, + {0x1e,0x20,0x00}, + {0x72,0xdc,0x00}, + {0x73,0x11,0x00}, + {0x76,0x82,0x00}, + {0x77,0x90,0x00}, + {0x78,0x6c,0x00}, + {0x0a,0x02,0x00}, + {0x34,0x0d,0x00}, + {0x35,0x0a,0x00}, + {0x36,0x05,0x00}, + {0x37,0x05,0x00}, + {0x38,0x06,0x00}, + {0x39,0x08,0x00}, + {0x3A,0x0d,0x00}, + {0x3B,0x0d,0x00}, + {0x3C,0x18,0x00}, + {0x3D,0xE0,0x00}, + {0x3E,0x20,0x00}, + {0x66,0x02,0x00}, + {0x6c,0x40,0x00}, + {0x7c,0x01,0x00}, + {0x0D,0x24,0x00}, + {0x40,0x1B,0x00}, + {0x41,0x4F,0x00}, + {0x42,0x24,0x00}, + {0x43,0x3E,0x00}, + {0x44,0x32,0x00}, + {0x45,0x30,0x00}, + {0x48,0xa0,0x00}, + {0x49,0xd0,0x00}, + {0x4A,0x28,0x00}, + {0x4B,0x7d,0x00}, + {0x4C,0xd0,0x00}, + {0x4D,0xe0,0x00}, + {0x4E,0x1a,0x00}, + {0x4F,0xa0,0x00}, + {0x50,0xc0,0x00}, + {0x51,0xc0,0x00}, + {0x52,0x42,0x00}, + {0x53,0x7e,0x00}, + {0x54,0xc0,0x00}, + {0x55,0xf0,0x00}, + {0x56,0x1e,0x00}, + {0x57,0xe0,0x00}, + {0x58,0xc0,0x00}, + {0x59,0xa0,0x00}, + {0x5A,0x4a,0x00}, + {0x5B,0x7e,0x00}, + {0x5C,0xc0,0x00}, + {0x5D,0xf0,0x00}, + {0x5E,0x2a,0x00}, + {0x5F,0x10,0x00}, + {0x79,0x00,0x00}, + {0x7a,0x00,0x00}, + {0xe0,0x0f,0x00}, + {0xe3,0x14,0x00}, + {0xe5,0x48,0x00}, + {0xe7,0x58,0x00}, + + //=============== page1 ===============// + {0xec,0x01,0x01}, + {0x10,0x05,0x01}, + {0x20,0xde,0x01}, + {0x0b,0x06,0x01}, + {0x30,0x00,0x01}, + {0x31,0x00,0x01}, + {0x32,0x00,0x01}, + {0x24,0x28,0x01}, + {0x25,0x3F,0x01}, + {0x26,0x65,0x01}, + {0x27,0xA1,0x01}, + {0x28,0xFF,0x01}, + {0x29,0x96,0x01}, + {0x2A,0x85,0x01}, + {0x2B,0xFF,0x01}, + {0x2C,0x00,0x01}, + {0x2D,0x1B,0x01}, + {0xB0,0x28,0x01}, + {0xB1,0x3F,0x01}, + {0xB2,0x65,0x01}, + {0xB3,0xA1,0x01}, + {0xB4,0xFF,0x01}, + {0xB5,0x96,0x01}, + {0xB6,0x85,0x01}, + {0xB7,0xFF,0x01}, + {0xB8,0x00,0x01}, + {0xB9,0x1B,0x01}, + {0x15,0x15,0x01}, + {0x18,0x85,0x01}, + {0x1f,0x05,0x01}, + {0x87,0x40,0x01}, + {0x37,0x60,0x01}, + {0x38,0xd5,0x01}, + {0x48,0xa0,0x01}, + {0x61,0x54,0x01}, + {0x62,0x54,0x01}, + {0x63,0x14,0x01}, + {0x64,0x14,0x01}, + {0x6d,0x12,0x01}, + {0x78,0x09,0x01}, + {0x79,0xD7,0x01}, + {0x7A,0x14,0x01}, + {0x7B,0xEE,0x01}, + + //=============== page2 ===============// + {0xec,0x02,0x02}, + {0x2c,0x76,0x02}, + {0x25,0x25,0x02}, + {0x27,0x27,0x02}, + {0x30,0x29,0x02}, + {0x36,0x08,0x02}, + {0x38,0x04,0x02}, + + //=============== page3 ===============// + {0xec,0x03,0x03}, + {0x08,0x00,0x03}, + {0x09,0x33,0x03}, + + //=============== page4 ===============// + {0xec,0x04,0x04}, + {0x00,0x21,0x04}, + {0x01,0x00,0x04}, + {0x02,0x9d,0x04}, + {0x03,0x02,0x04}, + {0x04,0x04,0x04}, + {0x05,0x00,0x04}, + {0x06,0x1f,0x04}, + {0x07,0x02,0x04}, + {0x08,0x21,0x04}, + {0x09,0x00,0x04}, + {0x0a,0x9d,0x04}, + {0x0b,0x02,0x04}, + {0x0c,0x04,0x04}, + {0x0d,0x00,0x04}, + {0x0e,0x20,0x04}, + {0x0f,0x02,0x04}, + {0x1b,0x3c,0x04}, + {0x1c,0x3c,0x04}, + + //=============== page5 ===============// + {0xec,0x05,0x05}, + {0x1f,0x00,0x05}, + {0x08,0x59,0x05}, + {0x0a,0x71,0x05}, + {0x1e,0x23,0x05}, + {0x0e,0x3c,0x05}, + + //=============== page7 ===============// + {0xec,0x07,0x07}, + {0x11,0xfe,0x07}, + + // added by junon + {0xec,0x01,0x07}, + {0x10,0x26,0x07}, + // 0x21-ITU-R656(CbYCrY), 0x25-ITU-R601(CbYCrY), 0x26-ITU-R601(YCrYCb) + + +}; + + +#define S5X532_INIT_REGS (sizeof(s5x532_reg)/sizeof(s5x532_reg[0])) +#define S5X532_RISC_REGS 0xEB +#define S5X532_ISP_REGS 0xFB /* S5C7323X */ +#define S5X532_CIS_REGS 0x2F /* S5K437LA03 */ + + +#define PAGE_ADDRESS 0xEC + +//#define S5X532_REGS (S5X532_RISC_REGS+S5X532_ISP_REGS+S5X532_CIS_REGS) +#define S5X532_REGS (0x1000) + + + +#endif + + diff --git a/arch/arm/mach-s3c2440/camera/sensor.h b/arch/arm/mach-s3c2440/camera/sensor.h new file mode 100644 index 00000000000..e28d01c5bed --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/sensor.h @@ -0,0 +1,20 @@ +/* + * + * Copyright (C) 2004 Samsung Electronics + * SW.LEE <hitchcar@sec.samsung.com> + * + * 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 __SENSOR_CMD_H_ +#define __SENSOR_CMD_H_ + +#include "bits.h" + +#define SENSOR_INIT BIT0 +#define USER_ADD BIT1 +#define USER_EXIT BIT2 + +#endif diff --git a/arch/arm/mach-s3c2440/camera/sxga.h b/arch/arm/mach-s3c2440/camera/sxga.h new file mode 100644 index 00000000000..b41305a1927 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/sxga.h @@ -0,0 +1,504 @@ +/* + * 2004 (C) Samsung Electronics + * SW.LEE <hitchcar@sec.samsung.com> + * This file is subject to the terms and conditions of the GNU General Public + * License 2. See the file COPYING in the main directory of this archive + * for more details. + */ + + +#ifndef _SAMSUNG_SXGA_H_ +#define _SAMSUNG_SXGA_H_ + + +#define CHIP_DELAY 0xFF + +typedef struct samsung_t{ + unsigned char subaddr; + unsigned char value; + unsigned char page; +} s5x532_t; + +s5x532_t s5x532_reg[] = { + // page 0 + {0xec,0x00,0x0}, + {0x0c,0x38,0x0}, + {0x0d,0x24,0x0}, + {0x13,0x10,0x0}, + {0x14,0x10,0x0}, + {0x15,0x10,0x0}, + {0x16,0x10,0x0}, + {0x17,0x20,0x0}, + {0x18,0x30,0x0}, + {0x19,0x30,0x0}, + {0x1a,0x10,0x0}, + {0x1b,0x10,0x0}, + + {0x2d,0x40,0x0}, + {0x3e,0x10,0x0}, + {0x34,0x0a,0x0}, + {0x39,0x04,0x0}, + {0x3a,0x02,0x0}, + {0x31,0x05,0x0}, + + {0x40,0x1d,0x0}, + {0x41,0x50,0x0}, + {0x42,0x24,0x0}, + {0x43,0x3f,0x0}, + {0x44,0x30,0x0}, + {0x45,0x31,0x0}, + + {0x48,0xa0,0x0}, + {0x49,0xc0,0x0}, + {0x4a,0x58,0x0}, + {0x4b,0x50,0x0}, + {0x4c,0xb0,0x0}, + {0x4d,0xc0,0x0}, + {0x4e,0x30,0x0}, + {0x4f,0x20,0x0}, + + {0x50,0xa0,0x0}, + {0x51,0xc0,0x0}, + {0x52,0x50,0x0}, + {0x53,0x60,0x0}, + {0x54,0xb0,0x0}, + {0x55,0xc0,0x0}, + {0x56,0x20,0x0}, + {0x57,0x08,0x0}, +// {0x72,0x50,0x0}, // Clock 16 + {0x72,0x78,0x0}, // Clock 24Mhz +// {0x72,0xf0,0x0}, // Clock 48Mhz + // page 1 + {0xec,0x01,0x1}, + {0x10,0x17,0x1}, // ITU-R601 + /* + [3:2] : out_sel + 00 : 656 + 01 : 601 + 10 : RGB + 11 : CIS + [1] : YC_SEL + [0] : CBCR_SEL + */ + + {0x0b,0x06,0x1}, // 6 + {0x20,0xa8,0x1}, //b0); // Highlight C Supp 040215 + {0x22,0x26,0x1}, //2f); 040225 + + {0x24,0x08,0x1}, //00); //1F); 040226 + {0x25,0x10,0x1}, //10); //34); + {0x26,0x40,0x1}, //56); + {0x27,0x80,0x1}, //8D); + {0x28,0x2c,0x1}, //E7); + {0x29,0xd6,0x1}, //7C); + {0x2A,0x0c,0x1}, //70); + {0x2B,0xFF,0x1}, //FF); + {0x2C,0x00,0x1}, //00); + {0x2D,0x5f,0x1}, //1B); + // + {0xB0,0x08,0x1}, //00); //1F); 040226 + {0xB1,0x10,0x1}, //10); //34);50 + {0xB2,0x40,0x1}, //36); + {0xB3,0x80,0x1}, //6D); + {0xB4,0x2c,0x1}, //b7); + {0xB5,0xd6,0x1}, //7C); + {0xB6,0x0c,0x1}, //70); + {0xB7,0xFF,0x1}, //FF); + {0xB8,0x00,0x1}, //00); + {0xB9,0x5f,0x1}, //1B); + + + {0xc2,0x01,0x1}, // shading On + {0xc3,0x80,0x1}, + {0xc4,0x02,0x1}, + {0xc5,0x00,0x1}, + {0xc6,0x01,0x1}, + {0xc7,0x00,0x1}, + {0xc8,0x05,0x1}, + {0xc9,0x00,0x1}, + {0xca,0x04,0x1}, + + // shading 5 + {0xd0,0xb5,0x1}, + {0xd1,0x9c,0x1}, + {0xd2,0x8d,0x1}, + {0xd3,0x84,0x1}, + {0xd4,0x84,0x1}, + {0xd5,0x91,0x1}, + {0xd6,0xa0,0x1}, + {0xd7,0xb5,0x1}, + + {0xd8,0xc0,0x1}, + {0xd9,0xa6,0x1}, + {0xda,0x93,0x1}, + {0xdb,0x85,0x1}, + {0xdc,0x85,0x1}, + {0xdd,0x90,0x1}, + {0xde,0xa0,0x1}, + {0xdf,0xb8,0x1}, + + // Page 2 + {0xec,0x02,0x02}, + + {0x2d,0x02,0x02}, + {0x20,0x13,0x02}, + {0x21,0x13,0x2}, + {0x22,0x13,0x2}, + {0x23,0x13,0x2}, + {0x2e,0x85,0x2}, + {0x2f,0x34,0x2}, + {0x30,0x00,0x2}, + {0x28,0x94,0x2}, + + + // page 3 + {0xec,0x03,0x03}, + {0x10,0x00,0x3}, + {0x20,0x00,0x3}, + {0x21,0x20,0x3}, + {0x22,0x00,0x3}, + {0x23,0x00,0x3}, + {0x40,0x20,0x3}, + {0x41,0x20,0x3}, + {0x42,0x20,0x3}, + {0x43,0x20,0x3}, + {0x60,0x00,0x3}, + {0x61,0x00,0x3}, + {0x62,0x00,0x3}, + {0x63,0x00,0x3}, + {0x64,0x04,0x3}, + {0x65,0x1C,0x3}, + {0x66,0x05,0x3}, + {0x67,0x1C,0x3}, + {0x68,0x00,0x3}, + {0x69,0x2D,0x3}, + {0x6a,0x00,0x3}, + {0x6b,0x72,0x3}, + {0x6c,0x00,0x3}, + {0x6d,0x00,0x3}, + {0x6e,0x16,0x3}, // 2.38 + {0x6f,0x16,0x3}, // 2.38 + {0x70,0x00,0x3}, + {0x71,0x00,0x3}, + {0x72,0x45,0x3}, + {0x73,0x00,0x3}, + {0x74,0x1C,0x3}, + {0x75,0x05,0x3}, + + {0x80,0x00,0x3}, //for 0.02 _ 44 + {0x81,0x00,0x3}, + {0x82,0x00,0x3}, + {0x83,0x00,0x3}, + {0x84,0x04,0x3}, + {0x85,0x1c,0x3}, + {0x86,0x05,0x3}, + {0x87,0x1c,0x3}, + {0x88,0x00,0x3}, + {0x89,0x2d,0x3}, + {0x8a,0x00,0x3}, + {0x8b,0xcc,0x3}, + {0x8c,0x00,0x3}, + {0x8d,0x00,0x3}, + {0x8e,0x08,0x3}, + {0x8f,0x08,0x3}, + {0x90,0x01,0x3}, + {0x91,0x00,0x3}, + {0x92,0x91,0x3}, + {0x93,0x00,0x3}, + {0x94,0x88,0x3}, + {0x95,0x02,0x3}, + + + + // page 4 + {0xec,0x04,0x04}, + {0x3f,0x09,0x04}, // VGA : old board :0x08 , new board ; 0X09 + {0x18,0x00,0x04}, // sxga + {0x1c,0x41,0x04}, + {0x20,0x41,0x04}, // vga center 040215 + {0x22,0xc1,0x04},// a1); + {0x23,0x02,0x04}, + {0x28,0x41,0x04}, + {0x2a,0xc1,0x04},// a1); + {0x2b,0x02,0x04}, + + {0x3c,0x0b,0x04}, //f); // vga + {0x58,0x11,0x04}, + {0x5c,0x14,0x04}, + {0x60,0x21,0x04}, + {0x61,0x00,0x04}, + {0x62,0xB1,0x04}, + {0x63,0x02,0x04}, + {0x64,0x01,0x04}, + {0x65,0x00,0x04}, + {0x66,0x01,0x04}, + {0x67,0x02,0x04}, + {0x68,0x21,0x04}, + {0x69,0x00,0x04}, + {0x6a,0xB1,0x04}, + {0x6b,0x02,0x04}, + {0x6c,0x01,0x04}, + {0x6d,0x00,0x04}, + {0x6e,0x01,0x04}, + {0x6f,0x02,0x04}, + {0x70,0x2D,0x04}, + {0x71,0x00,0x04}, + {0x72,0xd3,0x04}, // 14 + {0x73,0x05,0x04}, // 15 + {0x74,0x1C,0x04}, + {0x75,0x05,0x04}, + {0x76,0x1b,0x04}, // HendL + {0x77,0x0b,0x04}, // HendH + {0x78,0x01,0x04}, // 5.00 + {0x79,0x80,0x04}, // 5.2a + {0x7a,0x33,0x04}, + {0x7b,0x00,0x04}, + {0x7c,0x38,0x04}, // 5.0e + {0x7d,0x03,0x04}, + {0x7e,0x00,0x04}, + {0x7f,0x0A,0x04}, + + {0x80,0x2e,0x04}, + {0x81,0x00,0x04}, + {0x82,0xae,0x04}, + {0x83,0x02,0x04}, + {0x84,0x00,0x04}, + {0x85,0x00,0x04}, + {0x86,0x01,0x04}, + {0x87,0x02,0x04}, + {0x88,0x2e,0x04}, + {0x89,0x00,0x04}, + {0x8a,0xae,0x04}, + {0x8b,0x02,0x04}, + {0x8c,0x1c,0x04}, + {0x8d,0x00,0x04}, + {0x8e,0x04,0x04}, + {0x8f,0x02,0x04}, + {0x90,0x2d,0x04}, + {0x91,0x00,0x04}, + {0x92,0xa5,0x04}, + {0x93,0x00,0x04}, + {0x94,0x88,0x04}, + {0x95,0x02,0x04}, + {0x96,0xb3,0x04}, + {0x97,0x06,0x04}, + {0x98,0x01,0x04}, + {0x99,0x00,0x04}, + {0x9a,0x33,0x04}, + {0x9b,0x30,0x04}, + {0x9c,0x50,0x04}, + {0x9d,0x30,0x04}, + {0x9e,0x01,0x04}, + {0x9f,0x08,0x04}, + + // page 5 + {0xec,0x05,0x05}, + {0x5a,0x22,0x05}, + + // page 6 + {0xec,0x06,0x06}, + {0x14,0x1e,0x06}, + {0x15,0xb4,0x04}, + {0x16,0x25,0x04}, + {0x17,0x74,0x04}, + + {0x10,0x48,0x04}, + {0x11,0xa0,0x04}, + {0x12,0x40,0x04}, // 040216 AE1 window ÁÙÀÓ + {0x13,0x70,0x04}, + + {0x1a,0x29,0x04}, // 040217 AWB window ÁÙÀÓ + {0x30,0x40,0x04}, + {0x31,0xa2,0x04}, + {0x32,0x50,0x04}, + {0x33,0xbc,0x04}, + {0x34,0x10,0x04}, + {0x35,0xd2,0x04}, + {0x36,0x18,0x04}, + {0x37,0xf5,0x04}, + {0x38,0x10,0x04}, + {0x39,0xd3,0x04}, + {0x3a,0x1a,0x04}, + {0x3b,0xf0,0x04}, + + // page 7 + {0xec,0x07,0x07}, + {0x08,0xff,0x7}, + {0x38,0x01,0x7}, //07); 040315 + {0x39,0x01,0x7}, //02); //4); 040223 040315 + {0x11,0xfe,0x7}, //fe); // green -2 040303 + {0x2a,0x20,0x7}, + {0x2b,0x20,0x7}, + {0x2c,0x10,0x7}, + {0x2d,0x00,0x7}, + {0x2e,0xf0,0x7}, + {0x2f,0xd0,0x7}, + {0x3a,0xf0,0x7}, + {0x23,0x07,0x7}, // for ESD + + // page 0 + {0xec,0x00,0x00}, + {0x8a,0x04,0x00}, + + // page 1 + {0xec,0x01,0x01}, + {0xe5,0xb0,0x01}, + {0xe5,0xb0,0x01}, + {0xc2,0x01,0x01}, + + {0x61,0x7b,0x01}, + {0x62,0x7b,0x01}, + {0x63,0x1b,0x01}, + {0x64,0x1b,0x01}, + + // page 0 + {0xec,0x00,0x00}, + {0x7e,0x04,0x00}, + + // page 4 + {0xec,0x04,0x04}, + {0x04,0x02,0x04}, + {0x06,0x02,0x04}, + + // page 1 + {0xec,0x01,0x01}, + {0x10,0x05,0x01}, + {0x54,0x02,0x01}, + {0x56,0x02,0x01}, + + // page 3 + {0xec,0x03,0x03}, + {0x0e,0x08,0x03}, + {0x0f,0x08,0x03}, + + // page 4 + {0xec,0x04,0x04}, + {0x00,0x30,0x04}, + {0x0a,0x30,0x04}, + + // page 5 + {0xec,0x05,0x05}, + {0x08,0x33,0x05}, + + // page 0 + {0xec,0x00,0x00}, + {0x02,0x00,0x00}, + + // page 4 +//scale out + {0xec,0x04,0x04}, + {0x02,0x20,0x04}, + {0x1c,0x4f,0x04}, + + // page 1 + {0xec,0x01,0x01}, + {0x52,0x20,0x01}, + + // page 5 + {0xec,0x05,0x05}, + {0x0e,0x4f,0x05}, + +//ae speed + // page 0 + {0xec,0x00,0x00}, + {0x92,0x80,0x00}, + {0x93,0x02,0x00}, + {0x94,0x04,0x00}, + {0x95,0x04,0x00}, + {0x96,0x04,0x00}, + {0x97,0x04,0x00}, + {0x9b,0x47,0x00}, + + {0xec,0x00,0x00}, + {0x40,0x17,0x00}, + {0x41,0x4c,0x00}, + {0x42,0x1d,0x00}, + {0x43,0x3e,0x00}, + {0x44,0x2a,0x00}, + {0x45,0x2d,0x00}, + + {0xec,0x01,0x01}, + {0x20,0xd0,0x01}, //high light color reference + + {0xec,0x00,0x00}, + {0x7e,0x00,0x00}, + {0x73,0x11,0x00}, // 41 + {0x78,0x78,0x00}, + + {0xec,0x07,0x07}, + {0x1b,0x3e,0x07}, + + {0xec,0x00,0x00}, + {0x48,0xA0,0x00}, //s48C0 + {0x49,0xB0,0x00}, //s49B0 + {0x4a,0x30,0x00}, //s4a20 + {0x4b,0x70,0x00}, //s4b70 + {0x4c,0xD0,0x00}, //s4cA0 + {0x4d,0xB0,0x00}, //s4dB0 + {0x4e,0x30,0x00}, //s4e30 + {0x4f,0xF0,0x00}, //s4fF0 + {0x50,0xA0,0x00}, //s50D0 + {0x51,0xB0,0x00}, //s51B0 + {0x52,0x25,0x00}, //s5210 + {0x53,0x70,0x00}, //s5370 + {0x54,0xD0,0x00}, //s5490 + {0x55,0xD0,0x00}, //s55B0 + {0x56,0x3A,0x00}, //s5640 + {0x57,0xD0,0x00}, //s57D0 + {0x58,0xA0,0x00}, //s58D0 + {0x59,0xA0,0x00}, //s59B0 + {0x5a,0x32,0x00}, //s5a0A + {0x5b,0x7A,0x00}, //s5b7A + {0x5c,0xB0,0x00}, //s5c90 + {0x5d,0xC0,0x00}, //s5dC0 + {0x5e,0x3E,0x00}, //s5e4A + {0x5f,0xfa,0x00}, //s5fD0 + + // gamma + {0xec,0x01,0x01}, + {0x24,0x31,0x01}, + {0x25,0x4C,0x01}, + {0x26,0x75,0x01}, + {0x27,0xB5,0x01}, + {0x28,0x17,0x01}, + {0x29,0xAE,0x01}, + {0x2A,0x97,0x01}, + {0x2B,0xFF,0x01}, + {0x2C,0x00,0x01}, + {0x2D,0x5B,0x01}, + + {0xB0,0x31,0x01}, + {0xB1,0x4C,0x01}, + {0xB2,0x75,0x01}, + {0xB3,0xB5,0x01}, + {0xB4,0x17,0x01}, + {0xB5,0xAE,0x01}, + {0xB6,0x97,0x01}, + {0xB7,0xFF,0x01}, + {0xB8,0x00,0x01}, + {0xB9,0x5B,0x01}, + + {0xec,0x00,0x00}, + {0x77,0xb0,0x00}, + {0x39,0x06,0x00}, + {0x3a,0x08,0x00}, + +}; + + +#define S5X532_INIT_REGS (sizeof(s5x532_reg)/sizeof(s5x532_reg[0])) +#define S5X532_RISC_REGS 0xEB +#define S5X532_ISP_REGS 0xFB /* S5C7323X */ +#define S5X532_CIS_REGS 0x2F /* S5K437LA03 */ + + +#define PAGE_ADDRESS 0xEC + +//#define S5X532_REGS (S5X532_RISC_REGS+S5X532_ISP_REGS+S5X532_CIS_REGS) +#define S5X532_REGS (0x1000) + + + +#endif + + diff --git a/arch/arm/mach-s3c2440/camera/userapp.h b/arch/arm/mach-s3c2440/camera/userapp.h new file mode 100644 index 00000000000..92033783923 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/userapp.h @@ -0,0 +1,44 @@ +/* + Character Driver API Interface + + Copyright (C) 2003 Samsung Electronics (SW.LEE: hitchcar@samsung.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +*/ + +#ifndef __FIMC20_CAMIF_USR_APP_H_ +#define __FIMC20_CAMIF_USR_APP_H_ + + +/* + * IOCTL Command for Character Driver + */ + +#define CMD_CAMERA_INIT 0x23 +/* Test Application Usage */ +typedef struct { + int src_x; + int src_y; + int dst_x; + int dst_y; + int bpp; + int flip; +} camif_param_t; + + + +#endif + + +/* + * Local variables: + * tab-width: 8 + * c-indent-level: 8 + * c-basic-offset: 8 + * c-set-style: "K&R" + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/v4l2_api.c b/arch/arm/mach-s3c2440/camera/v4l2_api.c new file mode 100644 index 00000000000..13aed36d917 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/v4l2_api.c @@ -0,0 +1,311 @@ +/* + * . 2004-01-03: SW.LEE <hitchcar@sec.samsung.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License 2. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/irq.h> +#include <linux/tqueue.h> +#include <linux/locks.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/miscdevice.h> +#include <linux/wait.h> + +#include <asm/io.h> +#include <asm/semaphore.h> +#include <asm/hardware.h> +#include <asm/uaccess.h> + +#include <asm/arch/cpu_s3c2440.h> +#include <asm/arch/S3C2440.h> + +#include "camif.h" +#include "videodev.h" + +/* + Codec_formats/Preview_format[0] must be same to initial value of + preview_init_param/codec_init_param +*/ + +const struct v4l2_fmtdesc codec_formats[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +// .flags = FORMAT_FLAGS_PLANAR, + .description = "4:2:2, planar, Y-Cb-Cr", + .pixelformat = V4L2_PIX_FMT_YUV422P, + + },{ + .index = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +// .flags = FORMAT_FLAGS_PLANAR, + .name = "4:2:0, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV420, + } +}; + + +/* Todo + FIMC V4L2_PIX_FMT_RGB565 is not same to that of V4L2spec + and so we need image convert to FIMC V4l2_PIX_FMT_RGB565. +*/ +const struct v4l2_fmtdesc preview_formats[] = { + { + .index = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, +// .flags = FORMAT_FLAGS_PACKED, + }, + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +// .flags = FORMAT_FLAGS_PACKED, + .description = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + } +} + +#define NUM_F ARRARY_SIZE(preview_formats) + + +/* + * This function and v4l2 structure made for V4L2 API functions + * App <--> v4l2 <--> logical param <--> hardware + */ +static int camif_get_v4l2(camif_cfg_t *cfg) +{ + return 0; +} + + +/* +** Gives the depth of a video4linux2 fourcc aka pixel format in bits. +*/ +static int pixfmt2depth(int pixfmt,int *fmtptr) +{ + int fmt, depth; + + switch (pixfmt) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + fmt = CAMIF_RGB_16; + depth = 16; + break; + case V4L2_PIX_FMT_BGR24: /* Not tested */ + case V4L2_PIX_FMT_RGB24: + fmt = CAMIF_RGB_24; + depth = 24; + break; + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + fmt = CAMIF_RGB_24; + depth 32; + break; + case V4L2_PIX_FMT_GREY: /* Not tested */ + fmt = CAMIF_OUT_YCBCR420; + depth = 8; + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV422P: + fmt = CAMIF_OUT_YCBCR422; + depth = 16; + break; + case V4L2_PIX_FMT_YUV420: + fmt = CAMIF_OUT_YCBCR420; + depth = 12; + break; + } + if (fmtptr) *fmtptr = fmt; + return depth; +} + + + +static int camif_s_v4l2(camif_cfg_t *cfg) +{ + int num = cfg->v2.used_fmt; + + if ( !(cfg->v2.status&CAMIF_V4L2_INIT)) { + int depth; + int fourcc = v2.fmtdesc[num].pixelformat; + + /* To define v4l2_fmtsdesc */ + if (cfg->dma_type == CAMIF_CODEC) + cfg->v2->fmtdesc = codec_formats; + else + cfg->v2->fmtdesc = preview_formats; + + /* To define v4l2_format used currently */ + cfg->v2.fmt.width = cfg->target_x; + cfg->v2.fmt.height = cfg->target_y; + cfg->v2.fmt.field = V4L2_FIELD_NONE; + cfg->v2.fmt.pixelformat = fourcc; + depth = pixfmt2depth(fourcc,NULL); + cfg->v2.fmt.bytesperline= cfg->v2.fmt.width*depth >> 3; + cfg->v2.fmt.sizeimage = + cfg->v2.fmt.height * cfg->v2.fmt.bytesperline; + + /* To define v4l2_input */ + cfg->v2.input.index = 0; + if (cfg->dma_type == CAMIF_CODEC) + snprintf(cfg->v2.input.name, 31, "CAMIF CODEC"); + else + snprintf(cfg->v2.input.name, 31, "CAMIF PREVIEW"); + cfg->v2.input.type = V4L2_INPUT_TYPE_CAMERA; + + /* Write the Status of v4l2 machine */ + cfg->v2.status |= CAMIF_V4L2_INIT; + } + return 0; +} + + +static int camif_g_fmt(camif_cfg_t *cfg, struct v4l2_format *f) +{ + int size = sizeof(struct v4l2_pix_format); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(&f->fmt.pix,0,size); + memcpy(&f->fmt.pix,&cfg->v2.fmt,size); + return 0; + default: + return -EINVAL; + } +} + + +/* Copy v4l2 parameter into other element of camif_cfg_t */ +static int camif_s_try(camif_cfg_t *cfg, int f) +{ + int fmt; + cfg->target_x = cfg->v2.fmt.width; + cfg->target_y = cfg->v2.fmt.height; + pixfmt2depth(cfg->v2.fmt.pixelformat,&fmt); + cfg->fmt = fmt; + camif_dynamic_conf(cfg); +} + + +static int camif_s_fmt(camif_cfg_t *cfg, struct v4l2_format *f) +{ + int retval; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + /* update our state informations */ +// down(&fh->cap.lock); + cfg->v2.fmt = f->pix; + cfg->v2.status |= CAMIF_v4L2_DIRTY; + camif_dynamic_conf(cfg); + cfg->v2.status &= ~CAMIF_v4L2_DIRTY; /* dummy ? */ +// up(&fh->cap.lock); + + return 0; + } + default: + return -EINVAL; + } + +} + +/* Refer ioctl of videodeX.c and bttv-driver.c */ +int camif_do_ioctl +(struct inode *inode, struct file *file,unsigned int cmd, void * arg) +{ + camif_cfg_t *cfg = file->private_data; + int ret = 0; + + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + strcpy(cap->driver,"Fimc Camera"); + strlcpy(cap->card,cfg->v->name,sizeof(cap->card)); + sprintf(cap->bus_info,"FIMC 2.0 AHB Bus"); + cap->version = 0; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE |V4L2_CAP_READWRITE; + return 0; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; + return camif_g_fmt(cfg,f); + } + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; + return camif_s_fmt(cfg,f); + } + + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + enum v4l2_buf_type type = f->type; + int index = f->index; + + if (index >= NUM_F) + return -EINVAL; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + default: + return -EINVAL; + } + memset(f,0,sizeof(*f)); + memcpy(f,cfg->v2.fmtdesc+index,sizeof(*f)); + return 0; + } + case VIDIOC_G_INPUT: + { + u32 *i = arg; + *i = cfg->v2.input; + return 0; + } + case VIDIOC_S_INPUT: + { + int index = *((int *)arg); + if (index != 0) + return -EINVAL; + cfg->v2.input.index = index; + return 0; + } + + default: + return -ENOIOCTLCMD; /* errno.h */ + } /* End of Switch */ + + +} + + + + + + + +/* + * Local variables: + * tab-width: 8 + * c-indent-level: 8 + * c-basic-offset: 8 + * c-set-style: "K&R" + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/video-driver.c b/arch/arm/mach-s3c2440/camera/video-driver.c new file mode 100644 index 00000000000..fe9130cd9f5 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/video-driver.c @@ -0,0 +1,591 @@ +/* + Copyright (C) 2004 Samsung Electronics + SW.LEE <hitchcar@sec.samsung.com> + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/signal.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/kmod.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/irq.h> +#include <asm/semaphore.h> +#include <linux/miscdevice.h> + +//#define SW_DEBUG + +#include "camif.h" +#include "videodev.h" +#include "miscdevice.h" +#include "cam_reg.h" +#include "sensor.h" +#include "userapp.h" + +#ifdef Z_API +#include "qt.h" +#endif + +/* Codec and Preview */ +#define CAMIF_NUM 2 +static camif_cfg_t fimc[CAMIF_NUM]; + +static const char *driver_version = + "$Id: video-driver.c,v 1.9 2004/06/02 03:10:36 swlee Exp $"; +extern const char *fimc_version; +extern const char *fsm_version; + + +camif_cfg_t * get_camif(int nr) +{ + camif_cfg_t *ret = NULL; + switch(nr) { + case CODEC_MINOR: + ret = &fimc[0]; + break; + case PREVIEW_MINOR: + ret = &fimc[1]; + break; + default: + panic("Unknow Minor Number \n"); + } + return ret; +} + + +static int camif_codec_start(camif_cfg_t *cfg) +{ + int ret = 0; + ret =camif_check_preview(cfg); + switch(ret) { + case 0: /* Play alone */ + DPRINTK("Start Alone \n"); + camif_4fsm_start(cfg); + cfg->gc->status |= C_WORKING; + break; + case -ERESTARTSYS: /* Busy , retry */ + //DPRINTK("Error \n"); + printk("Error \n"); + break; + case 1: + DPRINTK("need callback \n"); + ret = camif_callback_start(cfg); + if(ret < 0 ) { + printk(KERN_INFO "Busy RESTART \n"); + return ret; /* Busy, retry */ + } + break; + } + return ret; +} + + +ssize_t camif_write (struct file *f, const char *b, size_t c,loff_t *offset) +{ + camif_cfg_t *cfg; + + c = 0; /* return value */ + DPRINTK("\n"); + cfg = get_camif(MINOR(f->f_dentry->d_inode->i_rdev)); + switch (*b) { + case 'O': + if (cfg->dma_type & CAMIF_PREVIEW) { + if (cfg->gc->status & C_WORKING) { + camif_start_c_with_p(cfg,get_camif(CODEC_MINOR)); + } + else { + camif_4fsm_start(cfg); + } + } + else{ + c = camif_codec_start(cfg); + if(c < 0) c = 1; /* Error and neet to retry */ + } + + break; + case 'X': + camif_p_stop(cfg); + break; + default: + panic("CAMERA:camif_write: Unexpected Param\n"); + } + DPRINTK("end\n"); + + return c; +} + + +ssize_t camif_p_read(struct file *file, char *buf, size_t count, loff_t *pos) +{ + camif_cfg_t *cfg = NULL; + size_t end; + + cfg = get_camif(MINOR(file->f_dentry->d_inode->i_rdev)); + cfg->status = CAMIF_STARTED; + + if (wait_event_interruptible(cfg->waitq,cfg->status == CAMIF_INT_HAPPEN)) + return -ERESTARTSYS; + + cfg->status = CAMIF_STOPPED; + end = min_t(size_t, cfg->pp_totalsize /cfg->pp_num, count); + if (copy_to_user(buf, camif_g_frame(cfg), end)) + return -EFAULT; + + return end; +} + + +static ssize_t +camif_c_read(struct file *file, char *buf, size_t count, loff_t *pos) +{ + camif_cfg_t *cfg = NULL; + size_t end; + + /* cfg = file->private_data; */ + cfg = get_camif(MINOR(file->f_dentry->d_inode->i_rdev)); +#if 0 + if(file->f_flags & O_NONBLOCK) { + printk(KERN_ERR"Don't Support NON_BLOCK \n"); + } +#endif + + /* Change the below wait_event_interruptible func */ + if (wait_event_interruptible(cfg->waitq,cfg->status == CAMIF_INT_HAPPEN)) + return -ERESTARTSYS; + cfg->status = CAMIF_STOPPED; + end = min_t(size_t, cfg->pp_totalsize /cfg->pp_num, count); + if (copy_to_user(buf, camif_g_frame(cfg), end)) + return -EFAULT; + return end; +} + + +static void camif_c_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + camif_cfg_t *cfg = (camif_cfg_t *)dev_id; + DPRINTK("\n"); + camif_g_fifo_status(cfg); + camif_g_frame_num(cfg); + if(camif_enter_c_4fsm(cfg) == INSTANT_SKIP) return; + wake_up_interruptible(&cfg->waitq); +} + +static void camif_p_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + camif_cfg_t *cfg = (camif_cfg_t *)dev_id; + DPRINTK("\n"); + camif_g_fifo_status(cfg); + camif_g_frame_num(cfg); + if(camif_enter_p_4fsm(cfg) == INSTANT_SKIP) return; + wake_up_interruptible(&cfg->waitq); +#if 0 + if( (cfg->perf.frames % 5) == 0) + DPRINTK("5\n"); +#endif +} + +static void camif_release_irq(camif_cfg_t *cfg) +{ + disable_irq(cfg->irq); + free_irq(cfg->irq, cfg); +} + +static int camif_irq_request(camif_cfg_t *cfg) +{ + int ret = 0; + + if (cfg->dma_type & CAMIF_CODEC) { + if ((ret = request_irq(cfg->irq, camif_c_irq, + SA_INTERRUPT,cfg->shortname, cfg))) { + printk("request_irq(CAM_C) failed.\n"); + } + } + if (cfg->dma_type & CAMIF_PREVIEW) { + if ((ret = request_irq(cfg->irq, camif_p_irq, + SA_INTERRUPT,cfg->shortname, cfg))) { + printk("request_irq(CAM_P) failed.\n"); + } + } + return 0; +} + +static void camif_init_sensor(camif_cfg_t *cfg) +{ + camif_gc_t *gc = cfg->gc; + if (!gc->sensor) + panic("CAMERA:I2C Client(Img Sensor)Not registered\n"); + if(!gc->init_sensor) { + camif_reset(gc->reset_type, gc->reset_udelay); + gc->sensor->driver->command(gc->sensor,SENSOR_INIT,NULL); + gc->init_sensor = 1; /*sensor init done */ + } + gc->sensor->driver->command(gc->sensor, USER_ADD, NULL); +} + +static int camif_open(struct inode *inode, struct file *file) +{ + int err; + camif_cfg_t * cfg = get_camif(MINOR(inode->i_rdev)); + + if(cfg->dma_type & CAMIF_PREVIEW) { + if(down_interruptible(&cfg->gc->lock)) + return -ERESTARTSYS; + if (cfg->dma_type & CAMIF_PREVIEW) { + cfg->gc->status &= ~PNOTWORKING; + } + up(&cfg->gc->lock); + } + err = video_exclusive_open(inode,file); + cfg->gc->user++; + cfg->status = CAMIF_STOPPED; + if (err < 0) return err; + if (file->f_flags & O_NONCAP ) { + printk("Don't Support Non-capturing open \n"); + return 0; + } + file->private_data = cfg; + camif_irq_request(cfg); + camif_init_sensor(cfg); + return 0; +} + +#if 0 +static void print_pregs(void) +{ + printk(" CISRCFMT 0x%08X \n", CISRCFMT); + printk(" CIWDOFST 0x%08X \n", CIWDOFST); + printk(" CIGCTRL 0x%08X \n", CIGCTRL); + printk(" CIPRTRGFMT 0x%08X \n", CIPRTRGFMT); + printk(" CIPRCTRL 0x%08X \n", CIPRCTRL); + printk(" CIPRSCPRERATIO 0x%08X \n", CIPRSCPRERATIO); + printk(" CIPRSCPREDST 0x%08X \n", CIPRSCPREDST); + printk(" CIPRSCCTRL 0x%08X \n", CIPRSCCTRL); + printk(" CIPRTAREA 0x%08X \n", CIPRTAREA); + printk(" CIPRSTATUS 0x%08X \n", CIPRSTATUS); + printk(" CIIMGCPT 0x%08X \n", CIIMGCPT); +} + +static void print_cregs(void) +{ + printk(" CISRCFMT 0x%08X \n", CISRCFMT); + printk(" CIWDOFST 0x%08X \n", CIWDOFST); + printk(" CIGCTRL 0x%08X \n", CIGCTRL); + printk(" CICOCTRL 0x%8X \n", CICOCTRL); + printk(" CICOSCPRERATIO 0x%08X \n", CICOSCPRERATIO); + printk(" CICOSCPREDST 0x%08X \n", CICOSCPREDST); + printk(" CICOSCCTRL 0x%08X \n", CICOSCCTRL); + printk(" CICOTAREA 0x%08X \n", CICOTAREA); + printk(" CICOSTATUS 0x%8X \n", CICOSTATUS); + printk(" CIIMGCPT 0x%08X \n", CIIMGCPT); +} +#endif + + +static int camif_release(struct inode *inode, struct file *file) +{ + camif_cfg_t * cfg = get_camif(MINOR(inode->i_rdev)); + + //DPRINTK(" cfg->status 0x%0X cfg->gc->status 0x%0X \n", cfg->status,cfg->gc->status ); + if (cfg->dma_type & CAMIF_PREVIEW) { + if(down_interruptible(&cfg->gc->lock)) + return -ERESTARTSYS; + cfg->gc->status &= ~PWANT2START; + cfg->gc->status |= PNOTWORKING; + up(&cfg->gc->lock); + } + else { + cfg->gc->status &= ~CWANT2START; /* No need semaphore */ + } + camif_dynamic_close(cfg); + camif_release_irq(cfg); + video_exclusive_release(inode,file); + camif_p_stop(cfg); + cfg->gc->sensor->driver->command(cfg->gc->sensor, USER_EXIT, NULL); + cfg->gc->user--; + cfg->status = CAMIF_STOPPED; + return 0; +} + +static void fimc_config(camif_cfg_t *cfg,u32 x, u32 y, int bpp) +{ + cfg->target_x = x; + cfg->target_y = y; + + switch (bpp) { + case 16: + cfg->fmt = CAMIF_RGB16; + break; + case 24: + cfg->fmt = CAMIF_RGB24; + break; + case 420: + cfg->fmt = CAMIF_IN_YCBCR422|CAMIF_OUT_YCBCR420; + break; + case 422: + cfg->fmt = CAMIF_IN_YCBCR422|CAMIF_OUT_YCBCR422; + break; + default: + panic("Wrong BPP \n"); + } +} + + +static int +camif_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + camif_cfg_t *cfg = file->private_data; + camif_param_t par; + + switch (cmd) { + case CMD_CAMERA_INIT: + if (copy_from_user(&par,(camif_param_t *)arg, + sizeof(camif_param_t))) + return -EFAULT; + fimc_config(cfg,par.dst_x, par.dst_y, par.bpp); + if (camif_dynamic_open(cfg)) { + printk(" Eror Happens \n"); + ret = -1; + } + + switch (par.flip) { + case 3 : + cfg->flip = CAMIF_FLIP_MIRROR; + break; + case 1 : + cfg->flip = CAMIF_FLIP_X; + break; + case 2 : + cfg->flip = CAMIF_FLIP_Y; + break; + case 0 : + default: + cfg->flip = CAMIF_FLIP; + } + break; + /* Todo + case CMD_SENSOR_BRIGHTNESS: + cfg->gc->sensor->driver->command(cfg->gc->sensor, SENSOR_BRIGHTNESS, NULL); + break; + */ + default: + ret = -EINVAL; + break; + } + + return ret; +} + + +#if 0 +static int camif_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ +// camif_cfg_t *cfg = file->private_data; + + + switch (cmd) { +/* case Some_other_action */ + default: + return video_usercopy(inode, file, cmd, arg, camif_do_ioctl); + } +} +#endif + +static struct file_operations camif_c_fops = +{ + .owner = THIS_MODULE, + .open = camif_open, + .release = camif_release, + .ioctl = camif_ioctl, + .read = camif_c_read, + .write = camif_write, +}; + +static struct file_operations camif_p_fops = +{ + .owner = THIS_MODULE, + .open = camif_open, + .release = camif_release, + .ioctl = camif_ioctl, +#ifdef Z_API + .read = z_read, + .write = z_write, +#else + .read = camif_p_read, + .write = camif_write, +#endif +}; + +static struct video_device codec_template = +{ + .name = "CODEC_IF", + .type = VID_TYPE_CAPTURE|VID_TYPE_CLIPPING|VID_TYPE_SCALES, + .hardware = VID_HARDWARE_SAMSUNG_FIMC20, + .fops = &camif_c_fops, +// .release = camif_release + .minor = -1, +}; + +static struct video_device preview_template = +{ + .name = "PREVIEW_IF", + .type = VID_TYPE_CAPTURE|VID_TYPE_CLIPPING|VID_TYPE_SCALES, + .hardware = VID_HARDWARE_SAMSUNG_FIMC20, + .fops = &camif_p_fops, + .minor = -1, +}; + +static int preview_init(camif_cfg_t *cfg) +{ + char name[16]="CAM_PREVIEW"; + + memset(cfg, 0, sizeof(camif_cfg_t)); + cfg->target_x = 640; + cfg->target_y = 480; + cfg->pp_num = 4; + cfg->dma_type = CAMIF_PREVIEW; + cfg->fmt = CAMIF_RGB16; + cfg->flip = CAMIF_FLIP_Y; + cfg->v = &preview_template; + init_MUTEX(&cfg->v->lock); + cfg->irq = IRQ_CAM_P; + + strcpy(cfg->shortname,name); + init_waitqueue_head(&cfg->waitq); + cfg->status = CAMIF_STOPPED; + return cfg->status; +} + +static int codec_init(camif_cfg_t *cfg) +{ + char name[16]="CAM_CODEC"; + + memset(cfg, 0, sizeof(camif_cfg_t)); + cfg->target_x = 176; + cfg->target_y = 144; + cfg->pp_num = 4; + cfg->dma_type = CAMIF_CODEC; + cfg->fmt = CAMIF_IN_YCBCR422|CAMIF_OUT_YCBCR420; + cfg->flip = CAMIF_FLIP_X; + cfg->v = &codec_template; + init_MUTEX(&cfg->v->lock); + cfg->irq = IRQ_CAM_C; + strcpy(cfg->shortname,name); + init_waitqueue_head(&cfg->waitq); + cfg->status = CAMIF_STOPPED; + return cfg->status; +} + +static void camif_init(void) +{ + camif_setup_sensor(); +} + + + +static void print_version(void) +{ + printk(KERN_INFO"FIMC built:"__DATE__ " "__TIME__"\n%s\n%s\n%s\n", + fimc_version, driver_version,fsm_version); +} + + +static int camif_m_in(void) +{ + int ret = 0; + camif_cfg_t * cfg; + + camif_init(); + cfg = get_camif(CODEC_MINOR); + codec_init(cfg); + + if (video_register_device(cfg->v,0,CODEC_MINOR)!=0) { + DPRINTK("Couldn't register codec driver.\n"); + return 0; + } + cfg = get_camif(PREVIEW_MINOR); + preview_init(cfg); + if (video_register_device(cfg->v,0,PREVIEW_MINOR)!=0) { + DPRINTK("Couldn't register preview driver.\n"); + return 0; + } + + print_version(); + return ret; +} + +static void unconfig_device(camif_cfg_t *cfg) +{ + video_unregister_device(cfg->v); + camif_hw_close(cfg); + //memset(cfg, 0, sizeof(camif_cfg_t)); +} + +static void camif_m_out(void) /* module out */ +{ + camif_cfg_t *cfg; + + cfg = get_camif(CODEC_MINOR); + unconfig_device(cfg); + cfg = get_camif(PREVIEW_MINOR); + unconfig_device(cfg); + return; +} + +void camif_register_decoder(struct i2c_client *ptr) +{ + camif_cfg_t *cfg; + + cfg =get_camif(CODEC_MINOR); + cfg->gc = (camif_gc_t *)(ptr->data); + + cfg =get_camif(PREVIEW_MINOR); + cfg->gc = (camif_gc_t *)(ptr->data); + + sema_init(&cfg->gc->lock,1); /* global lock for both Codec and Preview */ + cfg->gc->status |= PNOTWORKING; /* Default Value */ + camif_hw_open(cfg->gc); +} + +void camif_unregister_decoder(struct i2c_client *ptr) +{ + camif_gc_t *gc; + + gc = (camif_gc_t *)(ptr->data); + gc->init_sensor = 0; /* need to modify */ +} + +module_init(camif_m_in); +module_exit(camif_m_out); + +EXPORT_SYMBOL(camif_register_decoder); +EXPORT_SYMBOL(camif_unregister_decoder); + +MODULE_AUTHOR("SW.LEE <hitchcar@sec.samsung.com>"); +MODULE_DESCRIPTION("Video-Driver For Fimc2.0 MISC Drivers"); +MODULE_LICENSE("GPL"); + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/videodev.c b/arch/arm/mach-s3c2440/camera/videodev.c new file mode 100644 index 00000000000..0b3498fa9c1 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/videodev.c @@ -0,0 +1,342 @@ +/* + * Video capture interface for Linux Character Device Driver. + * based on + * Alan Cox, <alan@redhat.com> video4linux + * + * Author: SW.LEE <hitchcar@samsung.com> + * 2004 (C) Samsung Electronics + * Modified for S3C2440/S3C24A0 Interface + * + * This file is released under the GPLv2 + */ + + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kmod.h> +#include <linux/slab.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/semaphore.h> + + + +#include "camif.h" +#include "videodev.h" +#include "miscdevice.h" + + +static DECLARE_MUTEX(videodev_lock); + +const char *fimc_version = "$Id: videodev.c,v 1.1.1.1 2004/04/27 03:52:50 swlee Exp $"; + +#define VIDEO_NAME "video4linux" + + +static inline unsigned iminor(struct inode *inode) +{ + return MINOR(inode->i_rdev); +} + +static inline unsigned imajor(struct inode *inode) +{ + return MAJOR(inode->i_rdev); +} + + +#define VIDEO_NUM_DEVICES 2 +static struct video_device *video_device[VIDEO_NUM_DEVICES]; + +static inline struct video_device * get_vd(int nr) +{ + if ( nr == CODEC_MINOR) + return video_device[0]; + else { + assert ( nr & PREVIEW_MINOR); + return video_device[1]; + } +} + +static inline void set_vd ( struct video_device * vd, int nr) +{ + if ( nr == CODEC_MINOR) + video_device[0] = vd; + else { + assert ( nr & PREVIEW_MINOR); + video_device[1] = vd; + } +} + +static inline int video_release(struct inode *inode, struct file *f) +{ + int minor = MINOR(inode->i_rdev); + struct video_device *vfd; + + vfd = get_vd(minor); +#if 1 /* needed until all drivers are fixed */ + if (!vfd->release) + return 0; +#endif + vfd->release(vfd); + return 0; +} + +struct video_device* video_devdata(struct file *file) +{ + return video_device[iminor(file->f_dentry->d_inode)]; +} + + +/* + * Open a video device. + */ +static int video_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + int err = 0; + struct video_device *vfl; + struct file_operations *old_fops; + + down(&videodev_lock); + + vfl = get_vd(minor); + + old_fops = file->f_op; + file->f_op = fops_get(vfl->fops); + if(file->f_op->open) + err = file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + up(&videodev_lock); + return err; +} + +/* + * open/release helper functions -- handle exclusive opens + */ +extern int video_exclusive_open(struct inode *inode, struct file *file) +{ + struct video_device *vfl = get_vd(MINOR(inode->i_rdev)); + int retval = 0; + + down(&vfl->lock); + if (vfl->users) { + retval = -EBUSY; + } else { + vfl->users++; + } + up(&vfl->lock); + return retval; +} + +extern int video_exclusive_release(struct inode *inode, struct file *file) +{ + struct video_device *vfl = get_vd(MINOR(inode->i_rdev)); + vfl->users--; + return 0; +} + +int +video_usercopy(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + int (*func)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg)) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + + // cmd = video_fix_command(cmd); + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + parg = (void *)arg; + break; + case _IOC_READ: + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (_IOC_DIR(cmd) & _IOC_WRITE) + if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd))) + goto out; + break; + } + + /* call driver */ + err = func(inode, file, cmd, parg); + if (err == -ENOIOCTLCMD) + err = -EINVAL; + if (err < 0) + goto out; + + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) + { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + if (mbuf) + kfree(mbuf); + return err; +} + + +static struct file_operations video_fops= +{ + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = video_open, + .release = video_release, +}; + +static struct miscdevice codec_dev = { + minor: CODEC_MINOR, + name : "codec", + fops : &video_fops +}; + +static struct miscdevice preview_dev = { + minor: PREVIEW_MINOR, + name : "preview", + fops : &video_fops +}; + + +/** + * video_register_device - register video4linux devices + * @vfd: video device structure we want to register + * @type: type of device to register + * @nr: minor number + * + * Zero is returned on success. + * type : ignored. + * nr : + * 0 Codec index + * 1 Preview index + */ +int video_register_device(struct video_device *vfd, int type, int nr) +{ + int ret=0; + + /* pick a minor number */ + down(&videodev_lock); + set_vd (vfd, nr); + vfd->minor=nr; + up(&videodev_lock); + + switch (vfd->minor) { + case CODEC_MINOR: + ret = misc_register(&codec_dev); + if (ret) { + printk(KERN_ERR + "can't misc_register : codec on minor=%d\n", CODEC_MINOR); + panic(" Give me misc codec \n"); + } + break; + case PREVIEW_MINOR: + ret = misc_register(&preview_dev); + if (ret) { + printk(KERN_ERR + "can't misc_register (preview) on minor=%d\n", PREVIEW_MINOR); + panic(" Give me misc codec \n"); + } + break; + } + +#if 0 /* needed until all drivers are fixed */ + if (!vfd->release) + printk(KERN_WARNING "videodev: \"%s\" has no release callback. " + "Please fix your driver for proper sysfs support, see " + "http://lwn.net/Articles/36850/\n", vfd->name); +#endif + return 0; +} + +/** + * video_unregister_device - unregister a video4linux device + * @vfd: the device to unregister + * + * This unregisters the passed device and deassigns the minor + * number. Future open calls will be met with errors. + */ + +void video_unregister_device(struct video_device *vfd) +{ + down(&videodev_lock); + + if(get_vd(vfd->minor)!=vfd) + panic("videodev: bad unregister"); + + if (vfd->minor== CODEC_MINOR) + misc_deregister(&codec_dev); + else + misc_deregister(&preview_dev); + set_vd (NULL, vfd->minor); + up(&videodev_lock); +} + + +/* + * Initialise video for linux + */ + +static int __init videodev_init(void) +{ +// printk(KERN_INFO "FIMC2.0 Built:"__DATE__" "__TIME__"\n%s\n",fimc_version); + return 0; +} + +static void __exit videodev_exit(void) +{ +} + +module_init(videodev_init) +module_exit(videodev_exit) + +EXPORT_SYMBOL(video_register_device); +EXPORT_SYMBOL(fimc_version); +EXPORT_SYMBOL(video_unregister_device); +EXPORT_SYMBOL(video_usercopy); +EXPORT_SYMBOL(video_exclusive_open); +EXPORT_SYMBOL(video_exclusive_release); + + +MODULE_AUTHOR("SW.LEE <hitchcar@sec.samsung.com>"); +MODULE_DESCRIPTION("VideoDev For FIMC2.0 MISC Drivers"); +MODULE_LICENSE("GPL"); + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/videodev.h b/arch/arm/mach-s3c2440/camera/videodev.h new file mode 100644 index 00000000000..f12db437a69 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/videodev.h @@ -0,0 +1,110 @@ +#ifndef __LINUX_S3C_VIDEODEV_H +#define __LINUX_S3C_VIDEODEV_H + +#include <linux/types.h> +#include <linux/version.h> +#include "videodev2.h" + + +struct video_device +{ + /* device info */ + // struct device *dev; + char name[32]; + int type; /* v4l1 */ + int type2; /* v4l2 */ + int hardware; + int minor; + + /* device ops + callbacks */ + struct file_operations *fops; + void (*release)(struct video_device *vfd); + + +#if 1 /* to be removed in 2.7.x */ + /* obsolete -- fops->owner is used instead */ + struct module *owner; + /* dev->driver_data will be used instead some day. + * Use the video_{get|set}_drvdata() helper functions, + * so the switch over will be transparent for you. + * Or use {pci|usb}_{get|set}_drvdata() directly. */ + void *priv; +#endif + + /* for videodev.c intenal usage -- please don't touch */ + int users; /* video_exclusive_{open|close} ... */ + struct semaphore lock; /* ... helper function uses these */ + char devfs_name[64]; /* devfs */ + // struct class_device class_dev; /* sysfs */ +}; + +#define VIDEO_MAJOR 81 + +#define VFL_TYPE_GRABBER 0 + + +extern int video_register_device(struct video_device *, int type, int nr); +extern void video_unregister_device(struct video_device *); +extern struct video_device* video_devdata(struct file*); + + + +struct video_picture +{ + __u16 brightness; + __u16 hue; + __u16 colour; + __u16 contrast; + __u16 whiteness; /* Black and white only */ + __u16 depth; /* Capture depth */ + __u16 palette; /* Palette in use */ +#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ +#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ +#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ +#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ +#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ +#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ +#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ +#define VIDEO_PALETTE_YUYV 8 +#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ +#define VIDEO_PALETTE_YUV420 10 +#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ +#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ +#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ +#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ +#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ +#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ +#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ +#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ +}; + +extern int video_exclusive_open(struct inode *inode, struct file *file); +extern int video_exclusive_release(struct inode *inode, struct file *file); +extern int video_usercopy(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + int (*func)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg)); + + + + +#define VID_TYPE_CAPTURE 1 /* Can capture */ +#define VID_TYPE_CLIPPING 32 /* Can clip */ +#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ +#define VID_TYPE_SCALES 128 /* Scalable */ +#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ + + + +#define VID_HARDWARE_SAMSUNG_FIMC 255 + + + +#endif + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/arch/arm/mach-s3c2440/camera/videodev2.h b/arch/arm/mach-s3c2440/camera/videodev2.h new file mode 100644 index 00000000000..1bfc45a4a43 --- /dev/null +++ b/arch/arm/mach-s3c2440/camera/videodev2.h @@ -0,0 +1,938 @@ +#ifndef __LINUX_VIDEODEV2_H +#define __LINUX_VIDEODEV2_H +/* + * Video for Linux Two + * + * Header file for v4l or V4L2 drivers and applications, for + * Linux kernels 2.2.x or 2.4.x. + * + * See http://bytesex.org/v4l/ for API specs and other + * v4l2 documentation. + * + * Author: Bill Dirks <bdirks@pacbell.net> + * Justin Schoeman + * et al. + */ +#ifdef __KERNEL__ +#include <linux/time.h> /* need struct timeval */ +#endif + +/* + * M I S C E L L A N E O U S + */ + +/* Four-character-code (FOURCC) */ +#define v4l2_fourcc(a,b,c,d)\ + (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) + +/* + * E N U M S + */ +enum v4l2_field { + V4L2_FIELD_ANY = 0, /* driver can choose from none, + top, bottom, interlaced + depending on whatever it thinks + is approximate ... */ + V4L2_FIELD_NONE = 1, /* this device has no fields ... */ + V4L2_FIELD_TOP = 2, /* top field only */ + V4L2_FIELD_BOTTOM = 3, /* bottom field only */ + V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ + V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one + buffer, top-bottom order */ + V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ + V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into + separate buffers */ +}; +#define V4L2_FIELD_HAS_TOP(field) \ + ((field) == V4L2_FIELD_TOP ||\ + (field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_BOTTOM(field) \ + ((field) == V4L2_FIELD_BOTTOM ||\ + (field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_BOTH(field) \ + ((field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) + +enum v4l2_buf_type { + V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, + V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, + V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, + V4L2_BUF_TYPE_VBI_CAPTURE = 4, + V4L2_BUF_TYPE_VBI_OUTPUT = 5, + V4L2_BUF_TYPE_PRIVATE = 0x80, +}; + +enum v4l2_ctrl_type { + V4L2_CTRL_TYPE_INTEGER = 1, + V4L2_CTRL_TYPE_BOOLEAN = 2, + V4L2_CTRL_TYPE_MENU = 3, + V4L2_CTRL_TYPE_BUTTON = 4, +}; + +enum v4l2_tuner_type { + V4L2_TUNER_RADIO = 1, + V4L2_TUNER_ANALOG_TV = 2, +}; + +enum v4l2_memory { + V4L2_MEMORY_MMAP = 1, + V4L2_MEMORY_USERPTR = 2, + V4L2_MEMORY_OVERLAY = 3, +}; + +/* see also http://vektor.theorem.ca/graphics/ycbcr/ */ +enum v4l2_colorspace { + /* ITU-R 601 -- broadcast NTSC/PAL */ + V4L2_COLORSPACE_SMPTE170M = 1, + + /* 1125-Line (US) HDTV */ + V4L2_COLORSPACE_SMPTE240M = 2, + + /* HD and modern captures. */ + V4L2_COLORSPACE_REC709 = 3, + + /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */ + V4L2_COLORSPACE_BT878 = 4, + + /* These should be useful. Assume 601 extents. */ + V4L2_COLORSPACE_470_SYSTEM_M = 5, + V4L2_COLORSPACE_470_SYSTEM_BG = 6, + + /* I know there will be cameras that send this. So, this is + * unspecified chromaticities and full 0-255 on each of the + * Y'CbCr components + */ + V4L2_COLORSPACE_JPEG = 7, + + /* For RGB colourspaces, this is probably a good start. */ + V4L2_COLORSPACE_SRGB = 8, +}; + +enum v4l2_priority { + V4L2_PRIORITY_UNSET = 0, /* not initialized */ + V4L2_PRIORITY_BACKGROUND = 1, + V4L2_PRIORITY_INTERACTIVE = 2, + V4L2_PRIORITY_RECORD = 3, + V4L2_PRIORITY_DEFAULT = V4L2_PRIORITY_INTERACTIVE, +}; + +struct v4l2_rect { + __s32 left; + __s32 top; + __s32 width; + __s32 height; +}; + +struct v4l2_fract { + __u32 numerator; + __u32 denominator; +}; + +/* + * D R I V E R C A P A B I L I T I E S + */ +struct v4l2_capability +{ + __u8 driver[16]; /* i.e. "bttv" */ + __u8 card[32]; /* i.e. "Hauppauge WinTV" */ + __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ + __u32 version; /* should use KERNEL_VERSION() */ + __u32 capabilities; /* Device capabilities */ + __u32 reserved[4]; +}; + +/* Values for 'capabilities' field */ +#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ +#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ +#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ +#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a VBI capture device */ +#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */ +#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ + +#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ +#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ +#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ + +#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ +#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ +#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ + +/* + * V I D E O I M A G E F O R M A T + */ + +struct v4l2_pix_format +{ + __u32 width; + __u32 height; + __u32 pixelformat; + enum v4l2_field field; + __u32 bytesperline; /* for padding, zero if unused */ + __u32 sizeimage; + enum v4l2_colorspace colorspace; + __u32 priv; /* private data, depends on pixelformat */ +}; + +/* Pixel format FOURCC depth Description */ +#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ +#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ +#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ +#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */ +#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */ +#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */ +#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ +#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ +#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ +#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ +#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ +#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ +#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ + +/* two planes -- one Y, one Cr + Cb interleaved */ +#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */ + +/* The following formats are not defined in the V4L2 specification */ +#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */ +#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */ +#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ + +/* compressed formats */ +#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */ +#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */ +#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */ +#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */ + +/* Vendor-specific formats */ +#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */ + +/* + * F O R M A T E N U M E R A T I O N + */ +struct v4l2_fmtdesc +{ + __u32 index; /* Format number */ + enum v4l2_buf_type type; /* buffer type */ + __u32 flags; + __u8 description[32]; /* Description string */ + __u32 pixelformat; /* Format fourcc */ + __u32 reserved[4]; +}; + +#define V4L2_FMT_FLAG_COMPRESSED 0x0001 + + +/* + * T I M E C O D E + */ +struct v4l2_timecode +{ + __u32 type; + __u32 flags; + __u8 frames; + __u8 seconds; + __u8 minutes; + __u8 hours; + __u8 userbits[4]; +}; + +/* Type */ +#define V4L2_TC_TYPE_24FPS 1 +#define V4L2_TC_TYPE_25FPS 2 +#define V4L2_TC_TYPE_30FPS 3 +#define V4L2_TC_TYPE_50FPS 4 +#define V4L2_TC_TYPE_60FPS 5 + +/* Flags */ +#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ +#define V4L2_TC_FLAG_COLORFRAME 0x0002 +#define V4L2_TC_USERBITS_field 0x000C +#define V4L2_TC_USERBITS_USERDEFINED 0x0000 +#define V4L2_TC_USERBITS_8BITCHARS 0x0008 +/* The above is based on SMPTE timecodes */ + + +/* + * C O M P R E S S I O N P A R A M E T E R S + */ +#if 0 +/* ### generic compression settings don't work, there is too much + * ### codec-specific stuff. Maybe reuse that for MPEG codec settings + * ### later ... */ +struct v4l2_compression +{ + __u32 quality; + __u32 keyframerate; + __u32 pframerate; + __u32 reserved[5]; + +/* what we'll need for MPEG, extracted from some postings on + the v4l list (Gert Vervoort, PlasmaJohn). + +system stream: + - type: elementary stream(ES), packatised elementary stream(s) (PES) + program stream(PS), transport stream(TS) + - system bitrate + - PS packet size (DVD: 2048 bytes, VCD: 2324 bytes) + - TS video PID + - TS audio PID + - TS PCR PID + - TS system information tables (PAT, PMT, CAT, NIT and SIT) + - (MPEG-1 systems stream vs. MPEG-2 program stream (TS not supported + by MPEG-1 systems) + +audio: + - type: MPEG (+Layer I,II,III), AC-3, LPCM + - bitrate + - sampling frequency (DVD: 48 Khz, VCD: 44.1 KHz, 32 kHz) + - Trick Modes? (ff, rew) + - Copyright + - Inverse Telecine + +video: + - picturesize (SIF, 1/2 D1, 2/3 D1, D1) and PAL/NTSC norm can be set + through excisting V4L2 controls + - noise reduction, parameters encoder specific? + - MPEG video version: MPEG-1, MPEG-2 + - GOP (Group Of Pictures) definition: + - N: number of frames per GOP + - M: distance between reference (I,P) frames + - open/closed GOP + - quantiser matrix: inter Q matrix (64 bytes) and intra Q matrix (64 bytes) + - quantiser scale: linear or logarithmic + - scanning: alternate or zigzag + - bitrate mode: CBR (constant bitrate) or VBR (variable bitrate). + - target video bitrate for CBR + - target video bitrate for VBR + - maximum video bitrate for VBR - min. quantiser value for VBR + - max. quantiser value for VBR + - adaptive quantisation value + - return the number of bytes per GOP or bitrate for bitrate monitoring + +*/ +}; +#endif + +struct v4l2_jpegcompression +{ + int quality; + + int APPn; /* Number of APP segment to be written, + * must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + __u32 jpeg_markers; /* Which markers should go into the JPEG + * output. Unless you exactly know what + * you do, leave them untouched. + * Inluding less markers will make the + * resulting code smaller, but there will + * be fewer aplications which can read it. + * The presence of the APP and COM marker + * is influenced by APP_len and COM_len + * ONLY, not by this property! */ + +#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will + * allways use APP0 */ +}; + + +/* + * M E M O R Y - M A P P I N G B U F F E R S + */ +struct v4l2_requestbuffers +{ + __u32 count; + enum v4l2_buf_type type; + enum v4l2_memory memory; + __u32 reserved[2]; +}; + +struct v4l2_buffer +{ + __u32 index; + enum v4l2_buf_type type; + __u32 bytesused; + __u32 flags; + enum v4l2_field field; + struct timeval timestamp; + struct v4l2_timecode timecode; + __u32 sequence; + + /* memory location */ + enum v4l2_memory memory; + union { + __u32 offset; + unsigned long userptr; + } m; + __u32 length; + + __u32 reserved[2]; +}; + +/* Flags for 'flags' field */ +#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ +#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ +#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ +#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ +#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ +#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ +#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ + +/* + * O V E R L A Y P R E V I E W + */ +struct v4l2_framebuffer +{ + __u32 capability; + __u32 flags; +/* FIXME: in theory we should pass something like PCI device + memory + * region + offset instead of some physical address */ + void* base; + struct v4l2_pix_format fmt; +}; +/* Flags for the 'capability' field. Read only */ +#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 +#define V4L2_FBUF_CAP_CHROMAKEY 0x0002 +#define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 +#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 +/* Flags for the 'flags' field. */ +#define V4L2_FBUF_FLAG_PRIMARY 0x0001 +#define V4L2_FBUF_FLAG_OVERLAY 0x0002 +#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 + +struct v4l2_clip +{ + struct v4l2_rect c; + struct v4l2_clip *next; +}; + +struct v4l2_window +{ + struct v4l2_rect w; + enum v4l2_field field; + __u32 chromakey; + struct v4l2_clip *clips; + __u32 clipcount; + void *bitmap; +}; + + +/* + * C A P T U R E P A R A M E T E R S + */ +struct v4l2_captureparm +{ + __u32 capability; /* Supported modes */ + __u32 capturemode; /* Current mode */ + struct v4l2_fract timeperframe; /* Time per frame in .1us units */ + __u32 extendedmode; /* Driver-specific extensions */ + __u32 readbuffers; /* # of buffers for read */ + __u32 reserved[4]; +}; +/* Flags for 'capability' and 'capturemode' fields */ +#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ +#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ + +struct v4l2_outputparm +{ + __u32 capability; /* Supported modes */ + __u32 outputmode; /* Current mode */ + struct v4l2_fract timeperframe; /* Time per frame in seconds */ + __u32 extendedmode; /* Driver-specific extensions */ + __u32 writebuffers; /* # of buffers for write */ + __u32 reserved[4]; +}; + +/* + * I N P U T I M A G E C R O P P I N G + */ + +struct v4l2_cropcap { + enum v4l2_buf_type type; + struct v4l2_rect bounds; + struct v4l2_rect defrect; + struct v4l2_fract pixelaspect; +}; + +struct v4l2_crop { + enum v4l2_buf_type type; + struct v4l2_rect c; +}; + +/* + * A N A L O G V I D E O S T A N D A R D + */ + +typedef __u64 v4l2_std_id; + +/* one bit for each */ +#define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) +#define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) +#define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004) +#define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008) +#define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010) +#define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020) +#define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040) +#define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080) + +#define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100) +#define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200) +#define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) +#define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) + +#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) +#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) + +#define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) +#define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) +#define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000) +#define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000) +#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000) +#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000) +#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) + +/* ATSC/HDTV */ +#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) +#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) + +/* some common needed stuff */ +#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ + V4L2_STD_PAL_B1 |\ + V4L2_STD_PAL_G) +#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ + V4L2_STD_PAL_D1 |\ + V4L2_STD_PAL_K) +#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ + V4L2_STD_PAL_DK |\ + V4L2_STD_PAL_H |\ + V4L2_STD_PAL_I) +#define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ + V4L2_STD_NTSC_M_JP) +#define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ + V4L2_STD_SECAM_D |\ + V4L2_STD_SECAM_G |\ + V4L2_STD_SECAM_H |\ + V4L2_STD_SECAM_K |\ + V4L2_STD_SECAM_K1 |\ + V4L2_STD_SECAM_L) + +#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ + V4L2_STD_PAL_60 |\ + V4L2_STD_NTSC) +#define V4L2_STD_625_50 (V4L2_STD_PAL |\ + V4L2_STD_PAL_N |\ + V4L2_STD_PAL_Nc |\ + V4L2_STD_SECAM) + +#define V4L2_STD_UNKNOWN 0 +#define V4L2_STD_ALL (V4L2_STD_525_60 |\ + V4L2_STD_625_50) + +struct v4l2_standard +{ + __u32 index; + v4l2_std_id id; + __u8 name[24]; + struct v4l2_fract frameperiod; /* Frames, not fields */ + __u32 framelines; + __u32 reserved[4]; +}; + + +/* + * V I D E O I N P U T S + */ +struct v4l2_input +{ + __u32 index; /* Which input */ + __u8 name[32]; /* Label */ + __u32 type; /* Type of input */ + __u32 audioset; /* Associated audios (bitfield) */ + __u32 tuner; /* Associated tuner */ + v4l2_std_id std; + __u32 status; + __u32 reserved[4]; +}; +/* Values for the 'type' field */ +#define V4L2_INPUT_TYPE_TUNER 1 +#define V4L2_INPUT_TYPE_CAMERA 2 + +/* field 'status' - general */ +#define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */ +#define V4L2_IN_ST_NO_SIGNAL 0x00000002 +#define V4L2_IN_ST_NO_COLOR 0x00000004 + +/* field 'status' - analog */ +#define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */ +#define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */ + +/* field 'status' - digital */ +#define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */ +#define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */ +#define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */ + +/* field 'status' - VCR and set-top box */ +#define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */ +#define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ +#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ + +/* + * V I D E O O U T P U T S + */ +struct v4l2_output +{ + __u32 index; /* Which output */ + __u8 name[32]; /* Label */ + __u32 type; /* Type of output */ + __u32 audioset; /* Associated audios (bitfield) */ + __u32 modulator; /* Associated modulator */ + v4l2_std_id std; + __u32 reserved[4]; +}; +/* Values for the 'type' field */ +#define V4L2_OUTPUT_TYPE_MODULATOR 1 +#define V4L2_OUTPUT_TYPE_ANALOG 2 +#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 + +/* + * C O N T R O L S + */ +struct v4l2_control +{ + __u32 id; + __s32 value; +}; + +/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ +struct v4l2_queryctrl +{ + __u32 id; + enum v4l2_ctrl_type type; + __u8 name[32]; /* Whatever */ + __s32 minimum; /* Note signedness */ + __s32 maximum; + __s32 step; + __s32 default_value; + __u32 flags; + __u32 reserved[2]; +}; + +/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ +struct v4l2_querymenu +{ + __u32 id; + __u32 index; + __u8 name[32]; /* Whatever */ + __u32 reserved; +}; + +/* Control flags */ +#define V4L2_CTRL_FLAG_DISABLED 0x0001 +#define V4L2_CTRL_FLAG_GRABBED 0x0002 + +/* Control IDs defined by V4L2 */ +#define V4L2_CID_BASE 0x00980900 +/* IDs reserved for driver specific controls */ +#define V4L2_CID_PRIVATE_BASE 0x08000000 + +#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) +#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) +#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) +#define V4L2_CID_HUE (V4L2_CID_BASE+3) +#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) +#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) +#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) +#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) +#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) +#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) +#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) +#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) +#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) +#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) +#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) +#define V4L2_CID_GAMMA (V4L2_CID_BASE+16) +#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */ +#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) +#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) +#define V4L2_CID_GAIN (V4L2_CID_BASE+19) +#define V4L2_CID_HFLIP (V4L2_CID_BASE+20) +#define V4L2_CID_VFLIP (V4L2_CID_BASE+21) +#define V4L2_CID_HCENTER (V4L2_CID_BASE+22) +#define V4L2_CID_VCENTER (V4L2_CID_BASE+23) +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */ + +/* + * T U N I N G + */ +struct v4l2_tuner +{ + __u32 index; + __u8 name[32]; + enum v4l2_tuner_type type; + __u32 capability; + __u32 rangelow; + __u32 rangehigh; + __u32 rxsubchans; + __u32 audmode; + __s32 signal; + __s32 afc; + __u32 reserved[4]; +}; + +struct v4l2_modulator +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 rangelow; + __u32 rangehigh; + __u32 txsubchans; + __u32 reserved[4]; +}; + +/* Flags for the 'capability' field */ +#define V4L2_TUNER_CAP_LOW 0x0001 +#define V4L2_TUNER_CAP_NORM 0x0002 +#define V4L2_TUNER_CAP_STEREO 0x0010 +#define V4L2_TUNER_CAP_LANG2 0x0020 +#define V4L2_TUNER_CAP_SAP 0x0020 +#define V4L2_TUNER_CAP_LANG1 0x0040 + +/* Flags for the 'rxsubchans' field */ +#define V4L2_TUNER_SUB_MONO 0x0001 +#define V4L2_TUNER_SUB_STEREO 0x0002 +#define V4L2_TUNER_SUB_LANG2 0x0004 +#define V4L2_TUNER_SUB_SAP 0x0004 +#define V4L2_TUNER_SUB_LANG1 0x0008 + +/* Values for the 'audmode' field */ +#define V4L2_TUNER_MODE_MONO 0x0000 +#define V4L2_TUNER_MODE_STEREO 0x0001 +#define V4L2_TUNER_MODE_LANG2 0x0002 +#define V4L2_TUNER_MODE_SAP 0x0002 +#define V4L2_TUNER_MODE_LANG1 0x0003 + +struct v4l2_frequency +{ + __u32 tuner; + enum v4l2_tuner_type type; + __u32 frequency; + __u32 reserved[8]; +}; + +/* + * A U D I O + */ +struct v4l2_audio +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 mode; + __u32 reserved[2]; +}; +/* Flags for the 'capability' field */ +#define V4L2_AUDCAP_STEREO 0x00001 +#define V4L2_AUDCAP_AVL 0x00002 + +/* Flags for the 'mode' field */ +#define V4L2_AUDMODE_AVL 0x00001 + +struct v4l2_audioout +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 mode; + __u32 reserved[2]; +}; + +/* + * D A T A S E R V I C E S ( V B I ) + * + * Data services API by Michael Schimek + */ + +struct v4l2_vbi_format +{ + __u32 sampling_rate; /* in 1 Hz */ + __u32 offset; + __u32 samples_per_line; + __u32 sample_format; /* V4L2_PIX_FMT_* */ + __s32 start[2]; + __u32 count[2]; + __u32 flags; /* V4L2_VBI_* */ + __u32 reserved[2]; /* must be zero */ +}; + +/* VBI flags */ +#define V4L2_VBI_UNSYNC (1<< 0) +#define V4L2_VBI_INTERLACED (1<< 1) + + +/* + * A G G R E G A T E S T R U C T U R E S + */ + +/* Stream data format + */ +struct v4l2_format +{ + enum v4l2_buf_type type; + union + { + struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE + struct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAY + struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE + __u8 raw_data[200]; // user-defined + } fmt; +}; + + +/* Stream type-dependent parameters + */ +struct v4l2_streamparm +{ + enum v4l2_buf_type type; + union + { + struct v4l2_captureparm capture; + struct v4l2_outputparm output; + __u8 raw_data[200]; /* user-defined */ + } parm; +}; + + + +/* + * I O C T L C O D E S F O R V I D E O D E V I C E S + * + */ +#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) +#define VIDIOC_RESERVED _IO ('V', 1) +#define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc) +#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) +#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) +#if 0 +#define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression) +#define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression) +#endif +#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) +#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) +#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) +#define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer) +#define VIDIOC_OVERLAY _IOW ('V', 14, int) +#define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer) +#define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer) +#define VIDIOC_STREAMON _IOW ('V', 18, int) +#define VIDIOC_STREAMOFF _IOW ('V', 19, int) +#define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm) +#define VIDIOC_S_PARM _IOWR ('V', 22, struct v4l2_streamparm) +#define VIDIOC_G_STD _IOR ('V', 23, v4l2_std_id) +#define VIDIOC_S_STD _IOW ('V', 24, v4l2_std_id) +#define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_standard) +#define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input) +#define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control) +#define VIDIOC_S_CTRL _IOWR ('V', 28, struct v4l2_control) +#define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner) +#define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner) +#define VIDIOC_G_AUDIO _IOR ('V', 33, struct v4l2_audio) +#define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio) +#define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl) +#define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu) +#define VIDIOC_G_INPUT _IOR ('V', 38, int) +#define VIDIOC_S_INPUT _IOWR ('V', 39, int) +#define VIDIOC_G_OUTPUT _IOR ('V', 46, int) +#define VIDIOC_S_OUTPUT _IOWR ('V', 47, int) +#define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output) +#define VIDIOC_G_AUDOUT _IOR ('V', 49, struct v4l2_audioout) +#define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout) +#define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator) +#define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator) +#define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency) +#define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency) +#define VIDIOC_CROPCAP _IOR ('V', 58, struct v4l2_cropcap) +#define VIDIOC_G_CROP _IOWR ('V', 59, struct v4l2_crop) +#define VIDIOC_S_CROP _IOW ('V', 60, struct v4l2_crop) +#define VIDIOC_G_JPEGCOMP _IOR ('V', 61, struct v4l2_jpegcompression) +#define VIDIOC_S_JPEGCOMP _IOW ('V', 62, struct v4l2_jpegcompression) +#define VIDIOC_QUERYSTD _IOR ('V', 63, v4l2_std_id) +#define VIDIOC_TRY_FMT _IOWR ('V', 64, struct v4l2_format) +#define VIDIOC_ENUMAUDIO _IOWR ('V', 65, struct v4l2_audio) +#define VIDIOC_ENUMAUDOUT _IOWR ('V', 66, struct v4l2_audioout) +#define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority) +#define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority) + +/* for compatibility, will go away some day */ +#define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int) +#define VIDIOC_S_PARM_OLD _IOW ('V', 22, struct v4l2_streamparm) +#define VIDIOC_S_CTRL_OLD _IOW ('V', 28, struct v4l2_control) +#define VIDIOC_G_AUDIO_OLD _IOWR ('V', 33, struct v4l2_audio) +#define VIDIOC_G_AUDOUT_OLD _IOWR ('V', 49, struct v4l2_audioout) + +#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ + + +#ifdef __KERNEL__ +/* + * + * V 4 L 2 D R I V E R H E L P E R A P I + * + * Some commonly needed functions for drivers (v4l2-common.o module) + */ +#include <linux/fs.h> + +/* Video standard functions */ +extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs); +extern int v4l2_video_std_construct(struct v4l2_standard *vs, + int id, char *name); + +/* prority handling */ +struct v4l2_prio_state { + atomic_t prios[4]; +}; +int v4l2_prio_init(struct v4l2_prio_state *global); +int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, + enum v4l2_priority new); +int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local); +int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local); +enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global); +int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local); + +/* names for fancy debug output */ +extern char *v4l2_field_names[]; +extern char *v4l2_type_names[]; +extern char *v4l2_ioctl_names[]; + +/* Compatibility layer interface -- v4l1-compat module */ +typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +int v4l_compat_translate_ioctl(struct inode *inode, struct file *file, + int cmd, void *arg, v4l2_kioctl driver_ioctl); + +#endif /* __KERNEL__ */ +#endif /* __LINUX_VIDEODEV2_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ |