diff options
Diffstat (limited to 'drivers/media/video/wmt_v4l2/sensors/gc2035/gc2035-shutter.c')
-rwxr-xr-x | drivers/media/video/wmt_v4l2/sensors/gc2035/gc2035-shutter.c | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/drivers/media/video/wmt_v4l2/sensors/gc2035/gc2035-shutter.c b/drivers/media/video/wmt_v4l2/sensors/gc2035/gc2035-shutter.c new file mode 100755 index 00000000..c3c11719 --- /dev/null +++ b/drivers/media/video/wmt_v4l2/sensors/gc2035/gc2035-shutter.c @@ -0,0 +1,441 @@ + +#include "../cmos-subdev.h" +#include "../../wmt-vid.h" +#include "gc2035.h" + +#define sensor_write_array(sd, arr, sz) \ + cmos_init_8bit_addr(arr, sz, (sd)->i2c_addr) + +#define sensor_read(sd, reg) \ + wmt_vid_i2c_read(sd->i2c_addr, reg) + +#define sensor_write(sd, reg, val) \ + wmt_vid_i2c_write(sd->i2c_addr, reg, val) + +struct cmos_win_size { + char *name; + int width; + int height; + uint8_t *regs; + size_t size; +}; + +#define CMOS_WIN_SIZE(n, w, h, r) \ + {.name = n, .width = w , .height = h, .regs = r, .size = ARRAY_SIZE(r) } + +#define FILP_REG_INIT_VALUE 0x14 +#define DELAY_INTERVAL 50 +#define RETRY_TIMES 10 +static uint32_t Preview_Shutter = 0; +static uint32_t Capture_Shutter = 0; + +static const struct cmos_win_size cmos_supported_win_sizes[] = { + //CMOS_WIN_SIZE("QVGA", 320, 240, gc2035_320_240_regs), + CMOS_WIN_SIZE("VGA", 640, 480, gc2035_640_480_regs), + //CMOS_WIN_SIZE("SVGA", 800, 600, gc2035_800_600_regs), + //CMOS_WIN_SIZE("720p", 1280, 720, gc2035_1280_720_regs), + CMOS_WIN_SIZE("UXGA", 1600, 1200, gc2035_1600_1200_regs), +}; + +static const struct cmos_win_size *cmos_select_win(u32 *width, u32 *height) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cmos_supported_win_sizes); i++) { + if (cmos_supported_win_sizes[i].width == *width && + cmos_supported_win_sizes[i].height == *height) { + *width = cmos_supported_win_sizes[i].width; + *height = cmos_supported_win_sizes[i].height; + return &cmos_supported_win_sizes[i]; + } + } + return NULL; +} + +static int sensor_s_wb(struct cmos_subdev *sd, enum v4l2_wb_mode value) +{ + uint8_t *regs; + size_t size; + + switch (value) { + case WHITE_BALANCE_AUTO: + regs = gc2035_wb_auto; + size = ARRAY_SIZE(gc2035_wb_auto); + break; + case WHITE_BALANCE_INCANDESCENCE: + regs = gc2035_wb_incandescent; + size = ARRAY_SIZE(gc2035_wb_incandescent); + break; + case WHITE_BALANCE_DAYLIGHT: + regs = gc2035_wb_daylight; + size = ARRAY_SIZE(gc2035_wb_daylight); + break; + case WHITE_BALANCE_CLOUDY: + regs = gc2035_wb_cloudy; + size = ARRAY_SIZE(gc2035_wb_cloudy); + break; + case WHITE_BALANCE_FLUORESCENT: + regs = gc2035_wb_fluorescent; + size = ARRAY_SIZE(gc2035_wb_fluorescent); + break; + default: + return -EINVAL; + } + + sensor_write_array(sd, regs, size); + return 0; +} + +static int sensor_s_scenemode(struct cmos_subdev *sd, enum v4l2_scene_mode value) +{ + uint8_t *regs; + size_t size; + + switch (value) { + case SCENE_MODE_AUTO: + regs = gc2035_scene_mode_auto; + size = ARRAY_SIZE(gc2035_scene_mode_auto); + break; + case SCENE_MODE_NIGHTSHOT: + regs = gc2035_scene_mode_night; + size = ARRAY_SIZE(gc2035_scene_mode_night); + break; + default: + return -EINVAL; + } + + sensor_write_array(sd, regs, size); + return 0; +} + +static int sensor_s_exposure(struct cmos_subdev *sd, enum v4l2_exposure_mode value) +{ + uint8_t *regs; + size_t size; + + switch (value) { + case -2: + regs = gc2035_exposure_neg6; + size = ARRAY_SIZE(gc2035_exposure_neg6); + break; + case -1: + regs = gc2035_exposure_neg3; + size = ARRAY_SIZE(gc2035_exposure_neg3); + break; + case 0: + regs = gc2035_exposure_zero; + size = ARRAY_SIZE(gc2035_exposure_zero); + break; + case 1: + regs = gc2035_exposure_pos3; + size = ARRAY_SIZE(gc2035_exposure_pos3); + break; + case 2: + regs = gc2035_exposure_pos6; + size = ARRAY_SIZE(gc2035_exposure_pos6); + break; + default: + return -EINVAL; + } + + sensor_write_array(sd, regs, size); + return 0; +} + +static int sensor_s_antibanding(struct cmos_subdev *sd, int value) +{ + uint8_t *regs; + size_t size; + + switch (value) { + case 0: + regs = gc2035_antibanding_auto; + size = ARRAY_SIZE(gc2035_antibanding_auto); + break; + case 1: + regs = gc2035_antibanding_50hz; + size = ARRAY_SIZE(gc2035_antibanding_50hz); + break; + case 2: + regs = gc2035_antibanding_60hz; + size = ARRAY_SIZE(gc2035_antibanding_60hz); + break; + case 3: + regs = gc2035_antibanding_off; + size = ARRAY_SIZE(gc2035_antibanding_off); + break; + default: + return -EINVAL; + } + + sensor_write_array(sd, regs, size); + + return 0; +} + +static int sensor_s_hflip(struct cmos_subdev *sd, int value) +{ + uint8_t data,tmp=0 ; + uint8_t retry_times=0; + + sensor_write(sd, 0xfe, 0x00); // set page0 + data=sensor_read(sd, 0x17); + + switch (value) { + case 0: + data &= ~0x01; + break; + case 1: + data |= 0x01; + break; + default: + return -EINVAL; + } + + tmp=data | FILP_REG_INIT_VALUE; + for(retry_times=0;retry_times<RETRY_TIMES;retry_times++){ + sensor_write(sd, 0x17, tmp); + msleep(50+retry_times*DELAY_INTERVAL); + if(sensor_read(sd, 0x17)==tmp) + break; + } + + return 0; +} + +static int sensor_s_vflip(struct cmos_subdev *sd, int value) +{ + uint8_t data,tmp=0; + uint8_t retry_times=0; + + sensor_write(sd, 0xfe, 0x00); // set page0 + data=sensor_read(sd, 0x17); + + switch (value) { + case 0: + data &= ~0x02; + break; + case 1: + data |= 0x02; + break; + default: + return -EINVAL; + } + + tmp=data | FILP_REG_INIT_VALUE; + for(retry_times=0;retry_times<RETRY_TIMES;retry_times++){ + sensor_write(sd, 0x17, tmp); + msleep(50+retry_times*DELAY_INTERVAL); + if(sensor_read(sd, 0x17)==tmp) + break; + } + return 0; +} + +static int sensor_queryctrl(struct cmos_subdev *sd, struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_VFLIP: + case V4L2_CID_HFLIP: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); + case V4L2_CID_CAMERA_SCENE_MODE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); + case V4L2_CID_DO_WHITE_BALANCE: + return v4l2_ctrl_query_fill(qc, 0, 3, 1, 0); + case V4L2_CID_EXPOSURE: + return v4l2_ctrl_query_fill(qc, -2, 2, 1, 0); + } + return -EINVAL; +} + +static int sensor_s_ctrl(struct cmos_subdev *sd, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_CAMERA_SCENE_MODE: + return sensor_s_scenemode(sd, ctrl->value); + case V4L2_CID_DO_WHITE_BALANCE: + return sensor_s_wb(sd, ctrl->value); + case V4L2_CID_EXPOSURE: + return sensor_s_exposure(sd, ctrl->value); + case V4L2_CID_HFLIP: + return sensor_s_hflip(sd, ctrl->value); + case V4L2_CID_VFLIP: + return sensor_s_vflip(sd, ctrl->value); + case V4L2_CID_CAMERA_ANTI_BANDING: + return sensor_s_antibanding(sd, ctrl->value); + default: + case WMT_V4L2_CID_CAMERA_ANTIBANDING: + return -EINVAL; + } + return -EINVAL; +} + +static int sensor_g_mbus_fmt(struct cmos_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + return -EINVAL; +} + +uint32_t sensor_read_shutter(struct cmos_subdev *sd) +{ + return (sensor_read(sd,0x03) << 8)|sensor_read(sd,0x04) ; +} + + +static void sensor_write_shutter(struct cmos_subdev *sd,uint32_t shutter) +{ + + if(shutter < 1) + return; + + sensor_write(sd,0x03, (shutter >> 8) & 0xff); + sensor_write(sd,0x04, shutter & 0xff); +} + + +static void sensor_set_ae_mode(struct cmos_subdev *sd,bool AE_enable) +{ + sensor_write(sd,0xfe, 0x00); + if (AE_enable == true) + { + // turn on AEC/AGC + sensor_write(sd,0xb6, 0x03); + } + else + { + // turn off AEC/AGC + sensor_write(sd,0xb6, 0x00); + } +} + + +static int sensor_s_mbus_fmt(struct cmos_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + const struct cmos_win_size *win; + uint32_t shutter = 0; + + printk(KERN_DEBUG "%s, s_mbus_fmt width %d, height %d\n", + sd->name, mf->width, mf->height); + + win = cmos_select_win(&mf->width, &mf->height); + if (!win) { + pr_err("%s, s_mbus_fmt failed, width %d, height %d\n", + sd->name, mf->width, mf->height); + return -EINVAL; + } + + sensor_write_array(sd, win->regs, win->size); + if(mf->width == 640 && mf->height ==480){ + sensor_write_shutter(sd,Preview_Shutter); + sensor_set_ae_mode(sd,true); + }else if(mf->width == 1600 && mf->height ==1200){ + sensor_set_ae_mode(sd,false); + shutter = sensor_read_shutter(sd); + Preview_Shutter = shutter; + shutter = shutter /2; + Capture_Shutter = shutter; + sensor_write_shutter(sd,Capture_Shutter); + + + } + + msleep(400); + //msleep(500); + return 0; +} + +static int sensor_try_mbus_fmt(struct cmos_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + return 0; +} + +static int sensor_enum_framesizes(struct cmos_subdev *sd, + struct v4l2_frmsizeenum *fsize) +{ + int i; + int num_valid = -1; + __u32 index = fsize->index; + + for (i = 0; i < ARRAY_SIZE(cmos_supported_win_sizes); i++) { + const struct cmos_win_size *win = &cmos_supported_win_sizes[index]; + if (index == ++num_valid) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = win->width; + fsize->discrete.height = win->height; + return 0; + } + } + + return -EINVAL; +} + +static int sensor_identify(struct cmos_subdev *sd) +{ + uint32_t data = 0; + + data |= (sensor_read(sd, 0xf0) & 0xff) << 8; + data |= (sensor_read(sd, 0xf1) & 0xff); + + return (data == sd->id) ? 0 : -EINVAL; +} + +static int sensor_init(struct cmos_subdev *sd) +{ + if (sensor_identify(sd)) { + return -1; + } + + sensor_write_array(sd, gc2035_default_regs_init, + ARRAY_SIZE(gc2035_default_regs_init)); + + msleep(100); + Preview_Shutter =sensor_read_shutter(sd); + return 0; +} + +static int sensor_exit(struct cmos_subdev *sd) +{ + sensor_write_array(sd, gc2035_default_regs_exit, + ARRAY_SIZE(gc2035_default_regs_exit)); + return 0; +} + +static struct cmos_subdev_ops gc2035_ops = { + .identify = sensor_identify, + .init = sensor_init, + .exit = sensor_exit, + .queryctrl = sensor_queryctrl, + .s_ctrl = sensor_s_ctrl, + .s_mbus_fmt = sensor_s_mbus_fmt, + .g_mbus_fmt = sensor_g_mbus_fmt, + .try_mbus_fmt = sensor_try_mbus_fmt, + .enum_framesizes = sensor_enum_framesizes, +}; + +struct cmos_subdev gc2035 = { + .name = "gc2035", + .i2c_addr = 0x3c, + .id = 0x2035, + .max_width = 1600, + .max_height = 1200, + .ops = &gc2035_ops, +}; + +#if 0 +static int __init gc2035_init(void) +{ + return cmos_register_sudbdev(&gc2035); +} + +static void __exit gc2035_exit(void) +{ + return cmos_unregister_subdev(&gc2035); +} + +module_init(gc2035_init); +module_exit(gc2035_exit); + +MODULE_LICENSE("GPL"); +#endif |