📄 smdk2440_ov7620.c
字号:
#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/locks.h>#include <linux/delay.h>#include <linux/slab.h>#include "videodev.h"#include <asm/semaphore.h>#include <asm/hardware.h>#include <asm/arch/cpu_s3c2440.h>#include "s3c2440_camif.h"#include "smdk2440_ov7620.h"#define DEBUG_PRINTK 0#define DEBUG_PRINTK2 0#define OV7620_SCCB_ID 0x42 /* CS[2:0] = 000 */#define OV7620_MAX_CLK 24000000 #define OV7620_PRODUCT_ID 0x7FA2#define OV7620_SCCB_DELAY 100#define OV7620_SCCB_DELAY2 40# define SIO_C (GPIO_E14)# define SIO_D (GPIO_E15)# define MAKE_HIGH(_x) write_gpio_bit_set(_x)# define MAKE_LOW(_x) write_gpio_bit_clear(_x)# define BIT_READ(_x) read_gpio_bit(_x)# define CFG_READ(_x) set_gpio_ctrl(_x | GPIO_PULLUP_DIS | GPIO_MODE_IN)# define CFG_WRITE(_x) set_gpio_ctrl(_x | GPIO_PULLUP_DIS | GPIO_MODE_OUT)#if OV7620_SCCB_DELAY > 0# define WAIT_CYL udelay(OV7620_SCCB_DELAY)#else# define WAIT_CYL (void)(0)#endif#if OV7620_SCCB_DELAY2 > 0# define WAIT_STAB udelay(OV7620_SCCB_DELAY2)#else# define WAIT_STAB (void)(0)#endif#if DEBUG_PRINTK#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) do {} while (0) /* !!!! */#endif#if DEBUG_PRINTK2#define DPRINTK2(x...) printk(x)#else#define DPRINTK2(x...) do {} while (0) /* !!!! */#endif#define OV7620_MAX_WIDTH 640#define OV7620_MAX_HEIGHT 480static int ov7620_regs_mirror[OV7620_REGS];static DECLARE_MUTEX(bus_lock);static DECLARE_MUTEX(reg_lock);/* 2-wire SCCB */void inline ov7620_sccb_start(void){ MAKE_HIGH(SIO_C); MAKE_HIGH(SIO_D); WAIT_STAB; MAKE_LOW(SIO_D); WAIT_STAB; MAKE_LOW(SIO_C); WAIT_STAB;}/* 2-wire SCCB */void inline ov7620_sccb_end(void){ MAKE_LOW(SIO_D); WAIT_STAB; MAKE_HIGH(SIO_C); WAIT_STAB; MAKE_HIGH(SIO_D); WAIT_STAB;}void inline ov7620_sccb_write_bit(unsigned char bit){ if (bit) MAKE_HIGH(SIO_D); else MAKE_LOW(SIO_D); WAIT_STAB; MAKE_HIGH(SIO_C); WAIT_CYL; MAKE_LOW(SIO_C); WAIT_STAB;}int inline ov7620_sccb_read_bit(void){ int tmp = 0; MAKE_HIGH(SIO_C); WAIT_CYL; tmp = BIT_READ(SIO_D); MAKE_LOW(SIO_C); WAIT_STAB; return tmp;} void inline ov7620_sccb_writechar(unsigned char data){ int i = 0; /* data */ for (i = 0; i < 8; i++ ) { ov7620_sccb_write_bit(data & 0x80); data <<= 1; } /* 9th bit - Don't care */ ov7620_sccb_write_bit(1);}void inline ov7620_sccb_readchar(unsigned char *val){ int i; int tmp = 0; CFG_READ(SIO_D); for (i = 7; i >= 0; i--) tmp |= ov7620_sccb_read_bit() << i; CFG_WRITE(SIO_D); /* 9th bit - N.A. */ ov7620_sccb_write_bit(1); *val = tmp & 0xff;}/* 3-phase write */static void ov7620_sccb_sendbyte(unsigned char subaddr, unsigned char data){ down(&bus_lock); ov7620_sccb_start(); ov7620_sccb_writechar(OV7620_SCCB_ID); ov7620_sccb_writechar(subaddr); ov7620_sccb_writechar(data); ov7620_sccb_end(); mdelay(7); up(&bus_lock);}/* 2-phase read */static unsigned char ov7620_sccb_receivebyte(unsigned char subaddr){ unsigned char value; down(&bus_lock); /* 2-phase write */ ov7620_sccb_start(); ov7620_sccb_writechar(OV7620_SCCB_ID); ov7620_sccb_writechar(subaddr); ov7620_sccb_end(); /* 2-phase read */ ov7620_sccb_start(); ov7620_sccb_writechar(OV7620_SCCB_ID | 0x01); ov7620_sccb_readchar(&value); ov7620_sccb_end(); mdelay(7); up(&bus_lock); return value;}void inline ov7620_init(void){ CFG_WRITE(SIO_C); CFG_WRITE(SIO_D); mdelay(10);}void inline ov7620_deinit(void){ CFG_READ(SIO_C); CFG_READ(SIO_D);}void inline ov7620_init_config(void){ int i; down(®_lock); for (i = 0; i < OV7620_INIT_REGS; i++) { if (ov7620_reg[i].subaddr == CHIP_DELAY) mdelay(ov7620_reg[i].value); else ov7620_sccb_sendbyte(ov7620_reg[i].subaddr & 0xff , ov7620_reg[i].value & 0xff); } for (i = 0; i < OV7620_REGS; i++) { ov7620_regs_mirror[i] = ov7620_sccb_receivebyte(i); DPRINTK("[%02x] = 0x%02x\n", i, ov7620_regs_mirror[i]); } up(®_lock);}int inline check_ov7620(void){ int ret = 0; int ov7620_mid = 0; ov7620_mid = (ov7620_sccb_receivebyte(0x1c) << 8); ov7620_mid |= ov7620_sccb_receivebyte(0x1d); if (ov7620_mid != OV7620_PRODUCT_ID) { printk("Invalid manufacture ID (0x%04X). there is no OV7620(0x%04X)\n", ov7620_mid, OV7620_PRODUCT_ID); ret = -ENODEV; } else { printk("OV7620(0x%04X) detected.\n", ov7620_mid); } return ret;}void inline change_ov7620_reg_value(int subaddr, int value){ down(®_lock); ov7620_regs_mirror[subaddr] = value; ov7620_sccb_sendbyte(subaddr, value); up(®_lock);}void inline change_ov7620_reg_bit(int subaddr, int num, int value){ int tmp = 0; down(®_lock); tmp = ov7620_regs_mirror[subaddr]; tmp &= ~(1<<num); tmp |= (value<<num); ov7620_regs_mirror[subaddr] = tmp; ov7620_sccb_sendbyte(subaddr, tmp); up(®_lock);}static int ov7620_enc_brightness(int in, unsigned int *out){ DPRINTK("%s(): set to %d\n", __FUNCTION__, in); if (in == 128 ) { /* auto control */ change_ov7620_reg_value(0x06, in); change_ov7620_reg_bit(0x2d, 4, 1); } else { /* manual control */ change_ov7620_reg_bit(0x2d, 4, 0); change_ov7620_reg_value(0x06, in); } DPRINTK("[0x2d] = 0x%02x\n", ov7620_sccb_receivebyte(0x2d)); if (out) *out = in; return 0;}static int ov7620_enc_redbalance(int in, unsigned int *out){ DPRINTK("%s(): set to %d\n", __FUNCTION__, in); change_ov7620_reg_value(0x02, in & 0xff0000); // red gain if (out) *out = in; return 0;}static int ov7620_enc_bluebalance(int in, unsigned int *out){ DPRINTK("%s(): set to %d\n", __FUNCTION__, in); change_ov7620_reg_value(0x01, in & 0xff); // blue gain; if (out) *out = in; return 0;}static int ov7620_enc_autowhitebalance(int in, unsigned int *out){ DPRINTK("%s(): set to %d\n", __FUNCTION__, in); if (in) { /* auto control */ change_ov7620_reg_bit(0x12, 2, 1); } else { /* manual control */ change_ov7620_reg_bit(0x12, 2, 0); ov7620_enc_bluebalance(ov7620_regs_mirror[0x01], NULL); ov7620_enc_redbalance(ov7620_regs_mirror[0x02], NULL); } if (out) *out = in; return 0;}static int ov7620_enc_exposure(int in, unsigned int *out){ DPRINTK("%s(): set to %d\n", __FUNCTION__, in); if (in == 128) { /* auto control */ change_ov7620_reg_bit(0x13, 0, 1); change_ov7620_reg_bit(0x29, 7, 0); } else { /* manual control */ change_ov7620_reg_bit(0x13, 0, 1); change_ov7620_reg_bit(0x29, 7, 1); change_ov7620_reg_bit(0x13, 0, 0); change_ov7620_reg_value(0x10, in); } if (out) *out = in; return -1;}static int ov7620_configure(void){ return -1;}static void ov7620_grab(void){ MOD_INC_USE_COUNT;}static void ov7620_ungrab(void){ MOD_DEC_USE_COUNT;}/* default config */static struct s3c2440_cam_hwcfg ov7620_cfg = { .width = OV7620_MAX_WIDTH, .height = OV7620_MAX_HEIGHT, .pixelfmt = V4L2_PIX_FMT_YUV420, .ctrl = CTRL_SWAP_YUYV | CTRL_IMGFMT_ITU601,};static struct s3c2440_cam_hw ov7620 = { .max_width = OV7620_MAX_WIDTH, .max_height = OV7620_MAX_HEIGHT, .cfg = &ov7620_cfg, .encode_brightness = ov7620_enc_brightness, .encode_redbalance = ov7620_enc_redbalance, .encode_bluebalance = ov7620_enc_bluebalance, .encode_autowhitebalance = ov7620_enc_autowhitebalance, .encode_exposure = ov7620_enc_exposure, .configure = ov7620_configure, .grab = ov7620_grab, .ungrab = ov7620_ungrab,};int __init ov7620_initializer(void){ int ret = 0; ov7620_init(); if ((ret = check_ov7620())) goto err_not_det; ov7620_init_config(); snprintf(&ov7620.name[0], 7, "%s", "OV7620"); ret = s3c2440_camif_register_camhw(&ov7620);err_not_det: if (ret) ov7620_deinit(); /* CPU : FIXME */ flush_scheduled_tasks(); return ret;}void __exit ov7620_deinitializer(void){ ov7620_deinit(); s3c2440_camif_unregister_camhw(&ov7620);}MODULE_LICENSE("GPL");module_init(ov7620_initializer);module_exit(ov7620_deinitializer);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -