diff --git a/arch/arm/mach-rk29/include/mach/rk29_camera.h b/arch/arm/mach-rk29/include/mach/rk29_camera.h index 0daaab9b35e4..8dbc314b7bce 100644 --- a/arch/arm/mach-rk29/include/mach/rk29_camera.h +++ b/arch/arm/mach-rk29/include/mach/rk29_camera.h @@ -32,6 +32,7 @@ #define RK29_CAM_EIO_INVALID -1 #define RK29_CAM_EIO_REQUESTFAIL -2 +#define RK29_CAM_SENSOR_OV7675 ov7675 #define RK29_CAM_SENSOR_OV9650 ov9650 #define RK29_CAM_SENSOR_OV2655 ov2655 #define RK29_CAM_SENSOR_OV2659 ov2659 @@ -44,8 +45,15 @@ #define RK29_CAM_SENSOR_MT9P111 mt9p111 #define RK29_CAM_SENSOR_GT2005 gt2005 #define RK29_CAM_SENSOR_GC0308 gc0308 +#define RK29_CAM_SENSOR_GC0309 gc0309 +#define RK29_CAM_SENSOR_GC2015 gc2015 #define RK29_CAM_SENSOR_SIV120B siv120b +#define RK29_CAM_SENSOR_SID130B sid130B +#define RK29_CAM_SENSOR_HI253 hi253 +#define RK29_CAM_SENSOR_HI704 hi704 +#define RK29_CAM_SENSOR_NT99250 nt99250 +#define RK29_CAM_SENSOR_NAME_OV7675 "ov7675" #define RK29_CAM_SENSOR_NAME_OV9650 "ov9650" #define RK29_CAM_SENSOR_NAME_OV2655 "ov2655" #define RK29_CAM_SENSOR_NAME_OV2659 "ov2659" @@ -58,7 +66,13 @@ #define RK29_CAM_SENSOR_NAME_MT9P111 "mt9p111" #define RK29_CAM_SENSOR_NAME_GT2005 "gt2005" #define RK29_CAM_SENSOR_NAME_GC0308 "gc0308" +#define RK29_CAM_SENSOR_NAME_GC0309 "gc0309" +#define RK29_CAM_SENSOR_NAME_GC2015 "gc2015" #define RK29_CAM_SENSOR_NAME_SIV120B "siv120b" +#define RK29_CAM_SENSOR_NAME_SID130B "sid130B" +#define RK29_CAM_SENSOR_NAME_HI253 "hi253" +#define RK29_CAM_SENSOR_NAME_HI704 "hi704" +#define RK29_CAM_SENSOR_NAME_NT99250 "nt99250" #define RK29_CAM_POWERACTIVE_BITPOS 0x00 #define RK29_CAM_POWERACTIVE_MASK (1< #include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif #include +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend cm3202_early_suspend; +#endif + struct rk29_lsr_platform_data *lightsensor; static void lsr_report_value(struct input_dev *input_dev, int value) { - input_report_abs(input_dev, ABS_X, value); - //input_sync(input_dev); + input_report_abs(input_dev, ABS_MISC/*ABS_X*/, value); + input_sync(input_dev); } @@ -219,7 +226,7 @@ static void rk29_lsr_input_init(struct platform_device *dev) pdata->input_dev->name = "lsensor"; pdata->input_dev->dev.parent = &dev->dev; pdata->input_dev->evbit[0] = BIT(EV_ABS); - input_set_abs_params(pdata->input_dev,ABS_X,0,0x3ff,0,0); + input_set_abs_params(pdata->input_dev,ABS_MISC/*ABS_X*/,0,9/*0x3ff*/,0,0); ret = input_register_device(pdata->input_dev); return ; init_input_register_device_failed: @@ -232,7 +239,19 @@ static void rk29_lsr_input_deinit(struct platform_device *dev) input_unregister_device(pdata->input_dev); input_free_device(pdata->input_dev); } +static int lsr_suspend(struct platform_device *pdev, pm_message_t state) +{ + set_lsr_timer(0); + set_lsr_value(LSR_OFF); + return 0; +} +static int lsr_resume(struct platform_device *pdev) +{ + set_lsr_timer(1); + set_lsr_value(LSR_ON); + return 0; +} static int __devinit lsr_probe(struct platform_device *pdev) { lightsensor = kzalloc(sizeof(struct rk29_lsr_platform_data), GFP_KERNEL); @@ -253,6 +272,12 @@ static int __devinit lsr_probe(struct platform_device *pdev) rk29_lsr_adc_init(pdev); rk29_lsr_timer_init(pdev); rk29_lsr_input_init(pdev); +#ifdef CONFIG_HAS_EARLYSUSPEND + cm3202_early_suspend.suspend = lsr_suspend; + cm3202_early_suspend.resume = lsr_resume; + register_early_suspend(&cm3202_early_suspend); +#endif + return 0; err_kzalloc_lightsensor: @@ -271,27 +296,11 @@ static int __devexit lsr_remove(struct platform_device *pdev) return 0; } -static int lsr_suspend(struct platform_device *pdev, pm_message_t state) -{ - set_lsr_timer(0); - set_lsr_value(LSR_OFF); - return 0; -} - -static int lsr_resume(struct platform_device *pdev) -{ - set_lsr_timer(1); - set_lsr_value(LSR_ON); - return 0; -} - - - static struct platform_driver lsr_device_driver = { .probe = lsr_probe, .remove = __devexit_p(lsr_remove), - .suspend = lsr_suspend, - .resume = lsr_resume, +// .suspend = lsr_suspend, +// .resume = lsr_resume, .driver = { .name = LSR_NAME, .owner = THIS_MODULE, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4558672b62da..4c9e6344e2ed 100755 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -906,11 +906,24 @@ config SOC_CAMERA_OV9650 depends on SOC_CAMERA && I2C help This is a ov2655 camera driver + config SOC_CAMERA_OV3640 tristate "ov3640 camera support" depends on SOC_CAMERA && I2C help - This is a ov3640 camera driver + This is a ov3640 camera driver +choice + prompt "OV3640 Module Focus select" + depends on SOC_CAMERA_OV3640 + default OV3640_AUTOFOCUS + ---help--- + +config OV3640_AUTOFOCUS + bool "OV3640 auto focus" + +config OV3640_FIXEDFOCUS + bool "OV3640 fixed focus" +endchoice config SOC_CAMERA_OV5642 tristate "ov5642 camera support" @@ -964,11 +977,43 @@ config SOC_CAMERA_GC0308 depends on SOC_CAMERA && I2C help This is a GC0308 camera driver +config SOC_CAMERA_GC0309 + tristate "GC0309 support" + depends on SOC_CAMERA && I2C + help + This is a GC0309 camera driver +config SOC_CAMERA_GC2015 + tristate "GC2015 support" + depends on SOC_CAMERA && I2C + help + This is a GC2015 camera driver +config SOC_CAMERA_HI253 + tristate "HI253 support" + depends on SOC_CAMERA && I2C + help + This is a HI253 camera driver +config SOC_CAMERA_HI704 + tristate "HI704 support" + depends on SOC_CAMERA && I2C + help + This is a HI704 camera driver config SOC_CAMERA_SIV120B tristate "siv120b support" depends on SOC_CAMERA && I2C help This is a SIV120B camera driver + +config SOC_CAMERA_SID130B + tristate "sid130b support" + depends on SOC_CAMERA && I2C + help + This is a SID130B camera driver + +config SOC_CAMERA_NT99250 + tristate "NT99250 support" + depends on SOC_CAMERA && I2C + help + This is a NT99250 camera driver config MX1_VIDEO bool diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 18b0140a5db0..ff5d986bbded 100755 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -92,7 +92,13 @@ obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o obj-$(CONFIG_SOC_CAMERA_S5K6AA) += s5k6aa.o obj-$(CONFIG_SOC_CAMERA_GT2005) += gt2005.o obj-$(CONFIG_SOC_CAMERA_GC0308) += gc0308.o +obj-$(CONFIG_SOC_CAMERA_GC0309) += gc0309.o +obj-$(CONFIG_SOC_CAMERA_GC2015) += gc2015.o obj-$(CONFIG_SOC_CAMERA_SIV120B) += siv120b.o +obj-$(CONFIG_SOC_CAMERA_SID130B) += sid130B.o +obj-$(CONFIG_SOC_CAMERA_HI253) += hi253.o +obj-$(CONFIG_SOC_CAMERA_HI704) += hi704.o +obj-$(CONFIG_SOC_CAMERA_NT99250) += nt99250.o # And now the v4l2 drivers: obj-$(CONFIG_VIDEO_BT848) += bt8xx/ diff --git a/drivers/media/video/gc0309.c b/drivers/media/video/gc0309.c new file mode 100755 index 000000000000..3f55a02a9cf3 --- /dev/null +++ b/drivers/media/video/gc0309.c @@ -0,0 +1,2449 @@ +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_GC0309 +#define SENSOR_V4L2_IDENT V4L2_IDENT_GC0309 +#define SENSOR_ID 0xa0 +#define SENSOR_MIN_WIDTH 176 +#define SENSOR_MIN_HEIGHT 144 +#define SENSOR_MAX_WIDTH 648 +#define SENSOR_MAX_HEIGHT 488 +#define SENSOR_INIT_WIDTH 648 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 488 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_PIX_FMT_UYVY + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 100000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING|\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + + +struct reginfo +{ + u8 reg; + u8 val; +}; + +/* init SVGA preview */ +static struct reginfo sensor_init_data[] = +{ + /*init registers code.*/ + +{0xfe,0x80}, // soft reset + +// GC0309_SET_PAGE0; // set page0 + +{0x1a,0x16}, +{0xd2,0x10}, // close AEC +{0x22,0x55}, // close AWB + +{0x5a,0x56}, +{0x5b,0x40}, +{0x5c,0x4a}, + +{0x22,0x57}, + +{0x01,0xfa}, +{0x02,0x70}, +{0x0f,0x01}, + +{0xe2,0x00}, +{0xe3,0x64}, + +{0x03,0x01}, +{0x04,0x2c}, + + /* +{0x01,0x6a}, +{0x02,0x25}, +{0x0f,0x00}, + +{0xe2,0x00}, +{0xe3,0x4b}, + +{0xe4,0x02}, +{0xe5,0x0d}, +{0xe6,0x02}, +{0xe7,0x0d}, +{0xe8,0x02}, +{0xe9,0x0d}, +{0xea,0x05}, +{0xeb,0xdc}, + */ + +{0x05,0x00}, +{0x06,0x00}, +{0x07,0x00}, +{0x08,0x00}, +{0x09,0x01}, +{0x0a,0xe8}, +{0x0b,0x02}, +{0x0c,0x88}, +{0x0d,0x02}, +{0x0e,0x02}, +{0x10,0x22}, +{0x11,0x0d}, +{0x12,0x2a}, +{0x13,0x00}, +//{0x14,0x10}, +{0x15,0x0a}, +{0x16,0x05}, +{0x17,0x01}, + +{0x1b,0x03}, +{0x1c,0xc1}, +{0x1d,0x08}, +{0x1e,0x20}, +{0x1f,0x16}, + +{0x20,0xff}, +{0x21,0xf8}, +{0x24,0xa0}, +{0x25,0x0f}, + //output sync_mode +{0x26,0x03}, +{0x2f,0x01}, + ///////////////////////////////////////////////////////////////////// + /////////////////////////// grab_t //////////////////////////////// + ///////////////////////////////////////////////////////////////////// +{0x30,0xf7}, +{0x31,0x40}, +{0x32,0x00}, +{0x39,0x04}, +{0x3a,0x20}, +{0x3b,0x20}, +{0x3c,0x02}, +{0x3d,0x02}, +{0x3e,0x02}, +{0x3f,0x02}, + + //gain +{0x50,0x24}, + +{0x53,0x82}, +{0x54,0x80}, +{0x55,0x80}, +{0x56,0x82}, + + ///////////////////////////////////////////////////////////////////// + /////////////////////////// LSC_t //////////////////////////////// + ///////////////////////////////////////////////////////////////////// +{0x8b,0x20}, +{0x8c,0x20}, +{0x8d,0x20}, +{0x8e,0x10}, +{0x8f,0x10}, +{0x90,0x10}, +{0x91,0x3c}, +{0x92,0x50}, +{0x5d,0x12}, +{0x5e,0x1a}, +{0x5f,0x24}, + ///////////////////////////////////////////////////////////////////// + /////////////////////////// DNDD_t /////////////////////////////// + ///////////////////////////////////////////////////////////////////// +{0x60,0x07}, +{0x61,0x0e}, +{0x62,0x0c}, +{0x64,0x03}, +{0x66,0xe8}, +{0x67,0x86}, +{0x68,0xa2}, + + ///////////////////////////////////////////////////////////////////// + /////////////////////////// asde_t /////////////////////////////// + ///////////////////////////////////////////////////////////////////// +{0x69,0x20}, +{0x6a,0x0f}, +{0x6b,0x00}, +{0x6c,0x53}, +{0x6d,0x83}, +{0x6e,0xac}, +{0x6f,0xac}, +{0x70,0x15}, +{0x71,0x33}, + ///////////////////////////////////////////////////////////////////// + /////////////////////////// eeintp_t/////////////////////////////// +}; + + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ +{0x45 , 0x0f}, //output enable + {0x0,0x0} +}; + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{}; + + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + + {0x00, 0x00} +}; + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + + {0x00, 0x00} +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + + {0x00, 0x00} +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + //Sunny + + {0x00, 0x00} +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + //Office + + {0x00, 0x00} + +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + //Home + + {0x00, 0x00} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + + {0x00, 0x00} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + //Negative + + {0x00, 0x00} +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + // Bluish + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + // Greenish + + {0x00, 0x00} +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + //-3 + +}; + +static struct reginfo sensor_Exposure1[]= +{ + //-2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure2[]= +{ + //-0.3EV + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure3[]= +{ + //default + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure4[]= +{ + // 1 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure5[]= +{ + // 2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure6[]= +{ + // 3 + + {0x00, 0x00} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Saturation1[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Saturation2[]= +{ + + {0x00, 0x00} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + //Contrast -3 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast1[]= +{ + //Contrast -2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast2[]= +{ + // Contrast -1 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast3[]= +{ + //Contrast 0 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast4[]= +{ + //Contrast +1 + + {0x00, 0x00} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + //Contrast +2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast6[]= +{ + //Contrast +3 + + {0x00, 0x00} +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + + {0x00, 0x00} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_FlipOff[]= +{ + + {0x00, 0x00} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ +#if 0 /* ddl@rock-chips.com : */ + {0x3014, 0x04}, + {0x3015, 0x00}, + {0x302e, 0x00}, + {0x302d, 0x00}, + {0x00, 0x00} +#else + + {0x00, 0x00} +#endif +}; + +static struct reginfo sensor_SceneNight[] = +{ +#if 1 + //30fps ~ 5fps night mode for 60/50Hz light environment, 24Mhz clock input,36Mzh pclk + + {0x00, 0x00} +#else + //15fps ~ 5fps night mode for 60/50Hz light environment, 24Mhz clock input,18Mhz pclk + {0x300e, 0x34}, + {0x3011, 0x01}, + {0x302c, 0x00}, + {0x3071, 0x00}, + {0x3070, 0x5d}, + {0x301c, 0x05}, + {0x3073, 0x00}, + {0x3072, 0x4d}, + {0x301d, 0x07}, + {0x3014, 0x0c}, + {0x3015, 0x50}, + {0x302e, 0x00}, + {0x302d, 0x00}, +#endif +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0x0, 0x0}, +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0x0, 0x0}, +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +#define COL_FMT(_name, _depth, _fourcc, _colorspace) \ + { .name = _name, .depth = _depth, .fourcc = _fourcc, \ + .colorspace = _colorspace } + +#define JPG_FMT(_name, _depth, _fourcc) \ + COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) + +static const struct soc_camera_data_format sensor_colour_formats[] = { + JPG_FMT(SENSOR_NAME_STRING(UYVY), 16, V4L2_PIX_FMT_UYVY), + JPG_FMT(SENSOR_NAME_STRING(YUYV), 16, V4L2_PIX_FMT_YUYV), +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + unsigned int pixfmt; + +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } +#endif + return 0; +sensor_task_lock_err: + return -1; +} + +#if 0 +/* sensor register */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int ret = 0; + + ret = i2c_master_reg8_recv(client, reg, val, 1, CONFIG_SENSOR_I2C_SPEED); + + return (ret > 0)? 0 : ret; +} + +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int ret = 0; + + ret = i2c_master_reg8_send(client, reg, &val, 1, CONFIG_SENSOR_I2C_SPEED); + + return (ret > 0)? 0 : ret; +} +#else +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg; + buf[1] = val; + + if (reg == 0xfe) + mdelay(10); + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + u8 buf[1]; + struct i2c_msg msg[2]; + + buf[0] = reg ; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +#endif + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; + int j = 0; + char valchk; + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + while (regarray[i].reg != 0) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + //mdelay(5); + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != 0) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } + return 0; +} +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + char value; + int ret; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + ret = sensor_write(client, 0xfe, 0x80); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); //delay 5 microseconds + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x00, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + if (value == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), value); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + sensor_task_lock(client,0); + //icd->user_width = SENSOR_INIT_WIDTH; + //icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + sensor->info_priv.pixfmt = SENSOR_INIT_PIXFMT; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + + return 0; +sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); + return 0; +} + +static struct reginfo sensor_power_down_sequence[]= +{ + {0x00,0x00} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = icd->user_width; + pix->height = icd->user_height; + pix->pixelformat = sensor->info_priv.pixfmt; + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_JPEG; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) { + ret = true; + } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) { + ret = true; + } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) { + ret = true; + } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) { + ret = true; + } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 720)) { + ret = true; + } else if ((f->fmt.pix.width == 1920) && (f->fmt.pix.height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + SENSOR_TR("sensor_s_fmt\n"); + if (sensor->info_priv.pixfmt != pix->pixelformat) { + switch (pix->pixelformat) + { + case V4L2_PIX_FMT_YUYV: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_PIX_FMT_UYVY: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.pixfmt = pix->pixelformat; + + SENSOR_DG("%s Pixelformat(0x%x) set success!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } else { + SENSOR_TR("%s Pixelformat(0x%x) is invalidate!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } + } + + set_w = pix->width; + set_h = pix->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + winseqe_set_addr = sensor_vga; + set_w = 640; + set_h = 480; + } + + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + ret = -1; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,pix->width,pix->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,f) == true) { /* ddl@rock-chips.com : Video */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + pix->width = set_w; + pix->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + bool bayer = pix->pixelformat == V4L2_PIX_FMT_UYVY || + pix->pixelformat == V4L2_PIX_FMT_YUYV; + + /* + * With Bayer format enforce even side lengths, but let the user play + * with the starting pixel + */ + + if (pix->height > SENSOR_MAX_HEIGHT) + pix->height = SENSOR_MAX_HEIGHT; + else if (pix->height < SENSOR_MIN_HEIGHT) + pix->height = SENSOR_MIN_HEIGHT; + else if (bayer) + pix->height = ALIGN(pix->height, 2); + + if (pix->width > SENSOR_MAX_WIDTH) + pix->width = SENSOR_MAX_WIDTH; + else if (pix->width < SENSOR_MIN_WIDTH) + pix->width = SENSOR_MIN_WIDTH; + else if (bayer) + pix->width = ALIGN(pix->width, 2); + + return 0; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV2655 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char value; + int ret; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + ret = sensor_write(client, 0xfe, 0x80); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(5); //delay 5 microseconds + + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x00, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + if (value == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + SENSOR_TR("chip id:0x%x\n",value); + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), value); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + icd->formats = sensor_colour_formats; + icd->num_formats = ARRAY_SIZE(sensor_colour_formats); + + return 0; + +sensor_video_probe_err: + + return ret; +} +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_fmt = sensor_s_fmt, + .g_fmt = sensor_g_fmt, + .try_fmt = sensor_try_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + icd->y_skip_top = 0; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); + + + diff --git a/drivers/media/video/gc2015.c b/drivers/media/video/gc2015.c new file mode 100755 index 000000000000..21825633b90a --- /dev/null +++ b/drivers/media/video/gc2015.c @@ -0,0 +1,2655 @@ +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_GC2015 +#define SENSOR_V4L2_IDENT V4L2_IDENT_GC2015 +#define SENSOR_ID 0x2005 +#define SENSOR_MIN_WIDTH 176 +#define SENSOR_MIN_HEIGHT 144 +#define SENSOR_MAX_WIDTH 1600 +#define SENSOR_MAX_HEIGHT 1200 +#define SENSOR_INIT_WIDTH 1024 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 768 +#define SENSOR_INIT_WINSEQADR sensor_svga +#define SENSOR_INIT_PIXFMT V4L2_PIX_FMT_UYVY + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 100000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING|\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + + +struct reginfo +{ + u8 reg; + u8 val; +}; + +/* init SVGA preview */ +static struct reginfo sensor_init_data[] = +{ +//{0xfe , 0x80}, //soft reset +{0x45 , 0x00}, //output_enable + ////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////preview capture switch ///////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + //preview +{0x02 , 0x01}, //preview mode +{0x2a , 0xca}, //[7]col_binning , 0x[6]even skip +{0x48 , 0x40}, //manual_gain + + //////////////////////////////////////////////////////////////////////// + ////////////////////////// preview LSC ///////////////////////////////// + //////////////////////////////////////////////////////////////////////// + +{0xb0 , 0x13}, //[4]Y_LSC_en [3]lsc_compensate [2]signed_b4 [1:0]pixel array select +{0xb1 , 0x20}, //P_LSC_red_b2 +{0xb2 , 0x20}, //P_LSC_green_b2 +{0xb3 , 0x20}, //P_LSC_blue_b2 +{0xb4 , 0x20}, //P_LSC_red_b4 +{0xb5 , 0x20}, //P_LSC_green_b4 +{0xb6 , 0x20}, //P_LSC_blue_b4 +{0xb7 , 0x00}, //P_LSC_compensate_b2 +{0xb8 , 0x80}, //P_LSC_row_center , 0x344 , 0x (0x600/2-100)/2=100 +{0xb9 , 0x80}, //P_LSC_col_center , 0x544 , 0x (0x800/2-200)/2=100 + + //////////////////////////////////////////////////////////////////////// + ////////////////////////// capture LSC /////////////////////////// + //////////////////////////////////////////////////////////////////////// +{0xba , 0x13}, //[4]Y_LSC_en [3]lsc_compensate [2]signed_b4 [1:0]pixel array select +{0xbb , 0x20}, //C_LSC_red_b2 +{0xbc , 0x20}, //C_LSC_green_b2 +{0xbd , 0x20}, //C_LSC_blue_b2 +{0xbe , 0x20}, //C_LSC_red_b4 +{0xbf , 0x20}, //C_LSC_green_b4 +{0xc0 , 0x20}, //C_LSC_blue_b4 +{0xc1 , 0x00}, //C_Lsc_compensate_b2 +{0xc2 , 0x80}, //C_LSC_row_center , 0x344 , 0x (0x1200/2-344)/2=128 +{0xc3 , 0x80}, //C_LSC_col_center , 0x544 , 0x (0x1600/2-544)/2=128 + + //GC2015_SET_PAGE0; //page0 + + //////////////////////////////////////////////////////////////////////// + ////////////////////////// analog configure /////////////////////////// + //////////////////////////////////////////////////////////////////////// +{0x29 , 0x00}, //cisctl mode 1 +{0x2b , 0x06}, //cisctl mode 3 +{0x32 , 0x0c}, //analog mode 1 +{0x33 , 0x0f}, //analog mode 2 +{0x34 , 0x00}, //[6:4]da_rsg + +{0x35 , 0x88}, //Vref_A25 +{0x37 , 0x16}, //Drive Current + + ///////////////////////////////////////////////////////////////////// + ///////////////////////////ISP Related////////////////////////////// + ///////////////////////////////////////////////////////////////////// +{0x40 , 0xff}, +{0x41 , 0x24}, //[5]skin_detectionenable[2]auto_gray , 0x[1]y_gamma +{0x42 , 0x76}, //[7]auto_sa[6]auto_ee[5]auto_dndd[4]auto_lsc[3]na[2]abs , 0x[1]awb +{0x4b , 0xea}, //[1]AWB_gain_mode , 0x1:atpregain0:atpostgain +{0x4d , 0x03}, //[1]inbf_en +{0x4f , 0x01}, //AEC enable + + //////////////////////////////////////////////////////////////////// + /////////////////////////// BLK /////////////////////////////////// + //////////////////////////////////////////////////////////////////// +{0x63 , 0x77}, //BLK mode 1 +{0x66 , 0x00}, //BLK global offset +{0x6d , 0x04}, +{0x6e , 0x18}, //BLK offset submode,offset R +{0x6f , 0x10}, +{0x70 , 0x18}, +{0x71 , 0x10}, +{0x73 , 0x03}, + + + //////////////////////////////////////////////////////////////////// + /////////////////////////// DNDD //////////////////////////////// + //////////////////////////////////////////////////////////////////// +{0x80 , 0x07}, //[7]dn_inc_or_dec [4]zero_weight_mode[3]share [2]c_weight_adap [1]dn_lsc_mode [0]dn_b +{0x82 , 0x08}, //DN lilat b base + + //////////////////////////////////////////////////////////////////// + /////////////////////////// EEINTP //////////////////////////////// + //////////////////////////////////////////////////////////////////// +{0x8a , 0x7c}, +{0x8c , 0x02}, +{0x8e , 0x02}, +{0x8f , 0x48}, + + ///////////////////////////////////////////////////////////////////// + /////////////////////////// CC_t /////////////////////////////// + ///////////////////////////////////////////////////////////////////// +{0xb0 , 0x44}, +{0xb1 , 0xfe}, +{0xb2 , 0x00}, +{0xb3 , 0xf8}, +{0xb4 , 0x48}, +{0xb5 , 0xf8}, +{0xb6 , 0x00}, +{0xb7 , 0x04}, +{0xb8 , 0x00}, + + ///////////////////////////////////////////////////////////////////// + /////////////////////////// GAMMA /////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + //RGB_GAMMA +{0xbf , 0x0e}, +{0xc0 , 0x1c}, +{0xc1 , 0x34}, +{0xc2 , 0x48}, +{0xc3 , 0x5a}, +{0xc4 , 0x6b}, +{0xc5 , 0x7b}, +{0xc6 , 0x95}, +{0xc7 , 0xab}, +{0xc8 , 0xbf}, +{0xc9 , 0xce}, +{0xca , 0xd9}, +{0xcb , 0xe4}, +{0xcc , 0xec}, +{0xcd , 0xf7}, +{0xce , 0xfd}, +{0xcf , 0xff}, + + ///////////////////////////////////////////////////////////////////// + /////////////////////////// YCP_t /////////////////////////////// + ///////////////////////////////////////////////////////////////////// +{0xd1 , 0x38}, //saturation +{0xd2 , 0x38}, //saturation +{0xde , 0x21}, //auto_gray + + //////////////////////////////////////////////////////////////////// + /////////////////////////// ASDE //////////////////////////////// + //////////////////////////////////////////////////////////////////// +{0x98 , 0x30}, +{0x99 , 0xf0}, +{0x9b , 0x00}, + + //GC2015_SET_PAGE1; //page1 + //////////////////////////////////////////////////////////////////// + /////////////////////////// AEC //////////////////////////////// + //////////////////////////////////////////////////////////////////// +{0x10 , 0x45}, //AEC mode 1 +{0x11 , 0x32}, //[7]fix target +{0x13 , 0x60}, +{0x17 , 0x00}, +{0x1c , 0x96}, +{0x1e , 0x11}, +{0x21 , 0xc0}, //max_post_gain +{0x22 , 0x40}, //max_pre_gain +{0x2d , 0x06}, //P_N_AEC_exp_level_1[12:8] +{0x2e , 0x00}, //P_N_AEC_exp_level_1[7:0] +{0x1e , 0x32}, +{0x33 , 0x00}, //[6:5]max_exp_level [4:0]min_exp_level + + //////////////////////////////////////////////////////////////////// + /////////////////////////// AWB //////////////////////////////// + //////////////////////////////////////////////////////////////////// +{0x57 , 0x40}, //number limit +{0x5d , 0x44}, // +{0x5c , 0x35}, //show mode,close dark_mode +{0x5e , 0x29}, //close color temp +{0x5f , 0x50}, +{0x60 , 0x50}, +{0x65 , 0xc0}, + + //////////////////////////////////////////////////////////////////// + /////////////////////////// ABS //////////////////////////////// + //////////////////////////////////////////////////////////////////// +{0x80 , 0x82}, +{0x81 , 0x00}, +{0x83 , 0x00}, //ABS Y stretch limit + + //GC2015_SET_PAGE0; + + ////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////// Crop ////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// +{0x50 , 0x01},//out window +{0x51 , 0x00}, +{0x52 , 0x00}, +{0x53 , 0x00}, +{0x54 , 0x00}, +{0x55 , 0x02}, +{0x56 , 0x58}, +{0x57 , 0x03}, +{0x58 , 0x20}, + + //////////////////////////////////////////////////////////////////// + /////////////////////////// OUT //////////////////////////////// + //////////////////////////////////////////////////////////////////// +{0x44 , 0xa0}, //YUV sequence +{0x45 , 0x0f}, //output enable +{0x46 , 0x02}, //sync mode +}; + +/* 1600X1200 UXGA capture */ +static struct reginfo sensor_uxga[] = +{ +{0x45 , 0x0f}, //output enable + {0x0,0x0} +}; + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {0x0, 0x0} +}; +static struct reginfo sensor_xga[] = +{ + {0x0, 0x0} +}; +/* 800X600 SVGA,30fps*/ +static struct reginfo sensor_svga[] = +{ +{0x45 , 0x0f}, //output enable + {0x0,0x0} +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ +{0x45 , 0x0f}, //output enable + {0x0,0x0} +}; + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{}; +#if 0 +/* 160X120 QQVGA*/ +static struct reginfo ov2655_qqvga[] = +{ + + {0x300E, 0x34}, + {0x3011, 0x01}, + {0x3012, 0x10}, + {0x302a, 0x02}, + {0x302b, 0xE6}, + {0x306f, 0x14}, + {0x3362, 0x90}, + + {0x3070, 0x5d}, + {0x3072, 0x5d}, + {0x301c, 0x07}, + {0x301d, 0x07}, + + {0x3020, 0x01}, + {0x3021, 0x18}, + {0x3022, 0x00}, + {0x3023, 0x06}, + {0x3024, 0x06}, + {0x3025, 0x58}, + {0x3026, 0x02}, + {0x3027, 0x61}, + {0x3088, 0x00}, + {0x3089, 0xa0}, + {0x308a, 0x00}, + {0x308b, 0x78}, + {0x3316, 0x64}, + {0x3317, 0x25}, + {0x3318, 0x80}, + {0x3319, 0x08}, + {0x331a, 0x0a}, + {0x331b, 0x07}, + {0x331c, 0x80}, + {0x331d, 0x38}, + {0x3100, 0x00}, + {0x3302, 0x11}, + + {0x0, 0x0}, +}; + + + +static struct reginfo ov2655_Sharpness_auto[] = +{ + {0x3306, 0x00}, +}; + +static struct reginfo ov2655_Sharpness1[] = +{ + {0x3306, 0x08}, + {0x3371, 0x00}, +}; + +static struct reginfo ov2655_Sharpness2[][3] = +{ + //Sharpness 2 + {0x3306, 0x08}, + {0x3371, 0x01}, +}; + +static struct reginfo ov2655_Sharpness3[] = +{ + //default + {0x3306, 0x08}, + {0x332d, 0x02}, +}; +static struct reginfo ov2655_Sharpness4[]= +{ + //Sharpness 4 + {0x3306, 0x08}, + {0x332d, 0x03}, +}; + +static struct reginfo ov2655_Sharpness5[] = +{ + //Sharpness 5 + {0x3306, 0x08}, + {0x332d, 0x04}, +}; +#endif + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + + {0x00, 0x00} +}; + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + + {0x00, 0x00} +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + + {0x00, 0x00} +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + //Sunny + + {0x00, 0x00} +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + //Office + + {0x00, 0x00} + +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + //Home + + {0x00, 0x00} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + + {0x00, 0x00} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + //Negative + + {0x00, 0x00} +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + // Bluish + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + // Greenish + + {0x00, 0x00} +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + //-3 + +}; + +static struct reginfo sensor_Exposure1[]= +{ + //-2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure2[]= +{ + //-0.3EV + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure3[]= +{ + //default + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure4[]= +{ + // 1 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure5[]= +{ + // 2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure6[]= +{ + // 3 + + {0x00, 0x00} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Saturation1[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Saturation2[]= +{ + + {0x00, 0x00} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + //Contrast -3 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast1[]= +{ + //Contrast -2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast2[]= +{ + // Contrast -1 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast3[]= +{ + //Contrast 0 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast4[]= +{ + //Contrast +1 + + {0x00, 0x00} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + //Contrast +2 + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast6[]= +{ + //Contrast +3 + + {0x00, 0x00} +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + + {0x00, 0x00} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_FlipOff[]= +{ + + {0x00, 0x00} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ +#if 0 /* ddl@rock-chips.com : */ + {0x3014, 0x04}, + {0x3015, 0x00}, + {0x302e, 0x00}, + {0x302d, 0x00}, + {0x00, 0x00} +#else + + {0x00, 0x00} +#endif +}; + +static struct reginfo sensor_SceneNight[] = +{ +#if 1 + //30fps ~ 5fps night mode for 60/50Hz light environment, 24Mhz clock input,36Mzh pclk + + {0x00, 0x00} +#else + //15fps ~ 5fps night mode for 60/50Hz light environment, 24Mhz clock input,18Mhz pclk + {0x300e, 0x34}, + {0x3011, 0x01}, + {0x302c, 0x00}, + {0x3071, 0x00}, + {0x3070, 0x5d}, + {0x301c, 0x05}, + {0x3073, 0x00}, + {0x3072, 0x4d}, + {0x301d, 0x07}, + {0x3014, 0x0c}, + {0x3015, 0x50}, + {0x302e, 0x00}, + {0x302d, 0x00}, +#endif +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0x0, 0x0}, +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0x0, 0x0}, +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +#define COL_FMT(_name, _depth, _fourcc, _colorspace) \ + { .name = _name, .depth = _depth, .fourcc = _fourcc, \ + .colorspace = _colorspace } + +#define JPG_FMT(_name, _depth, _fourcc) \ + COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) + +static const struct soc_camera_data_format sensor_colour_formats[] = { + JPG_FMT(SENSOR_NAME_STRING(UYVY), 16, V4L2_PIX_FMT_UYVY), + JPG_FMT(SENSOR_NAME_STRING(YUYV), 16, V4L2_PIX_FMT_YUYV), +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + unsigned int pixfmt; + +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } +#endif + return 0; +sensor_task_lock_err: + return -1; +} + +#if 0 +/* sensor register */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int ret = 0; + + ret = i2c_master_reg8_recv(client, reg, val, 1, CONFIG_SENSOR_I2C_SPEED); + + return (ret > 0)? 0 : ret; +} + +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int ret = 0; + + ret = i2c_master_reg8_send(client, reg, &val, 1, CONFIG_SENSOR_I2C_SPEED); + + return (ret > 0)? 0 : ret; +} +#else +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg; + buf[1] = val; + + if (reg == 0xfe) + mdelay(20); + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + u8 buf[1]; + struct i2c_msg msg[2]; + + buf[0] = reg ; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +#endif + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; + int j = 0; + char valchk; + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + while (regarray[i].reg != 0) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + //mdelay(5); + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != 0) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } + return 0; +} +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + char value; + int ret,pid = 0; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + ret = sensor_write(client, 0xfe, 0x80); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); //delay 5 microseconds + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x00, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + pid |= (value << 8); + + ret = sensor_read(client, 0x01, &value); + if (ret != 0) { + SENSOR_TR("read chip id low byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + pid |= (value & 0xff); + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + sensor_task_lock(client,0); + //icd->user_width = SENSOR_INIT_WIDTH; + //icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + sensor->info_priv.pixfmt = SENSOR_INIT_PIXFMT; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + + return 0; +sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); + return 0; +} + +static struct reginfo sensor_power_down_sequence[]= +{ + {0x00,0x00} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = icd->user_width; + pix->height = icd->user_height; + pix->pixelformat = sensor->info_priv.pixfmt; + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_JPEG; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) { + ret = true; + } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) { + ret = true; + } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) { + ret = true; + } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) { + ret = true; + } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 720)) { + ret = true; + } else if ((f->fmt.pix.width == 1920) && (f->fmt.pix.height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + SENSOR_TR("sensor_s_fmt\n"); + if (sensor->info_priv.pixfmt != pix->pixelformat) { + switch (pix->pixelformat) + { + case V4L2_PIX_FMT_YUYV: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_PIX_FMT_UYVY: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.pixfmt = pix->pixelformat; + + SENSOR_DG("%s Pixelformat(0x%x) set success!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } else { + SENSOR_TR("%s Pixelformat(0x%x) is invalidate!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } + } + + set_w = pix->width; + set_h = pix->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + winseqe_set_addr = sensor_vga; + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1024) && (set_h <= 768)) && sensor_xga[0].reg) + { + winseqe_set_addr = sensor_xga; + set_w = 1024; + set_h = 768; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else if (((set_w <= 1600) && (set_h <= 1200)) && sensor_uxga[0].reg) + { + winseqe_set_addr = sensor_uxga; + set_w = 1600; + set_h = 1200; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + ret = -1; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,pix->width,pix->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,f) == true) { /* ddl@rock-chips.com : Video */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + pix->width = set_w; + pix->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + bool bayer = pix->pixelformat == V4L2_PIX_FMT_UYVY || + pix->pixelformat == V4L2_PIX_FMT_YUYV; + + /* + * With Bayer format enforce even side lengths, but let the user play + * with the starting pixel + */ + + if (pix->height > SENSOR_MAX_HEIGHT) + pix->height = SENSOR_MAX_HEIGHT; + else if (pix->height < SENSOR_MIN_HEIGHT) + pix->height = SENSOR_MIN_HEIGHT; + else if (bayer) + pix->height = ALIGN(pix->height, 2); + + if (pix->width > SENSOR_MAX_WIDTH) + pix->width = SENSOR_MAX_WIDTH; + else if (pix->width < SENSOR_MIN_WIDTH) + pix->width = SENSOR_MIN_WIDTH; + else if (bayer) + pix->width = ALIGN(pix->width, 2); + + return 0; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV2655 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char value; + int ret,pid=0; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + ret = sensor_write(client, 0xfe, 0x80); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(5); //delay 5 microseconds + + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x00, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + pid |= (value << 8); + + ret = sensor_read(client, 0x01, &value); + if (ret != 0) { + SENSOR_TR("read chip id low byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + pid |= (value & 0xff); + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + icd->formats = sensor_colour_formats; + icd->num_formats = ARRAY_SIZE(sensor_colour_formats); + + return 0; + +sensor_video_probe_err: + + return ret; +} +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_fmt = sensor_s_fmt, + .g_fmt = sensor_g_fmt, + .try_fmt = sensor_try_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + icd->y_skip_top = 0; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/media/video/hi253.c b/drivers/media/video/hi253.c new file mode 100755 index 000000000000..70c35675e720 --- /dev/null +++ b/drivers/media/video/hi253.c @@ -0,0 +1,3504 @@ +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_HI253 +#define SENSOR_V4L2_IDENT V4L2_IDENT_HI253 +#define SENSOR_ID 0x92 +#define SENSOR_MIN_WIDTH 176 +#define SENSOR_MIN_HEIGHT 144 +#define SENSOR_MAX_WIDTH 1600 +#define SENSOR_MAX_HEIGHT 1200 +#define SENSOR_INIT_WIDTH 1600 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 1200 +#define SENSOR_INIT_WINSEQADR sensor_uxga +#define SENSOR_INIT_PIXFMT V4L2_PIX_FMT_UYVY + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 100000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING|\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + + +#define END_REG 0xff + +struct reginfo +{ + u8 reg; + u8 val; +}; + +/* init SVGA preview */ +static struct reginfo sensor_init_data[] = +{ +// {0x01, 0xf9}, + {0x08, 0x0f}, + {0x01, 0xf8}, + + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + + {0x0e, 0x00}, + + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + + {0x0e, 0x00}, + {0x01, 0xf1}, + {0x08, 0x00}, + {0x01, 0xf3}, + {0x01, 0xf1}, + + {0x03, 0x20}, + {0x10, 0x0c}, + {0x03, 0x22}, + {0x10, 0x69}, + + //Page 00 + {0x03, 0x00}, + {0x10, 0x00}, //lxh + {0x11, 0x90}, + {0x12, 0x04}, + {0x0b, 0xaa}, + {0x0c, 0xaa}, + {0x0d, 0xaa}, + {0x20, 0x00}, + {0x21, 0x0a}, //lxh + {0x22, 0x00}, + {0x23, 0x0a}, //lxh + {0x24, 0x04}, + {0x25, 0xb0}, + {0x26, 0x06}, + {0x27, 0x40}, + + {0x40, 0x01}, + {0x41, 0x98},//lxh + {0x42, 0x00}, + {0x43, 0x14},//lxh + + {0x45, 0x04}, + {0x46, 0x18}, + {0x47, 0xd8}, + + {0xe1, 0x0f}, + + //BLC + {0x80, 0x2e}, + {0x81, 0x7e}, + {0x82, 0x90}, + {0x83, 0x00}, + {0x84, 0x0c}, + {0x85, 0x00}, + {0x90, 0x0c}, + {0x91, 0x0c}, + {0x92, 0x78}, + {0x93, 0x70}, + {0x94, 0x75}, + {0x95, 0x70}, + {0x96, 0xdc}, + {0x97, 0xfe}, + {0x98, 0x20}, + + //OutDoor BLC + {0x99,0x42}, + {0x9a,0x42}, + {0x9b,0x42}, + {0x9c,0x42}, + + //Dark BLC + {0xa0, 0x00}, + {0xa2, 0x00}, + {0xa4, 0x00}, + {0xa6, 0x00}, + + //Normal BLC + {0xa8, 0x43}, + {0xaa, 0x43}, + {0xac, 0x43}, + {0xae, 0x43}, + + //Page 02 + {0x03, 0x02}, + {0x12, 0x03}, + {0x13, 0x03}, + {0x16, 0x00}, + {0x17, 0x8C}, + {0x18, 0x4c}, + {0x19, 0x00}, + {0x1a, 0x39}, + {0x1c, 0x09}, + {0x1d, 0x40}, + {0x1e, 0x30}, + {0x1f, 0x10}, + {0x20, 0x77}, + {0x21, 0xde}, + {0x22, 0xa7}, + {0x23, 0x30}, + {0x27, 0x3c}, + {0x2b, 0x80}, + {0x2e, 0x00}, + {0x2f, 0x00}, + {0x30, 0x05}, + {0x50, 0x20}, + {0x52, 0x01}, + {0x53, 0xc1}, + {0x55, 0x1c}, + {0x56, 0x11}, + {0x5d, 0xA2}, + {0x5e, 0x5a}, + {0x60, 0x87}, + {0x61, 0x99}, + {0x62, 0x88}, + {0x63, 0x97}, + {0x64, 0x88}, + {0x65, 0x97}, + {0x67, 0x0c}, + {0x68, 0x0c}, + {0x69, 0x0c}, + {0x72, 0x89}, + {0x73, 0x96}, + {0x74, 0x89}, + {0x75, 0x96}, + {0x76, 0x89}, + {0x77, 0x96}, + {0x7C, 0x85}, + {0x7d, 0xaf}, + {0x80, 0x01}, + {0x81, 0x7f}, + {0x82, 0x13}, + {0x83, 0x24}, + {0x84, 0x7d}, + {0x85, 0x81}, + {0x86, 0x7d}, + {0x87, 0x81}, + {0x92, 0x48}, + {0x93, 0x54}, + {0x94, 0x7d}, + {0x95, 0x81}, + {0x96, 0x7d}, + {0x97, 0x81}, + {0xa0, 0x02}, + {0xa1, 0x7b}, + {0xa2, 0x02}, + {0xa3, 0x7b}, + {0xa4, 0x7b}, + {0xa5, 0x02}, + {0xa6, 0x7b}, + {0xa7, 0x02}, + {0xa8, 0x85}, + {0xa9, 0x8c}, + {0xaa, 0x85}, + {0xab, 0x8c}, + {0xac, 0x10}, + {0xad, 0x16}, + {0xae, 0x10}, + {0xaf, 0x16}, + {0xb0, 0x99}, + {0xb1, 0xa3}, + {0xb2, 0xa4}, + {0xb3, 0xae}, + {0xb4, 0x9b}, + {0xb5, 0xa2}, + {0xb6, 0xa6}, + {0xb7, 0xac}, + {0xb8, 0x9b}, + {0xb9, 0x9f}, + {0xba, 0xa6}, + {0xbb, 0xaa}, + {0xbc, 0x9b}, + {0xbd, 0x9f}, + {0xbe, 0xa6}, + {0xbf, 0xaa}, + {0xc4, 0x2c}, + {0xc5, 0x43}, + {0xc6, 0x63}, + {0xc7, 0x79}, + {0xc8, 0x2d}, + {0xc9, 0x42}, + {0xca, 0x2d}, + {0xcb, 0x42}, + {0xcc, 0x64}, + {0xcd, 0x78}, + {0xce, 0x64}, + {0xcf, 0x78}, + {0xd0, 0x0a}, + {0xd1, 0x09}, + {0xd4, 0x0c}, + {0xd5, 0x0c}, + {0xd6, 0xd8}, + {0xd7, 0xd0},//lxh + {0xe0, 0xc4}, + {0xe1, 0xc4}, + {0xe2, 0xc4}, + {0xe3, 0xc4}, + {0xe4, 0x00}, + {0xe8, 0x80}, + {0xe9, 0x40}, + {0xea, 0x7f}, + {0xf0, 0x01}, + {0xf1, 0x01}, + {0xf2, 0x01}, + {0xf3, 0x01}, + {0xf4, 0x01}, + + //PAGE10 + {0x03, 0x10}, + {0x10, 0x01}, //lxh + {0x11, 0x03}, //lxh,normal + {0x12, 0x00}, + {0x13, 0x00}, + {0x20, 0x00}, + + {0x40, 0x80}, + {0x41, 0x00}, + {0x48, 0x88},// 84 + {0x50, 0x90}, + {0x30, 0x00}, + {0x31, 0x00}, + {0x32, 0x00}, + {0x33, 0x00}, + + {0x34, 0x30}, + {0x35, 0x00}, + {0x36, 0x00}, + {0x38, 0x00}, + {0x3e, 0x58}, + {0x3f, 0x00}, + + //Saturation + {0x60, 0x6f}, + {0x61, 0x95},// 74 + {0x62, 0x95},// 76 + {0x63, 0x30}, + {0x64, 0x41}, + + {0x66, 0x33}, + {0x67, 0x00}, + + {0x6a, 0x90}, + {0x6b, 0x80}, + {0x6c, 0x80}, + {0x6d, 0xa0}, + + {0x76, 0x01}, + {0x74, 0x66}, + {0x79, 0x06}, + + //Page 11 + {0x03, 0x11}, + {0x10, 0x7f},//lxh,3f + {0x11, 0x40}, + {0x12, 0xba}, + {0x13, 0xcb}, + {0x26, 0x20}, + {0x27, 0x22}, + {0x28, 0x0f}, + {0x29, 0x10}, + {0x2b, 0x30}, + {0x2c, 0x32}, + + //Out2 D-LPF th + {0x30, 0x70}, + {0x31, 0x10}, + {0x32, 0x65}, + {0x33, 0x09}, + {0x34, 0x06}, + {0x35, 0x04}, + + //Out1 D-LPF th + {0x36, 0x70}, + {0x37, 0x18}, + {0x38, 0x65}, + {0x39, 0x09}, + {0x3a, 0x06}, + {0x3b, 0x04}, + + //Indoor D-LPF th + {0x3c, 0x80}, + {0x3d, 0x18}, + {0x3e, 0x80}, + {0x3f, 0x0c}, + {0x40, 0x09}, + {0x41, 0x06}, + + {0x42, 0x80}, + {0x43, 0x18}, + {0x44, 0x80}, + {0x45, 0x12}, + {0x46, 0x10}, + {0x47, 0x10}, + {0x48, 0x90}, + {0x49, 0x40}, + {0x4a, 0x80}, + {0x4b, 0x13}, + {0x4c, 0x10}, + {0x4d, 0x11}, + {0x4e, 0x80}, + {0x4f, 0x30}, + {0x50, 0x80}, + {0x51, 0x13}, + {0x52, 0x10}, + {0x53, 0x13}, + {0x54, 0x11}, + {0x55, 0x17}, + {0x56, 0x20}, + {0x57, 0x20}, + {0x58, 0x20}, + {0x59, 0x30}, + {0x5a, 0x18}, + {0x5b, 0x00}, + {0x5c, 0x00}, + {0x60, 0x3f}, + {0x62, 0x50}, + {0x70, 0x06}, + + //Page 12 + {0x03, 0x12}, + {0x20, 0x0f}, + {0x21, 0x0f}, + {0x25, 0x30}, + {0x28, 0x00}, + {0x29, 0x00}, + {0x2a, 0x00}, + {0x30, 0x50}, + {0x31, 0x18}, + {0x32, 0x32}, + {0x33, 0x40}, + {0x34, 0x50}, + {0x35, 0x70}, + {0x36, 0xa0}, + + //Out2 th + {0x40, 0xa0}, + {0x41, 0x40}, + {0x42, 0xa0}, + {0x43, 0x90}, + {0x44, 0x90}, + {0x45, 0x80}, + + //Out1 th + {0x46, 0xb0}, + {0x47, 0x55}, + {0x48, 0xa0}, + {0x49, 0x90}, + {0x4a, 0x90}, + {0x4b, 0x80}, + + //In door th + {0x4c, 0xb0}, + {0x4d, 0x40}, + {0x4e, 0x90}, + {0x4f, 0x90}, + {0x50, 0xe6}, + {0x51, 0x80}, + + //Dark1 th + {0x52, 0xb0}, + {0x53, 0x60}, + {0x54, 0xc0}, + {0x55, 0xc0}, + {0x56, 0xc0}, + {0x57, 0x80}, + + //Dark2 th + {0x58, 0x90}, + {0x59, 0x40}, + {0x5a, 0xd0}, + {0x5b, 0xd0}, + {0x5c, 0xe0}, + {0x5d, 0x80}, + + //Dark3 th + {0x5e, 0x88}, + {0x5f, 0x40}, + {0x60, 0xe0}, + {0x61, 0xe6}, + {0x62, 0xe6}, + {0x63, 0x80}, + + {0x70, 0x15}, + {0x71, 0x01}, + + {0x72, 0x18}, + {0x73, 0x01}, + + {0x74, 0x25}, + {0x75, 0x15}, + {0x80, 0x30}, + {0x81, 0x50}, + {0x82, 0x80}, + {0x85, 0x1a}, + {0x88, 0x00}, + {0x89, 0x00}, + {0x90, 0x5d}, + + {0xc5, 0x30}, + {0xc6, 0x2a}, + + {0xD0, 0x0c}, + {0xD1, 0x80}, + {0xD2, 0x67}, + {0xD3, 0x00}, + {0xD4, 0x00}, + {0xD5, 0x02}, + {0xD6, 0xff}, + {0xD7, 0x18}, + {0x3b, 0x06}, + {0x3c, 0x06}, + + {0xc5, 0x30}, + {0xc6, 0x2a}, + + //Page 13 + {0x03, 0x13}, + {0x10, 0xcb}, + {0x11, 0x7b}, + {0x12, 0x07}, + {0x14, 0x00}, + + {0x20, 0x15}, + {0x21, 0x13}, + {0x22, 0x33}, + {0x23, 0x04}, + {0x24, 0x09}, + {0x25, 0x08}, + {0x26, 0x18}, + {0x27, 0x30}, + {0x29, 0x12}, + {0x2a, 0x50}, + + //Low clip th + {0x2b, 0x06}, + {0x2c, 0x06}, + {0x25, 0x08}, + {0x2d, 0x0c}, + {0x2e, 0x12}, + {0x2f, 0x12}, + + //Out2 Edge + {0x50, 0x10}, + {0x51, 0x14}, + {0x52, 0x10}, + {0x53, 0x0c}, + {0x54, 0x0f}, + {0x55, 0x0c}, + + //Out1 Edge + {0x56, 0x10}, + {0x57, 0x13}, + {0x58, 0x10}, + {0x59, 0x0c}, + {0x5a, 0x0f}, + {0x5b, 0x0c}, + + //Indoor Edge + {0x5c, 0x0a}, + {0x5d, 0x0b}, + {0x5e, 0x0a}, + {0x5f, 0x08}, + {0x60, 0x09}, + {0x61, 0x08}, + + //Dark1 Edge + {0x62, 0x08}, + {0x63, 0x08}, + {0x64, 0x08}, + {0x65, 0x06}, + {0x66, 0x06}, + {0x67, 0x06}, + + //Dark2 Edge + {0x68, 0x07}, + {0x69, 0x07}, + {0x6a, 0x07}, + {0x6b, 0x05}, + {0x6c, 0x05}, + {0x6d, 0x05}, + + //Dark3 Edge + {0x6e, 0x07}, + {0x6f, 0x07}, + {0x70, 0x07}, + {0x71, 0x05}, + {0x72, 0x05}, + {0x73, 0x05}, + + //2DY + {0x80, 0xfd}, + {0x81, 0x1f}, + {0x82, 0x05}, + {0x83, 0x01}, + + {0x90, 0x15}, + {0x91, 0x15}, + {0x92, 0x33}, + {0x93, 0x30}, + {0x94, 0x03}, + {0x95, 0x14}, + {0x97, 0x30}, + {0x99, 0x30}, + + {0xa0, 0x04}, + {0xa1, 0x05}, + {0xa2, 0x04}, + {0xa3, 0x05}, + {0xa4, 0x07}, + {0xa5, 0x08}, + {0xa6, 0x07}, + {0xa7, 0x08}, + {0xa8, 0x07}, + {0xa9, 0x08}, + {0xaa, 0x07}, + {0xab, 0x08}, + + //Out2 + {0xb0, 0x22}, + {0xb1, 0x2a}, + {0xb2, 0x28}, + {0xb3, 0x22}, + {0xb4, 0x2a}, + {0xb5, 0x28}, + + //Out1 + {0xb6, 0x22}, + {0xb7, 0x2a}, + {0xb8, 0x28}, + {0xb9, 0x22}, + {0xba, 0x2a}, + {0xbb, 0x28}, + + {0xbc, 0x17}, + {0xbd, 0x17}, + {0xbe, 0x17}, + {0xbf, 0x17}, + {0xc0, 0x17}, + {0xc1, 0x17}, + + //Dark1 + {0xc2, 0x1e}, + {0xc3, 0x12}, + {0xc4, 0x10}, + {0xc5, 0x1e}, + {0xc6, 0x12}, + {0xc7, 0x10}, + + //Dark2 + {0xc8, 0x18}, + {0xc9, 0x05}, + {0xca, 0x05}, + {0xcb, 0x18}, + {0xcc, 0x05}, + {0xcd, 0x05}, + + //Dark3 + {0xce, 0x18}, + {0xcf, 0x05}, + {0xd0, 0x05}, + {0xd1, 0x18}, + {0xd2, 0x05}, + {0xd3, 0x05}, + + //Page 14 + {0x03, 0x14}, + {0x10, 0x11}, + {0x20, 0x40}, + {0x21, 0x80}, + {0x23, 0x80}, + {0x22, 0x80}, + {0x23, 0x80}, + {0x24, 0x80}, + + {0x30, 0xc8}, + {0x31, 0x2b}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x90}, + + {0x40, 0x42}, + {0x50, 0x2d}, + {0x60, 0x28}, + {0x70, 0x2d}, + + //Page 15 + {0x03, 0x15}, + {0x10, 0x0f}, + {0x14, 0x52}, + {0x15, 0x42}, + {0x16, 0x32}, + {0x17, 0x2f}, + + //CMC + {0x30, 0x8f}, + {0x31, 0x59}, + {0x32, 0x0a}, + {0x33, 0x15}, + {0x34, 0x5b}, + {0x35, 0x06}, + {0x36, 0x07}, + {0x37, 0x40}, + {0x38, 0x86}, + + //CMC OFS + {0x40, 0x95}, + {0x41, 0x1f}, + {0x42, 0x8a}, + {0x43, 0x86}, + {0x44, 0x0a}, + {0x45, 0x84}, + {0x46, 0x87}, + {0x47, 0x9b}, + {0x48, 0x23}, + + //CMC POFS + {0x50, 0x8c}, + {0x51, 0x0c}, + {0x52, 0x00}, + {0x53, 0x07}, + {0x54, 0x17}, + {0x55, 0x9d}, + {0x56, 0x00}, + {0x57, 0x0b}, + {0x58, 0x89}, + + {0x80, 0x03}, + {0x85, 0x40}, + {0x87, 0x02}, + {0x88, 0x00}, + {0x89, 0x00}, + {0x8a, 0x00}, + + {0x03, 0x16}, + {0x10, 0x31}, + {0x18, 0x37}, + {0x19, 0x36}, + {0x1a, 0x0e}, + {0x1b, 0x01}, + {0x1c, 0xdc}, + {0x1d, 0xfe}, +/* original + {0x30, 0x00}, + {0x31, 0x06}, + {0x32, 0x1d}, + {0x33, 0x33}, + {0x34, 0x53}, + {0x35, 0x6c}, + {0x36, 0x81}, + {0x37, 0x94}, + {0x38, 0xa4}, + {0x39, 0xb3}, + {0x3a, 0xc0}, + {0x3b, 0xcb}, + {0x3c, 0xd5}, + {0x3d, 0xde}, + {0x3e, 0xe6}, + {0x3f, 0xee}, + {0x40, 0xf5}, + {0x41, 0xfc}, + {0x42, 0xff}, + + {0x50, 0x00}, + {0x51, 0x03}, + {0x52, 0x19}, + {0x53, 0x34}, + {0x54, 0x58}, + {0x55, 0x75}, + {0x56, 0x8d}, + {0x57, 0xa1}, + {0x58, 0xb2}, + {0x59, 0xbe}, + {0x5a, 0xc9}, + {0x5b, 0xd2}, + {0x5c, 0xdb}, + {0x5d, 0xe3}, + {0x5e, 0xeb}, + {0x5f, 0xf0}, + {0x60, 0xf5}, + {0x61, 0xf7}, + {0x62, 0xf8}, + + {0x70, 0x00}, + {0x71, 0x08}, + {0x72, 0x17}, + {0x73, 0x2f}, + {0x74, 0x53}, + {0x75, 0x6c}, + {0x76, 0x81}, + {0x77, 0x94}, + {0x78, 0xa4}, + {0x79, 0xb3}, + {0x7a, 0xc0}, + {0x7b, 0xcb}, + {0x7c, 0xd5}, + {0x7d, 0xde}, + {0x7e, 0xe6}, + {0x7f, 0xee}, + {0x80, 0xf4}, + {0x81, 0xfa}, + {0x82, 0xff}, +*/ + {0x30, 0x00}, + {0x31, 0x08}, + {0x32, 0x1f}, + {0x33, 0x35}, + {0x34, 0x55}, + {0x35, 0x6e}, + {0x36, 0x83}, + {0x37, 0x96}, + {0x38, 0xa6}, + {0x39, 0xb5}, + {0x3a, 0xc2}, + {0x3b, 0xcd}, + {0x3c, 0xd7}, + {0x3d, 0xe0}, + {0x3e, 0xe8}, + {0x3f, 0xf0}, + {0x40, 0xf7}, + {0x41, 0xfe}, + {0x42, 0xff}, + + {0x50, 0x00}, + {0x51, 0x05}, + {0x52, 0x1b}, + {0x53, 0x36}, + {0x54, 0x5a}, + {0x55, 0x77}, + {0x56, 0x8f}, + {0x57, 0xa3}, + {0x58, 0xb4}, + {0x59, 0xc0}, + {0x5a, 0xcb}, + {0x5b, 0xd4}, + {0x5c, 0xde}, + {0x5d, 0xe5}, + {0x5e, 0xed}, + {0x5f, 0xf2}, + {0x60, 0xf7}, + {0x61, 0xf9}, + {0x62, 0xfa}, + + {0x70, 0x00}, + {0x71, 0x0a}, + {0x72, 0x19}, + {0x73, 0x31}, + {0x74, 0x55}, + {0x75, 0x6e}, + {0x76, 0x83}, + {0x77, 0x96}, + {0x78, 0xa6}, + {0x79, 0xb5}, + {0x7a, 0xc2}, + {0x7b, 0xcd}, + {0x7c, 0xd7}, + {0x7d, 0xe0}, + {0x7e, 0xe8}, + {0x7f, 0xf0}, + {0x80, 0xf6}, + {0x81, 0xfc}, + {0x82, 0xff}, + + + {0x03, 0x17}, + {0xc4, 0x6e}, + {0xc5, 0x5c}, + + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x20, 0x01}, + {0x21, 0x30}, + {0x22, 0x10}, + {0x23, 0x00}, + {0x24, 0x04}, + + {0x28, 0xff}, + {0x29, 0xad}, + + {0x2a, 0xf0}, + {0x2b, 0x34}, + {0x30, 0x78}, + {0x2c, 0xc3}, + {0x2d, 0x5f}, + {0x2e, 0x33}, + //{0x30, 0xf8}, + {0x32, 0x03}, + {0x33, 0x2e}, + {0x34, 0x30}, + {0x35, 0xd4}, + {0x36, 0xfe}, + {0x37, 0x32}, + {0x38, 0x04}, + {0x47, 0xf0}, + + //Y_Frame TH + {0x50, 0x45}, + {0x51, 0x88}, + + {0x56, 0x10}, + {0x57, 0xb7}, + {0x58, 0x14}, + {0x59, 0x88}, + {0x5a, 0x04}, + + {0x60, 0x55}, + {0x61, 0x55}, + {0x62, 0x6a}, + {0x63, 0xa9}, + {0x64, 0x6a}, + {0x65, 0xa9}, + {0x66, 0x6a}, + {0x67, 0xa9}, + {0x68, 0x6b}, + {0x69, 0xe9}, + {0x6a, 0x6a}, + {0x6b, 0xa9}, + {0x6c, 0x6a}, + {0x6d, 0xa9}, + {0x6e, 0x55}, + {0x6f, 0x55}, + {0x70, 0x42}, + {0x71, 0xBb}, + + // haunting control + {0x76, 0x21}, + {0x77, 0x02}, + {0x78, 0x22}, + {0x79, 0x2a}, + + {0x78, 0x24}, + {0x79, 0x23}, + {0x7a, 0x23}, + {0x7b, 0x22}, + {0x7d, 0x23}, + {0x83, 0x01}, + {0x84, 0x5f}, + {0x85, 0x6c}, + {0x86, 0x02}, + {0x87, 0x00}, + {0x88, 0x05}, + {0x89, 0x7c}, + {0x8a, 0x00}, + {0x8B, 0x75}, + {0x8C, 0x00}, + {0x8D, 0x61}, + {0x8E, 0x00}, + + {0x98, 0xdc}, + {0x99, 0x45}, + {0x9a, 0x0d}, + {0x9b, 0xde}, + {0x9c, 0x08}, + {0x9d, 0x0a}, + {0x9e, 0x01}, + {0x10, 0x9c}, + {0x18, 0x30}, + {0x90, 0x0c}, + {0x91, 0x0c}, + {0x92, 0xd8}, + {0x93, 0xd0}, + + {0x9f, 0x26}, + {0xa0, 0x03}, + {0xa1, 0xa9}, + {0xa2, 0x80}, + {0xb0, 0x1d}, + {0xb1, 0x1a}, + {0xb2, 0x60}, + {0xb3, 0x1a}, + {0xb4, 0x1a}, + {0xb5, 0x44}, + {0xb6, 0x2f}, + {0xb7, 0x28}, + {0xb8, 0x25}, + {0xb9, 0x22}, + {0xba, 0x21}, + {0xbb, 0x20}, + {0xbc, 0x1f}, + {0xbd, 0x1f}, + {0xc0, 0x30}, + {0xc1, 0x20}, + {0xc2, 0x20}, + {0xc3, 0x20}, + {0xc4, 0x08}, + {0xc8, 0x60}, + {0xc9, 0x40}, + + //Page 22 + {0x03, 0x22}, + {0x10, 0x69},//lxh + {0x11, 0x2c}, + {0x19, 0x01}, + {0x20, 0x30}, + {0x21, 0x80}, + {0x23, 0x08}, + {0x24, 0x01}, + + {0x30, 0x80}, + {0x31, 0x80}, + {0x38, 0x11}, + {0x39, 0x34}, + {0x40, 0xf7}, + + {0x41, 0x77}, + {0x42, 0x55}, + {0x43, 0xf0}, + {0x44, 0x43}, + {0x45, 0x33}, + {0x46, 0x00}, + + {0x47, 0x94}, + + {0x50, 0xb2}, + {0x51, 0x81}, + {0x52, 0x98}, + + {0x80, 0x3d},//lxh + {0x81, 0x20}, + {0x82, 0x32},//lxh + + {0x83, 0x50}, + {0x84, 0x20}, + {0x85, 0x50}, + {0x86, 0x20}, + + {0x87, 0x54}, + {0x88, 0x20}, + {0x89, 0x45}, + {0x8a, 0x2a}, + + {0x8b, 0x46}, + {0x8c, 0x3f}, + {0x8d, 0x34}, + {0x8e, 0x2c}, + + {0x8f, 0x60}, + {0x90, 0x5f}, + {0x91, 0x5c}, + {0x92, 0x4C}, + {0x93, 0x41}, + {0x94, 0x3b}, + {0x95, 0x36}, + {0x96, 0x30}, + {0x97, 0x27}, + {0x98, 0x20}, + {0x99, 0x1C}, + {0x9a, 0x19}, + + {0x9b, 0x88}, + {0x9c, 0x88}, + {0x9d, 0x48}, + {0x9e, 0x38}, + {0x9f, 0x30}, + + {0xa0, 0x74}, + {0xa1, 0x35}, + {0xa2, 0xaf}, + {0xa3, 0xf7}, + + {0xa4, 0x10}, + {0xa5, 0x50}, + {0xa6, 0xc4}, + + {0xad, 0x40}, + {0xae, 0x4a}, + + {0xaf, 0x2a}, + {0xb0, 0x29}, + + {0xb1, 0x20}, + {0xb4, 0xff}, + {0xb8, 0x6b}, + {0xb9, 0x00}, + + {0x03, 0x24}, + {0x10, 0x01}, + {0x18, 0x06}, + {0x30, 0x06}, + {0x31, 0x90}, + {0x32, 0x25}, + {0x33, 0xa2}, + {0x34, 0x26}, + {0x35, 0x58}, + {0x36, 0x60}, + {0x37, 0x00}, + {0x38, 0x50}, + {0x39, 0x00}, + + {0x03, 0x20}, + {0x10, 0x9c}, + {0x03, 0x22}, + {0x10, 0xe9}, + + //Page 00 + {0x03, 0x00}, + {0x0e, 0x03}, + {0x0e, 0x73}, + + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + + {0x03, 0x00}, + {0x01, 0xf8}, + + {END_REG, END_REG}, + +}; + + +/* 1600X1200 UXGA capture */ +static struct reginfo sensor_uxga[] = +{ + {0x03, 0x00}, + //{0x11, 0xa0}, + + {0x20, 0x00}, + {0x21, 0x0a}, + {0x22, 0x00}, + {0x23, 0x0a}, + + {0x03, 0x10}, + {0x3f, 0x00}, + + //Page12 + {0x03, 0x12}, + {0x20, 0x0f}, + {0x21, 0x0f}, + {0x90, 0x5d}, + + //Page13 + {0x03, 0x13}, + {0x80, 0xfd}, + + // 1600*1200 + {0x03,0x00}, + {0x10,0x00}, + + {END_REG, END_REG}, +}; + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {END_REG, END_REG}, +}; +static struct reginfo sensor_xga[] = +{ + {0x01, 0xf8}, + {END_REG, END_REG}, +}; +/* 800X600 SVGA,30fps*/ +static struct reginfo sensor_svga[] = +{ +#if 1 + {0x03, 0x10}, + {0x3f, 0x00}, + + + //Page12 + {0x03, 0x12}, //Function + {0x20, 0x0f}, + {0x21, 0x0f}, + {0x90, 0x5d}, + + //Page13 + {0x03, 0x13}, //Function + {0x80, 0xfd}, //Function + + // 800*600 + {0x03,0x00}, + {0x10,0x91},//11 + {0x20, 0x00}, + {0x21, 0x04}, + {0x22, 0x00}, + {0x23, 0x07}, + {0x24, 0x04}, + {0x25, 0xb0}, + {0x26, 0x06}, + {0x27, 0x40}, + + {0x03, 0x20}, + {0x8b, 0x1d}, + {0x8c, 0x4c}, + {0x8d, 0x18}, + {0x8e, 0x6a}, + + {0x03, 0x20}, + {0x03, 0x20}, +#endif + {END_REG, END_REG}, +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ + {END_REG, END_REG}, +}; + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{}; + + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + + {0x00, 0x00} +}; + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + {0x03, 0x22}, + {0x10, 0x69}, + {0x80, 0x3d}, + {0x81, 0x20}, + {0x82, 0x32}, + {0x83, 0x50}, + {0x84, 0x20}, + {0x85, 0x50}, + {0x86, 0x20}, + {0x10, 0xe9}, + {END_REG, END_REG}, +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0x03, 0x22}, + {0x10, 0x69}, + {0x80, 0x49}, + {0x81, 0x20}, + {0x82, 0x24}, + {0x83, 0x50}, + {0x84, 0x45}, + {0x85, 0x24}, + {0x86, 0x1e}, + {0x10, 0xe9}, + {END_REG, END_REG}, +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + //Sunny + {0x03, 0x22}, + {0x10, 0x69}, + {0x80, 0x45}, + {0x81, 0x20}, + {0x82, 0x27}, + {0x83, 0x44}, + {0x84, 0x3f}, + {0x85, 0x29}, + {0x86, 0x23}, + {END_REG, END_REG}, +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + //incandescense + {0x03, 0x22}, + {0x10, 0x69}, + {0x80, 0x33}, + {0x81, 0x20}, + {0x82, 0x3d}, + {0x83, 0x2e}, + {0x84, 0x24}, + {0x85, 0x43}, + {0x86, 0x3d}, + {END_REG, END_REG}, + +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + //Home + {0x03, 0x22}, + {0x10, 0x69}, + {0x80, 0x45}, + {0x81, 0x20}, + {0x82, 0x2f}, + {0x83, 0x38}, + {0x84, 0x32}, + {0x85, 0x39}, + {0x86, 0x33}, + {END_REG, END_REG}, +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + {0x03, 0x10}, + {0x40, 0xa0}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + {0x03, 0x10}, + {0x40, 0x90}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + {0x03, 0x10}, + {0x40, 0x00}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + {0x03, 0x10}, + {0x40, 0x10}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + {0x03, 0x10}, + {0x40, 0x20}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + {0x03, 0x10}, + {0x40, 0x30}, + {END_REG, END_REG}, +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x00}, + {0x13, 0x00}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x03}, + {0x13, 0x02}, + {0x44, 0x80}, + {0x45, 0x80}, + {0x47, 0x7f}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x23}, + {0x13, 0x00}, + {0x44, 0x70}, + {0x45, 0x98}, + {0x47, 0x7f}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + //Negative + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x08}, + {0x13, 0x02}, + {0x14, 0x00}, + {0x44, 0x80}, + {0x45, 0x80}, + {0x47, 0x7f}, + {END_REG, END_REG}, +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + // Bluish + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x03}, + {0x13, 0x02}, + {0x44, 0xb0}, + {0x45, 0x40}, + {0x47, 0x7f}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Effect_Green[] = +{ + // Greenish + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x03}, + {0x13, 0x02}, + {0x44, 0x30}, + {0x45, 0x50}, + {0x47, 0x7f}, + {END_REG, END_REG}, +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + //-3 + +}; + +static struct reginfo sensor_Exposure1[]= +{ + //-2 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure2[]= +{ + //-0.3EV + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure3[]= +{ + //default + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure4[]= +{ + // 1 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure5[]= +{ + // 2 + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure6[]= +{ + // 3 + + {END_REG, END_REG}, +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Saturation1[]= +{ + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Saturation2[]= +{ + {END_REG, END_REG}, +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + //Contrast -3 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast1[]= +{ + //Contrast -2 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast2[]= +{ + // Contrast -1 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast3[]= +{ + //Contrast 0 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast4[]= +{ + //Contrast +1 + + {END_REG, END_REG}, +}; + + +static struct reginfo sensor_Contrast5[]= +{ + //Contrast +2 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast6[]= +{ + //Contrast +3 + + {END_REG, END_REG}, +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_MirrorOff[]= +{ + + {END_REG, END_REG}, +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_FlipOff[]= +{ + + {END_REG, END_REG}, +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_SceneNight[] = +{ + + {END_REG, END_REG}, +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Zoom1[] = +{ + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Zoom2[] = +{ + {END_REG, END_REG}, +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {END_REG, END_REG}, +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +#define COL_FMT(_name, _depth, _fourcc, _colorspace) \ + { .name = _name, .depth = _depth, .fourcc = _fourcc, \ + .colorspace = _colorspace } + +#define JPG_FMT(_name, _depth, _fourcc) \ + COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) + +static const struct soc_camera_data_format sensor_colour_formats[] = { + JPG_FMT(SENSOR_NAME_STRING(UYVY), 16, V4L2_PIX_FMT_UYVY), + JPG_FMT(SENSOR_NAME_STRING(YUYV), 16, V4L2_PIX_FMT_YUYV), +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + unsigned int pixfmt; + +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif +} + +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + u8 buf[1]; + struct i2c_msg msg[2]; + + buf[0] = reg ; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + while (regarray[i].reg != END_REG) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + //mdelay(5); + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != 0) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } + return 0; +} +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + char value; + int ret; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; +#if 1 + ret = sensor_write(client, 0x01, 0xF9); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); //delay 5 microseconds + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x04, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), value); + if (value == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), value); + ret = -ENODEV; + goto sensor_INIT_ERR; + } +#endif + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + sensor_task_lock(client,0); + //icd->user_width = SENSOR_INIT_WIDTH; + //icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + sensor->info_priv.pixfmt = SENSOR_INIT_PIXFMT; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + + return 0; +sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); + return 0; +} + +static struct reginfo sensor_power_down_sequence[]= +{ + {0x00,0x00} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = icd->user_width; + pix->height = icd->user_height; + pix->pixelformat = sensor->info_priv.pixfmt; + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_JPEG; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) { + ret = true; + } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) { + ret = true; + } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) { + ret = true; + } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) { + ret = true; + } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 720)) { + ret = true; + } else if ((f->fmt.pix.width == 1920) && (f->fmt.pix.height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + if (sensor->info_priv.pixfmt != pix->pixelformat) { + switch (pix->pixelformat) + { + case V4L2_PIX_FMT_YUYV: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_PIX_FMT_UYVY: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.pixfmt = pix->pixelformat; + + SENSOR_DG("%s Pixelformat(0x%x) set success!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } else { + SENSOR_TR("%s Pixelformat(0x%x) is invalidate!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } + } + + set_w = pix->width; + set_h = pix->height; + + if (((set_w <= 176) && (set_h <= 144)) && (sensor_qcif[0].reg != END_REG)) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && (sensor_qvga[0].reg != END_REG)) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && (sensor_cif[0].reg != END_REG)) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && (sensor_vga[0].reg != END_REG)) + { + winseqe_set_addr = sensor_vga; + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && (sensor_svga[0].reg != END_REG)) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1024) && (set_h <= 768)) && (sensor_xga[0].reg != END_REG)) + { + winseqe_set_addr = sensor_xga; + set_w = 1024; + set_h = 768; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && (sensor_sxga[0].reg != END_REG)) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else if (((set_w <= 1600) && (set_h <= 1200)) && (sensor_uxga[0].reg != END_REG)) + { + winseqe_set_addr = sensor_uxga; + set_w = 1600; + set_h = 1200; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,pix->width,pix->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + #endif + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,f) == true) { /* ddl@rock-chips.com : Video */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + pix->width = set_w; + pix->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + bool bayer = pix->pixelformat == V4L2_PIX_FMT_UYVY || + pix->pixelformat == V4L2_PIX_FMT_YUYV; + + /* + * With Bayer format enforce even side lengths, but let the user play + * with the starting pixel + */ + + if (pix->height > SENSOR_MAX_HEIGHT) + pix->height = SENSOR_MAX_HEIGHT; + else if (pix->height < SENSOR_MIN_HEIGHT) + pix->height = SENSOR_MIN_HEIGHT; + else if (bayer) + pix->height = ALIGN(pix->height, 2); + + if (pix->width > SENSOR_MAX_WIDTH) + pix->width = SENSOR_MAX_WIDTH; + else if (pix->width < SENSOR_MIN_WIDTH) + pix->width = SENSOR_MIN_WIDTH; + else if (bayer) + pix->width = ALIGN(pix->width, 2); + + return 0; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV2655 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char value; + int ret; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + ret = sensor_write(client, 0x01, 0xf9); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(5); //delay 5 microseconds + + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x04, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), value); + if (value == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), value); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + + icd->formats = sensor_colour_formats; + icd->num_formats = ARRAY_SIZE(sensor_colour_formats); + + return 0; + +sensor_video_probe_err: + + return ret; +} +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_fmt = sensor_s_fmt, + .g_fmt = sensor_g_fmt, + .try_fmt = sensor_try_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + icd->y_skip_top = 0; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("lxh@wisky.com.cn"); +MODULE_LICENSE("GPL"); + + + diff --git a/drivers/media/video/hi704.c b/drivers/media/video/hi704.c new file mode 100755 index 000000000000..0a249551ff43 --- /dev/null +++ b/drivers/media/video/hi704.c @@ -0,0 +1,2957 @@ +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_HI704 +#define SENSOR_V4L2_IDENT V4L2_IDENT_HI704 +#define SENSOR_ID 0x96 +#define SENSOR_MIN_WIDTH 176 +#define SENSOR_MIN_HEIGHT 144 +#define SENSOR_MAX_WIDTH 640 +#define SENSOR_MAX_HEIGHT 480 +#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 480 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_PIX_FMT_UYVY + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 100000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING|\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +//lxh end of reg flag +#define END_REG 0xff + +struct reginfo +{ + u8 reg; + u8 val; +}; + +/* init SVGA preview */ +static struct reginfo sensor_init_data[] = +{ + //PAGE 0 + //Image Size/Windowing/HSYNC/VSYNC[Type1] +{0x03, 0x00}, //PAGEMODE(0x03) +{0x01, 0xf1}, +{0x01, 0xf3}, //PWRCTL(0x01[P0])Bit[1]:Software Reset. +{0x01, 0xf1}, +{0x10, 0x00},//vga mode +{0x11, 0x91}, //For No Fixed Framerate Bit[2] +{0x12, 0x04}, + +{0x20, 0x00}, +{0x21, 0x04}, +{0x22, 0x00}, +{0x23, 0x04}, + +{0x24, 0x01}, +{0x25, 0xe0}, +{0x26, 0x02}, +{0x27, 0x80}, + +{0x40, 0x00}, //HBLANK: 0x70 = 112 +{0x41, 0x70}, +{0x42, 0x00}, //VBLANK: 0x40 = 64 +{0x43, 0x40}, //0x04 -> 0x40: For Max Framerate = 30fps + +//BLC +{0x80, 0x2e}, +{0x81, 0x7e}, +{0x82, 0x90}, +{0x83, 0x30}, +{0x84, 0x2c}, +{0x85, 0x4b}, +{0x89, 0x48}, + +{0x90, 0x0b}, +{0x91, 0x0b}, +{0x92, 0x48}, +{0x93, 0x48}, +{0x98, 0x38}, +{0x99, 0x40}, +{0xa0, 0x00}, +{0xa8, 0x40}, + +//PAGE 2 +//Analog Circuit +{0x03, 0x02}, +{0x13, 0x40}, +{0x14, 0x04}, +{0x1a, 0x00}, +{0x1b, 0x08}, + +{0x20, 0x33}, +{0x21, 0xaa}, +{0x22, 0xa7}, +{0x23, 0xb1}, //For Sun Pot + +{0x3b, 0x48}, + +{0x50, 0x21}, +{0x52, 0xa2}, +{0x53, 0x0a}, +{0x54, 0x30}, +{0x55, 0x10}, +{0x56, 0x0c}, +{0x59, 0x0F}, + +{0x60, 0x54}, +{0x61, 0x5d}, +{0x62, 0x56}, +{0x63, 0x5c}, +{0x64, 0x56}, +{0x65, 0x5c}, +{0x72, 0x57}, +{0x73, 0x5b}, +{0x74, 0x57}, +{0x75, 0x5b}, +{0x80, 0x02}, +{0x81, 0x46}, +{0x82, 0x07}, +{0x83, 0x10}, +{0x84, 0x07}, +{0x85, 0x10}, +{0x92, 0x24}, +{0x93, 0x30}, +{0x94, 0x24}, +{0x95, 0x30}, +{0xa0, 0x03}, +{0xa1, 0x45}, +{0xa4, 0x45}, +{0xa5, 0x03}, +{0xa8, 0x12}, +{0xa9, 0x20}, +{0xaa, 0x34}, +{0xab, 0x40}, +{0xb8, 0x55}, +{0xb9, 0x59}, +{0xbc, 0x05}, +{0xbd, 0x09}, +{0xc0, 0x5f}, +{0xc1, 0x67}, +{0xc2, 0x5f}, +{0xc3, 0x67}, +{0xc4, 0x60}, +{0xc5, 0x66}, +{0xc6, 0x60}, +{0xc7, 0x66}, +{0xc8, 0x61}, +{0xc9, 0x65}, +{0xca, 0x61}, +{0xcb, 0x65}, +{0xcc, 0x62}, +{0xcd, 0x64}, +{0xce, 0x62}, +{0xcf, 0x64}, +{0xd0, 0x53}, +{0xd1, 0x68}, + + //PAGE 10 + //Image Format, Image Effect +{0x03, 0x10}, +{0x10, 0x01},//lxh +{0x11, 0x43}, +{0x12, 0x30}, + +{0x40, 0x10},//brightness +1 +{0x41, 0x02}, +{0x48, 0x98},//contrast level +1 + +{0x50, 0x48}, + +{0x60, 0x7f}, +{0x61, 0x00}, //Use default +{0x62, 0xa0}, //SATB (1.4x) +{0x63, 0xa0}, //SATR (1.2x) +{0x64, 0x48}, //AGSAT +{0x66, 0x90}, //wht_th2 +{0x67, 0x36}, //wht_gain Dark (0.4x), Normal (0.75x) + +//LPF +{0x03, 0x11}, +{0x10, 0x25}, +{0x11, 0x1f}, + +{0x20, 0x00}, +{0x21, 0x38}, +{0x23, 0x0a}, + +{0x60, 0x10}, +{0x61, 0x82}, +{0x62, 0x00}, +{0x63, 0x83}, +{0x64, 0x83}, +{0x67, 0xF0}, +{0x68, 0x20},//30 +{0x69, 0x10}, + + //PAGE 12 + //2D +{0x03, 0x12}, + +{0x40, 0xe9}, +{0x41, 0x09}, + +{0x50, 0x18}, +{0x51, 0x24}, + +{0x70, 0x1f}, +{0x71, 0x00}, +{0x72, 0x00}, +{0x73, 0x00}, +{0x74, 0x10}, +{0x75, 0x10}, +{0x76, 0x20}, +{0x77, 0x80}, +{0x78, 0x88}, +{0x79, 0x18}, + +{0xb0, 0x7d}, + +//Edge +{0x03, 0x13}, +{0x10, 0x01}, +{0x11, 0x89}, +{0x12, 0x14}, +{0x13, 0x19}, +{0x14, 0x08}, //Test Setting +{0x20, 0x06}, //SHARP_Negative +{0x21, 0x03}, //SHARP_Positive +{0x23, 0x30}, //SHARP_DY_CTL +{0x24, 0x33}, //40->33 +{0x25, 0x08}, //SHARP_PGA_TH +{0x26, 0x18}, //Test Setting +{0x27, 0x00}, //Test Setting +{0x28, 0x08}, //Test Setting +{0x29, 0x50}, //AG_TH +{0x2a, 0xe0}, //region ratio +{0x2b, 0x10}, //Test Setting +{0x2c, 0x28}, //Test Setting +{0x2d, 0x40}, //Test Setting +{0x2e, 0x00}, //Test Setting +{0x2f, 0x00}, //Test Setting +{0x30, 0x11}, //Test Setting +{0x80, 0x03}, //SHARP2D_CTL +{0x81, 0x07}, //Test Setting +{0x90, 0x04}, //SHARP2D_SLOPE +{0x91, 0x02}, //SHARP2D_DIFF_CTL +{0x92, 0x00}, //SHARP2D_HI_CLIP +{0x93, 0x20}, //SHARP2D_DY_CTL +{0x94, 0x42}, //Test Setting +{0x95, 0x60}, //Test Setting + +//Shading +{0x03, 0x14}, +{0x10, 0x01}, +{0x20, 0x60}, //XCEN +{0x21, 0x60}, //YCEN 80 +{0x22, 0x66}, //76, 34, 2b +{0x23, 0x50}, //4b, 15, 0d +{0x24, 0x44}, //3b, 10, 0b + +//Page 15 CMC +{0x03, 0x15}, +{0x10, 0x03}, + +{0x14, 0x3c}, +{0x16, 0x2c}, +{0x17, 0x2f}, + +{0x30, 0xcb}, +{0x31, 0x61}, +{0x32, 0x16}, +{0x33, 0x23}, +{0x34, 0xce}, +{0x35, 0x2b}, +{0x36, 0x01}, +{0x37, 0x34}, +{0x38, 0x75}, + +{0x40, 0x87}, +{0x41, 0x18}, +{0x42, 0x91}, +{0x43, 0x94}, +{0x44, 0x9f}, +{0x45, 0x33}, +{0x46, 0x00}, +{0x47, 0x94}, +{0x48, 0x14}, + +//Gamma +//normal +{0x03,0x16}, +{0x30,0x00}, +{0x31,0x0a}, +{0x32,0x1b}, +{0x33,0x2e}, +{0x34,0x5c}, +{0x35,0x79}, +{0x36,0x95}, +{0x37,0xa4}, +{0x38,0xb1}, +{0x39,0xbd}, +{0x3a,0xc8}, +{0x3b,0xd9}, +{0x3c,0xe8}, +{0x3d,0xf5}, +{0x3e,0xff}, + //0930 +//{0x03,0x16}, +//{0x30,0x00}, +//{0x31,0x08}, +//{0x32,0x0e}, +//{0x33,0x1b}, +//{0x34,0x33}, +//{0x35,0x4d}, +//{0x36,0x66}, +//{0x37,0x7e}, +//{0x38,0x95}, +//{0x39,0xa9}, +//{0x3a,0xbb}, +//{0x3b,0xd7}, +//{0x3c,0xeb}, +//{0x3d,0xf7}, +//{0x3e,0xff}, + +//night mode +//{0x03,0x16}, +//{0x30,0x00}, +//{0x31,0x1c}, +//{0x32,0x2d}, +//{0x33,0x4e}, +//{0x34,0x6d}, +//{0x35,0x8b}, +//{0x36,0xa2}, +//{0x37,0xb5}, +//{0x38,0xc4}, +//{0x39,0xd0}, +//{0x3a,0xda}, +//{0x3b,0xea}, +//{0x3c,0xf4}, +//{0x3d,0xfb}, +//{0x3e,0xff}, + +//Page 17 AE +{0x03, 0x17}, +{0xc4, 0x3c}, +{0xc5, 0x32}, + +//Page 20 AE +{0x03, 0x20}, +{0x10, 0x0c}, +{0x11, 0x04}, + +{0x20, 0x01}, +{0x28, 0x27}, +{0x29, 0xa1}, + +{0x2a, 0xf0}, +{0x2b, 0x34}, +{0x2c, 0x2b}, //23->2b 2010_04_06 hhzin + +{0x30, 0xf8}, + +{0x39, 0x22}, +{0x3a, 0xde}, +{0x3b, 0x22}, //23->22 _10_04_06 hhzin +{0x3c, 0xde}, + +{0x60, 0x95}, //d5, 99 +{0x68, 0x3c}, +{0x69, 0x64}, +{0x6A, 0x28}, +{0x6B, 0xc8}, + +{0x70, 0x42},//Y Target 42 + +{0x76, 0x22}, //Unlock bnd1 +{0x77, 0x02}, //Unlock bnd2 02->a2 _10_04_06 hhzin + +{0x78, 0x12}, //Yth 1 +{0x79, 0x27}, //Yth 2 26->27 _10_04_06 hhzin +{0x7a, 0x23}, //Yth 3 + +{0x7c, 0x1d}, //1c->1d _10_04_06 hhzin +{0x7d, 0x22}, + +//50Hz +{0x83, 0x00},//ExpTime 30fps +{0x84, 0xaf}, +{0x85, 0xc8}, + +//60Hz +//{0x83, 0x00},//ExpTime 30fps +//{0x84, 0xc3}, +//{0x85, 0x50}, + +{0x86, 0x00},//ExpMin +{0x87, 0xfa}, + +//50Hz_8fps +{0x88, 0x02},//ExpMax 8fps(8fps) +{0x89, 0xbf}, +{0x8a, 0x20}, + +//50Hz_5fps +//{0x88, 0x04},//ExpMax 8fps(8fps) +//{0x89, 0x93}, +//{0x8a, 0xe0}, + +//60Hz_8fps +//{0x88, 0x02},//ExpMax 8fps(8fps) +//{0x89, 0xdc}, +//{0x8a, 0x6c}, + +{0x8b, 0x3a},//Exp100 +{0x8c, 0x98}, + +{0x8d, 0x30},//Exp120 +{0x8e, 0xd4}, + +{0x91, 0x02}, +{0x92, 0xdc}, +{0x93, 0x6c}, + +{0x94, 0x01}, //fix_step +{0x95, 0xb7}, +{0x96, 0x74}, + +{0x98, 0x8C}, +{0x99, 0x23}, + +{0x9c, 0x0b}, //4shared limit_10_04_06 hhzin +{0x9d, 0x3b}, // 0x06d3 --> 0x0b3b +{0x9e, 0x00}, //4shared Unit_10_04_06 hhzin +{0x9f, 0xfa}, // 0x01f4 --> 0xfa + +{0xb1, 0x14}, +{0xb2, 0x50}, +{0xb4, 0x14}, +{0xb5, 0x38}, +{0xb6, 0x26}, +{0xb7, 0x20}, +{0xb8, 0x1d}, +{0xb9, 0x1b}, +{0xba, 0x1a}, +{0xbb, 0x19}, +{0xbc, 0x19}, +{0xbd, 0x18}, + +{0xc0, 0x1a}, +{0xc3, 0x48}, +{0xc4, 0x48}, + + +//Page 22 AWB +{0x03, 0x22}, +{0x10, 0xe2}, +{0x11, 0x26}, +{0x21, 0x40}, + +{0x30, 0x80}, +{0x31, 0x80}, +{0x38, 0x12}, +{0x39, 0x33}, +{0x40, 0xf0}, +{0x41, 0x33}, +{0x42, 0x33}, +{0x43, 0xf3}, +{0x44, 0x55}, +{0x45, 0x44}, +{0x46, 0x02}, + +{0x80, 0x45}, +{0x81, 0x20}, +{0x82, 0x48}, +{0x83, 0x52}, //RMAX Default : 50 -> 48 -> 52 +{0x84, 0x1b}, //RMIN Default : 20 +{0x85, 0x50}, //BMAX Default : 50, 5a -> 58 -> 55 +{0x86, 0x25}, //BMIN Default : 20 +{0x87, 0x4d}, //RMAXB Default : 50, 4d +{0x88, 0x38}, //RMINB Default : 3e, 45 --> 42 +{0x89, 0x3e}, //BMAXB Default : 2e, 2d --> 30 +{0x8a, 0x29}, //BMINB Default : 20, 22 --> 26 --> 29 +{0x8b, 0x02}, //OUT TH +{0x8d, 0x22}, +{0x8e, 0x71}, + +{0x8f, 0x63}, +{0x90, 0x60}, +{0x91, 0x5c}, +{0x92, 0x56}, +{0x93, 0x52}, +{0x94, 0x4c}, +{0x95, 0x36}, +{0x96, 0x31}, +{0x97, 0x2e}, +{0x98, 0x2a}, +{0x99, 0x29}, +{0x9a, 0x26}, +{0x9b, 0x09}, + +{0x03, 0x22}, +{0x10, 0xfb}, + +//PAGE 20 +{0x03, 0x20}, +{0x10, 0x9c}, + +{0x01, 0xf0}, + +//PAGE 0 +{0x03, 0x00}, +{0x01, 0x90}, //0xf1 ->0x41 : For Preview Green/Red Line. +{0xff, 0xff} //End of Initial Setting +}; + + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ +{0x03, 0x00}, +{0x10, 0x00}, //VGA Size + +{0x20, 0x00}, +{0x21, 0x04}, + +{0x40, 0x00}, //HBLANK: 0x70 = 112 +{0x41, 0x70}, +{0x42, 0x00}, //VBLANK: 0x04 = 4 +{0x43, 0x40}, + +{0x03, 0x11}, +{0x10, 0x25}, + +{0x03, 0x20}, +{0x83, 0x00}, +{0x84, 0xaf}, +{0x85, 0x80}, +{0x86, 0x00}, +{0x87, 0xc0}, + +{0x8b, 0x3a}, +{0x8c, 0x80}, +{0x8d, 0x30}, +{0x8e, 0xc0}, + +{0x9c, 0x08}, +{0x9d, 0xa0}, +{0x9e, 0x00}, +{0x9f, 0xc0}, +{END_REG, END_REG}, +}; + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{ + {END_REG, END_REG}, +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ +{0x03, 0x00}, +{0x10, 0x01}, //QVGA Size: 0x10 -> 0x01 + +{0x20, 0x00}, +{0x21, 0x02}, + +{0x40, 0x01}, //HBLANK: 0x0158 = 344 +{0x41, 0x58}, +{0x42, 0x00}, //VBLANK: 0x14 = 20 +{0x43, 0x14}, + +{0x03, 0x11}, //QVGA Fixframerate +{0x10, 0x21}, + +{0x03, 0x20}, + +{0x83, 0x00}, +{0x84, 0xaf}, +{0x85, 0xc8}, +{0x86, 0x00}, +{0x87, 0xfa}, + +{0x8b, 0x3a}, +{0x8c, 0x98}, +{0x8d, 0x30}, +{0x8e, 0xd4}, + +{0x9c, 0x0b}, +{0x9d, 0x3b}, +{0x9e, 0x00}, +{0x9f, 0xfa}, +{END_REG, END_REG}, +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {END_REG, END_REG}, +}; + + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + + {END_REG, END_REG}, +}; + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + {0x03, 0x22}, + {0x10, 0x6a}, + {0x80, 0x48}, + {0x81, 0x20}, + {0x82, 0x40}, + {0x83, 0x58}, + {0x84, 0x10}, + {0x85, 0x70}, + {0x86, 0x10}, + {0x10, 0xea}, + {END_REG, END_REG}, +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0x03, 0x22}, + {0x10, 0x6a}, + {0x80, 0x62}, + {0x81, 0x20}, + {0x82, 0x2e}, + {0x83, 0x6d}, + {0x84, 0x65}, + {0x85, 0x30}, + {0x86, 0x25}, + {END_REG, END_REG}, +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + //Sunny + {0x03, 0x22}, + {0x10, 0x6a}, + {0x80, 0x50}, + {0x81, 0x20}, + {0x82, 0x2d}, + {0x83, 0x52}, + {0x84, 0x40}, + {0x85, 0x30}, + {0x86, 0x1c}, + {END_REG, END_REG}, +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + //Office,荧光灯 + {0x03, 0x22}, + {0x10, 0x6a}, + {0x80, 0x40}, + {0x81, 0x20}, + {0x82, 0x4f}, + {0x83, 0x44}, + {0x84, 0x3a}, + {0x85, 0x47}, + {0x86, 0x3a}, + {END_REG, END_REG}, + +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + //Home,白炽灯 + {0x03, 0x22}, + {0x10, 0x6a}, + {0x80, 0x26}, + {0x81, 0x20}, + {0x82, 0x55}, + {0x83, 0x24}, + {0x84, 0x1e}, + {0x85, 0x58}, + {0x86, 0x4a}, + {END_REG, END_REG}, +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + {0x03, 0x10}, + {0x40, 0xa0}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + {0x03, 0x10}, + {0x40, 0x90}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + {0x03, 0x10}, + {0x40, 0x00}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + {0x03, 0x10}, + {0x40, 0x10}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + {0x03, 0x10}, + {0x40, 0x20}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + {0x03, 0x10}, + {0x40, 0x30}, + {END_REG, END_REG}, +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x30}, + {0x13, 0x00}, + {0x44, 0x80}, + {0x45, 0x80}, + {0x47, 0x7f}, + {0x03, 0x13}, + {0x20, 0x06}, + {0x21, 0x04}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x30}, + {0x13, 0x00}, + {0x44, 0x80}, + {0x45, 0x80}, + {0x47, 0x7f}, + {0x03, 0x13}, + {0x20, 0x06}, + {0x21, 0x04}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x23}, + {0x13, 0x00}, + {0x44, 0x70}, + {0x45, 0x98}, + {0x47, 0x7f}, + {0x03, 0x13}, + {0x20, 0x07}, + {0x21, 0x03}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + //Negative + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x28}, + {0x13, 0x00}, + {0x44, 0x80}, + {0x45, 0x80}, + {0x47, 0x7f}, + {0x03, 0x13}, + {0x20, 0x07}, + {0x21, 0x03}, + {END_REG, END_REG}, +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + // Bluish + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x33}, + {0x13, 0x00}, + {0x44, 0xb0}, + {0x45, 0x40}, + {0x47, 0x7f}, + {0x03, 0x13}, + {0x20, 0x07}, + {0x21, 0x03}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Effect_Green[] = +{ + // Greenish + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x33}, + {0x13, 0x00}, + {0x44, 0x60}, + {0x45, 0x60}, + {0x47, 0x7f}, + {0x03, 0x13}, + {0x20, 0x07}, + {0x21, 0x03}, + {END_REG, END_REG}, +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + //-3 + +}; + +static struct reginfo sensor_Exposure1[]= +{ + //-2 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure2[]= +{ + //-0.3EV + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure3[]= +{ + //default + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure4[]= +{ + // 1 + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure5[]= +{ + // 2 + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Exposure6[]= +{ + // 3 + + {END_REG, END_REG}, +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + //-3 level + {0x03, 0x10}, + {0x62, 0x60}, + {0x63, 0x60}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Saturation1[]= +{ + //00 level + {0x03, 0x10}, + {0x62, 0x90}, + {0x63, 0x90}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Saturation2[]= +{ + //+3 level + {0x03, 0x10}, + {0x62, 0xc0}, + {0x63, 0xc0}, + {END_REG, END_REG}, +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + //Contrast -3 + {0x03, 0x10}, + {0x48, 0x54}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast1[]= +{ + //Contrast -2 + {0x03, 0x10}, + {0x48, 0x64}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast2[]= +{ + // Contrast -1 + {0x03, 0x10}, + {0x48, 0x74}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast3[]= +{ + //Contrast 0 + {0x03, 0x10}, + {0x48, 0x84}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast4[]= +{ + //Contrast +1 + {0x03, 0x10}, + {0x48, 0x94}, + {END_REG, END_REG}, +}; + + +static struct reginfo sensor_Contrast5[]= +{ + //Contrast +2 + {0x03, 0x10}, + {0x48, 0xa4}, + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Contrast6[]= +{ + //Contrast +3 + {0x03, 0x10}, + {0x48, 0xb4}, + {END_REG, END_REG}, +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_MirrorOff[]= +{ + + {END_REG, END_REG}, +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + + {END_REG, END_REG}, +}; + +static struct reginfo sensor_FlipOff[]= +{ + + {END_REG, END_REG}, +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ + +}; + +static struct reginfo sensor_SceneNight[] = +{ + +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Zoom1[] = +{ + {END_REG, END_REG}, +}; + +static struct reginfo sensor_Zoom2[] = +{ + {END_REG, END_REG}, +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {END_REG, END_REG}, +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +#define COL_FMT(_name, _depth, _fourcc, _colorspace) \ + { .name = _name, .depth = _depth, .fourcc = _fourcc, \ + .colorspace = _colorspace } + +#define JPG_FMT(_name, _depth, _fourcc) \ + COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) + +static const struct soc_camera_data_format sensor_colour_formats[] = { + JPG_FMT(SENSOR_NAME_STRING(UYVY), 16, V4L2_PIX_FMT_UYVY), + JPG_FMT(SENSOR_NAME_STRING(YUYV), 16, V4L2_PIX_FMT_YUYV), +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + unsigned int pixfmt; + +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } +#endif + return 0; +sensor_task_lock_err: + return -1; +} + +#if 0 +/* sensor register */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int ret = 0; + + ret = i2c_master_reg8_recv(client, reg, val, 1, CONFIG_SENSOR_I2C_SPEED); + + return (ret > 0)? 0 : ret; +} + +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int ret = 0; + + ret = i2c_master_reg8_send(client, reg, &val, 1, CONFIG_SENSOR_I2C_SPEED); + + return (ret > 0)? 0 : ret; +} +#else +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + u8 buf[1]; + struct i2c_msg msg[2]; + + buf[0] = reg ; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +#endif + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + while (regarray[i].reg != END_REG) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + //mdelay(5); + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != 0) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } + return 0; +} +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + char value; + int ret; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; +#if 1 + ret = sensor_write(client, 0x01, 0xF3); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); //delay 5 microseconds + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x04, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), value); + if (value == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), value); + ret = -ENODEV; + goto sensor_INIT_ERR; + } +#endif + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + sensor_task_lock(client,0); + //icd->user_width = SENSOR_INIT_WIDTH; + //icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + sensor->info_priv.pixfmt = SENSOR_INIT_PIXFMT; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + + return 0; +sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); + return 0; +} + +static struct reginfo sensor_power_down_sequence[]= +{ + {0x00,0x00} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = icd->user_width; + pix->height = icd->user_height; + pix->pixelformat = sensor->info_priv.pixfmt; + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_JPEG; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) { + ret = true; + } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) { + ret = true; + } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) { + ret = true; + } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) { + ret = true; + } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 720)) { + ret = true; + } else if ((f->fmt.pix.width == 1920) && (f->fmt.pix.height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + if (sensor->info_priv.pixfmt != pix->pixelformat) { + switch (pix->pixelformat) + { + case V4L2_PIX_FMT_YUYV: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_PIX_FMT_UYVY: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.pixfmt = pix->pixelformat; + + SENSOR_DG("%s Pixelformat(0x%x) set success!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } else { + SENSOR_TR("%s Pixelformat(0x%x) is invalidate!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } + } + + set_w = pix->width; + set_h = pix->height; + + if (((set_w <= 176) && (set_h <= 144)) && (sensor_qcif[0].reg != END_REG)) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && (sensor_qvga[0].reg != END_REG)) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && (sensor_cif[0].reg != END_REG)) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && (sensor_vga[0].reg != END_REG)) + { + winseqe_set_addr = sensor_vga; + set_w = 640; + set_h = 480; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,pix->width,pix->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + #endif + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,f) == true) { /* ddl@rock-chips.com : Video */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + pix->width = set_w; + pix->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + bool bayer = pix->pixelformat == V4L2_PIX_FMT_UYVY || + pix->pixelformat == V4L2_PIX_FMT_YUYV; + + /* + * With Bayer format enforce even side lengths, but let the user play + * with the starting pixel + */ + + if (pix->height > SENSOR_MAX_HEIGHT) + pix->height = SENSOR_MAX_HEIGHT; + else if (pix->height < SENSOR_MIN_HEIGHT) + pix->height = SENSOR_MIN_HEIGHT; + else if (bayer) + pix->height = ALIGN(pix->height, 2); + + if (pix->width > SENSOR_MAX_WIDTH) + pix->width = SENSOR_MAX_WIDTH; + else if (pix->width < SENSOR_MIN_WIDTH) + pix->width = SENSOR_MIN_WIDTH; + else if (bayer) + pix->width = ALIGN(pix->width, 2); + + return 0; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV2655 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char value; + int ret; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + ret = sensor_write(client, 0x01, 0xf3); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(5); //delay 5 microseconds + + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x04, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), value); + + if (value == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), value); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + + icd->formats = sensor_colour_formats; + icd->num_formats = ARRAY_SIZE(sensor_colour_formats); + + return 0; + +sensor_video_probe_err: + + return ret; +} +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_fmt = sensor_s_fmt, + .g_fmt = sensor_g_fmt, + .try_fmt = sensor_try_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + icd->y_skip_top = 0; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("lxh@wisky.com.cn"); +MODULE_LICENSE("GPL"); + + + diff --git a/drivers/media/video/nt99250.c b/drivers/media/video/nt99250.c new file mode 100755 index 000000000000..25c3e5f38fe9 --- /dev/null +++ b/drivers/media/video/nt99250.c @@ -0,0 +1,2842 @@ +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_NT99250 +#define SENSOR_V4L2_IDENT V4L2_IDENT_NT99250 +#define SENSOR_ID 0x0105 +#define SENSOR_MIN_WIDTH 176 +#define SENSOR_MIN_HEIGHT 144 +#define SENSOR_MAX_WIDTH 1600 +#define SENSOR_MAX_HEIGHT 1200 +#define SENSOR_INIT_WIDTH 800 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 600 +#define SENSOR_INIT_WINSEQADR sensor_svga +#define SENSOR_INIT_PIXFMT V4L2_PIX_FMT_UYVY + +#define CONFIG_SENSOR_WhiteBalance 0 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 0 +#define CONFIG_SENSOR_Scene 0 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 250000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +struct reginfo +{ + u16 reg; + u8 val; +}; + +/* init 352X288 SVGA */ +static struct reginfo sensor_init_data[] = +{ +{0x3024,0x02}, //TG //0x02 +{0x32F0,0x00},//0:UYVY 2:VYUY 1:YUYV 3:YVYU +{0x301e,0x54}, +{0x301f,0x48}, +//gamma ++++ +{0x3270,0x00}, +{0x3271,0x04}, +{0x3272,0x0E}, +{0x3273,0x28}, +{0x3274,0x3F}, +{0x3275,0x50}, +{0x3276,0x6E}, +{0x3277,0x88}, +{0x3278,0xA0}, +{0x3279,0xB3}, +{0x327A,0xD2}, +{0x327B,0xE8}, +{0x327C,0xF5}, +{0x327D,0xFF}, +{0x327E,0xFF}, +//gamma ---- +//CC ++++ +{0x3302,0x00}, +{0x3303,0x2E}, +{0x3304,0x00}, +{0x3305,0xB7}, +{0x3306,0x00}, +{0x3307,0x1A}, +{0x3308,0x07}, +{0x3309,0xE7}, +{0x330A,0x07}, +{0x330B,0x44}, +{0x330C,0x00}, +{0x330D,0xD6}, +{0x330E,0x01}, +{0x330F,0x01}, +{0x3310,0x07}, +{0x3311,0x1A}, +{0x3312,0x07}, +{0x3313,0xE5}, +//CC ---- +//LSC_+++++ +{0x3250,0x01}, +{0x3251,0x87}, +{0x3252,0x01}, +{0x3253,0x88}, +{0x3254,0x01}, +{0x3255,0x89}, +{0x3256,0x01}, +{0x3257,0x33}, +{0x3258,0x01}, +{0x3259,0x34}, +{0x325A,0x01}, +{0x325B,0x35}, +{0x325C,0x00}, +{0x325D,0x00}, +{0x325E,0x00}, +{0x325F,0x00}, +{0x3260,0x00}, +{0x3261,0x00}, +{0x3262,0x09}, +{0x3263,0x08}, +{0x3264,0x08}, +{0x3265,0x17}, +{0x3266,0x00}, +{0x3200,0x3e}, +//LSC_---- +//analog ++++ +{0x3102,0x0b}, +{0x3103,0x46}, +{0x3105,0x33}, +{0x3107,0x32}, +{0x310A,0x03}, +{0x310B,0x18}, +{0x310f,0x08}, +{0x3110,0x03}, +{0x3113,0x0F}, +{0x3119,0x17}, +{0x3114,0x03}, +{0x3117,0x03}, +{0x3118,0x01}, +{0x3380,0x03}, +//analog ---- +//DAC&DPC ++++ +{0x3044,0x02}, +{0x3045,0xd0}, +{0x3046,0x02}, +{0x3047,0xd0}, +{0x3048,0x02}, +{0x3049,0xd0}, +{0x304a,0x02}, +{0x304b,0xd0}, +{0x303e,0x02}, +{0x303f,0x2b}, +{0x3052,0x80}, +{0x3059,0x10}, +{0x305a,0x28}, +{0x305b,0x20}, +{0x305c,0x04}, +{0x305d,0x28}, +{0x305e,0x04}, +{0x305f,0x52}, +{0x3058,0x01}, +//DAC&DPC ---- +{0x3080,0x80}, +{0x3081,0x80}, +{0x3082,0x80}, +{0x3083,0x40}, +{0x3084,0x80}, +{0x3085,0x40}, +//AEC AGC ++++ +{0x32b0,0x00}, +{0x32b1,0x90}, +{0x32BB,0x0b}, +{0x32bd,0x05}, +{0x32be,0x05}, +{0x32cd,0x01}, +{0x32d3,0x13}, +{0x32d7,0x82}, +{0x32d8,0x3F}, +{0x32d9,0x18}, +{0x32c5,0x18}, +//AEC AGC ---- +{0x32f6,0x0c},//effect function +{0x3069, 0x00}, //Pix //01 :for M1002 00 :for other +{0x306d, 0x01}, //pclk //00 :for M1002 01 :for other + + //============================== + //Output size + //============================== + //[800X600] + //edge & denoise +++ + {0x3300,0x30}, + {0x3301,0x80}, + {0x3320,0x28}, + {0x3331,0x04}, + {0x3332,0x40}, + {0x3339,0x10}, + {0x333a,0x1a}, + //edge & denoise --- + //AE AWB mode ++ + {0x329C,0x4b}, + {0x32bf,0x52}, + {0x32c0,0x10}, + {0x3200,0x3e}, + {0x3201,0x3f}, + {0x32b0,0x02}, + {0x32b1,0xc0}, + //AE AWB mode --- + {0x3052,0x80}, //OB + {0x32e0,0x03}, + {0x32e1,0x20}, + {0x32e2,0x02}, + {0x32e3,0x58}, + {0x32e4,0x01}, + {0x32e5,0x00}, + {0x32e6,0x00}, + {0x32e7,0x00}, + {0x301e,0x00}, //pll + {0x301f,0x20}, //pll + {0x3022,0x25}, + {0x3023,0x64}, + {0x3002,0x00}, + {0x3003,0x04}, + {0x3004,0x00}, + {0x3005,0x04}, + {0x3006,0x06}, + {0x3007,0x43}, + {0x3008,0x04}, + {0x3009,0xb3}, + {0x300a,0x09}, + {0x300b,0x91}, + {0x300c,0x02}, + {0x300d,0x64}, + {0x300e,0x06}, + {0x300f,0x40}, + {0x3010,0x02}, + {0x3011,0x58}, + {0x32bb,0x0b}, + {0x32bc,0x3a}, + {0x32c1,0x25}, + {0x32c2,0x5c}, //7.14fps @ 48M + {0x32c8,0x62}, + {0x32c9,0x52}, + {0x32c4,0x00}, + {0x3290,0x01}, //awb init ++++ + {0x3291,0x68}, + {0x3296,0x01}, + {0x3297,0x75}, + {0x32A9,0x11}, + {0x32AA,0x01}, + {0x329b,0x01}, + {0x32a2,0x60}, + {0x32a4,0xa0}, + {0x32a6,0x60}, + {0x32a8,0xa0}, //awb init ---- + {0x3012,0x02}, //AE init +++ + {0x3013,0xae}, + {0x301d,0x08}, + {0x3201,0x7f}, //AE init --- + {0x3021,0x06}, + {0x3060,0x01}, + {0x0, 0x0}, //end flag + +}; + +/* 1600X1200 UXGA */ +static struct reginfo sensor_uxga[] = +{ + //Output format & size + {0x3300, 0x3f}, + {0x3301, 0xa0}, + {0x3331, 0x08}, + {0x3332, 0x80}, //0x20 + {0x3320, 0x20}, //0x28 + + {0x329C, 0x4b}, + {0x32bf, 0x52}, + {0x3200, 0x3e}, + + {0x32e0,0x06}, + {0x32e1,0x40}, + {0x32e2,0x04}, + {0x32e3,0xb0}, + {0x32e4,0x00}, + {0x32e5,0x00}, + {0x32e6,0x00}, + {0x32e7,0x00}, + + {0x301e, 0x00}, + {0x301f, 0x20}, + + {0x3022, 0x25}, + {0x3023, 0x24}, + + //Capture_1600x1200s + {0x3002, 0x00}, + {0x3003, 0x04}, + {0x3004, 0x00}, + {0x3005, 0x04}, + {0x3006, 0x06}, + {0x3007, 0x43}, + {0x3008, 0x00}, + {0x3009, 0xb3}, + {0x300a, 0x09}, + {0x300b, 0x82}, + {0x300c, 0x07}, + {0x300d, 0xb4}, + {0x300e, 0x06}, + {0x300f, 0x40}, + {0x3010, 0x04}, + {0x3011, 0xb0}, + + {0x32bb, 0x0b}, + //{0x32bc, 0x38}, + + {0x32c4, 0x00}, + //{0x3201, 0x3f}, + {0x3021, 0x06}, + {0x3060, 0x01}, + + {0x0, 0x0}, +}; + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {0x3300, 0x3f}, + {0x3301, 0xa0}, + {0x3331, 0x0c}, + {0x3332, 0x80}, + {0x3320, 0x20}, + {0x329C, 0x4b}, + {0x32bf, 0x52}, + {0x3200, 0x3e}, +//1280x1024 + {0x32e0, 0x05}, + {0x32e1, 0x00}, + {0x32e2, 0x04}, + {0x32e3, 0x00}, + {0x32e4, 0x00}, + {0x32e5, 0x40}, + {0x32e6, 0x00}, + {0x32e7, 0x2c}, + + {0x301e, 0x00}, + {0x3022, 0x25}, + {0x3023, 0x24}, + {0x3002, 0x00}, + {0x3003, 0x04}, + {0x3004, 0x00}, + {0x3005, 0x04}, + {0x3006, 0x06}, + {0x3007, 0x43}, + {0x3008, 0x04}, + {0x3009, 0xb3}, + {0x300a, 0x09}, + {0x300b, 0x82}, + {0x300c, 0x07}, + {0x300d, 0xb4}, + {0x300e, 0x06}, + {0x300f, 0x40}, + {0x3010, 0x04}, + {0x3011, 0xb0}, + {0x32bb, 0x0b}, + + //{0x3201, 0x7f}, + {0x3021, 0x06}, + {0x3060, 0x01}, + {0x0, 0x0}, +}; + +/* 800X600 SVGA*/ +static struct reginfo sensor_svga[] = +{ +//edge & denoise +++ +{0x3300,0x30}, +{0x3301,0x80}, +{0x3320,0x30}, +{0x3331,0x0c}, +{0x3332,0x40}, +{0x3339,0x10}, +{0x333a,0x1a}, +//edge & denoise --- +//AE AWB mode ++ +{0x329C,0x4b}, +{0x32bf,0x52}, +{0x32c0,0x10}, +{0x3200,0x3e}, +//{0x3201,0x3f}, +{0x32b0,0x02}, +{0x32b1,0xc0}, +//AE AWB mode --- +{0x3052,0x80}, //OB + {0x32e0,0x03}, + {0x32e1,0x20}, + {0x32e2,0x02}, + {0x32e3,0x58}, + {0x32e4,0x01}, + {0x32e5,0x00}, + {0x32e6,0x00}, + {0x32e7,0x00}, +{0x301e,0x00}, //pll +{0x301f,0x20}, //pll 0x20 48Mhz 0x24 32Mhz +{0x3022,0x25}, +{0x3023,0x64}, + {0x3002,0x00}, + {0x3003,0x04}, + {0x3004,0x00}, + {0x3005,0x04}, + {0x3006,0x06}, + {0x3007,0x43}, + {0x3008,0x04}, + {0x3009,0xb3}, + {0x300a,0x09}, + {0x300b,0x91}, + {0x300c,0x02}, + {0x300d,0x64}, + {0x300e,0x06}, + {0x300f,0x40}, + {0x3010,0x02}, + {0x3011,0x58}, +{0x32bb,0x0b}, +{0x32bc,0x30}, +{0x32c1,0x25}, +{0x32c2,0x5c}, //7.14fps @ 48M +//{0x32c1,0x23}, +//{0x32c2,0xd4}, //10fps @ 48M +{0x32c8,0x62}, +{0x32c9,0x52}, +{0x32c4,0x00}, +//{0x3290,0x01}, //awb init ++++ +//{0x3291,0x68}, +//{0x3296,0x01}, +//{0x3297,0x75}, +{0x32A9,0x11}, +{0x32AA,0x01}, +{0x329b,0x01}, +{0x32a2,0x60}, +{0x32a4,0xa0}, +{0x32a6,0x60}, +{0x32a8,0xa0}, //awb init ---- +//{0x3012,0x02}, //AE init +++ +//{0x3013,0xae}, +//{0x301d,0x08}, +//{0x3201,0x7f}, //AE init --- +{0x3021,0x06}, +{0x3060,0x01}, + {0x0, 0x0}, + {0x0, 0x0}, +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ +//[640X480] +//edge & denoise +++ +{0x3300,0x30}, +{0x3301,0x80}, +{0x3320,0x28}, +{0x3331,0x04}, +{0x3332,0x40}, +{0x3339,0x10}, +{0x333a,0x1a}, +//edge & denoise --- +//AE AWB mode ++ +{0x329C,0x4b}, +{0x32bf,0x52}, +{0x32c0,0x10}, +{0x3200,0x3e}, +//{0x3201,0x3f}, +{0x32b0,0x02}, +{0x32b1,0xc0}, +//AE AWB mode --- +{0x3052,0x80}, //OB +{0x32e0,0x02}, +{0x32e1,0x80}, +{0x32e2,0x01}, +{0x32e3,0xe0}, +{0x32e4,0x01}, +{0x32e5,0x81}, +{0x32e6,0x00}, +{0x32e7,0x40}, +{0x301e,0x00}, //pll +{0x301f,0x20}, //pll 0x20 48Mhz 0x24 32Mhz +{0x3022,0x25}, +{0x3023,0x64}, +{0x3002,0x00}, +{0x3003,0x04}, +{0x3004,0x00}, +{0x3005,0x04}, +{0x3006,0x06}, +{0x3007,0x43}, +{0x3008,0x04}, +{0x3009,0xb3}, +{0x300a,0x09}, +{0x300b,0x91}, +{0x300c,0x02}, +{0x300d,0x91}, +{0x300e,0x06}, +{0x300f,0x40}, +{0x3010,0x02}, +{0x3011,0x58}, +{0x32bb,0x0b}, +{0x32bc,0x30}, +//{0x32c1,0x25}, +//{0x32c2,0x5c}, //7.14fps @ 48M +{0x32c1,0x23}, +{0x32c2,0xd4}, //10fps @ 48M +{0x32c8,0x62}, +{0x32c9,0x52}, +{0x32c4,0x00}, +//{0x3290,0x01}, //awb init ++++ +//{0x3291,0x68}, +//{0x3296,0x01}, +//{0x3297,0x75}, +{0x32A9,0x11}, +{0x32AA,0x01}, +{0x329b,0x01}, +{0x32a2,0x60}, +{0x32a4,0xa0}, +{0x32a6,0x60}, +{0x32a8,0xa0}, //awb init ---- +//{0x3012,0x02}, //AE init +++ +//{0x3013,0xae}, +//{0x301d,0x08}, +//{0x3201,0x7f}, //AE init --- +{0x3021,0x06}, +{0x3060,0x01}, + {0x0, 0x0}, +}; + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{ + {0x0, 0x0}, +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ + {0x0, 0x0}, +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {0x0, 0x0}, +}; + + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + {0x32f0, 0x00}, //0:UYVY 2:VYUY 1:YUYV 3:YVYU + {0x0000, 0x00} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + {0x32F0, 0x00}, //0:UYVY 2:VYUY 1:YUYV 3:YVYU + {0x0000, 0x00} +}; + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + {0x3201, 0x3f}, //AWB auto, bit[1]:0,auto + {0x0000, 0x00} +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0x3201, 0x2f}, + {0x3290, 0x01}, + {0x3291, 0x48}, + {0x3296, 0x01}, + {0x3297, 0x58}, + {0x0000, 0x00} +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + //Sunny + {0x3201, 0x2f}, + {0x3290, 0x01}, + {0x3291, 0x38}, + {0x3296, 0x01}, + {0x3297, 0x68}, + {0x0000, 0x00} + +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + //Office + {0x3201, 0x2f}, + {0x3290, 0x01}, + {0x3291, 0x24}, + {0x3296, 0x01}, + {0x3297, 0x78}, + {0x0000, 0x00} + +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + //Home + {0x3201, 0x2f}, + {0x3290, 0x01}, + {0x3291, 0x30}, + {0x3296, 0x01}, + {0x3297, 0x70}, + {0x0000, 0x00} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + {0x32f1, 0x05}, + {0x32f2, 0x60}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + {0x32f1, 0x05}, + {0x32f2, 0x70}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + {0x32f1, 0x05}, + {0x32f2, 0x80}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + {0x32f1, 0x05}, + {0x32f2, 0x90}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + {0x32f1, 0x05}, + {0x32f2, 0xa0}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + {0x32f1, 0x05}, + {0x32f2, 0xb0}, + {0x0000, 0x00} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0x32f1, 0x00}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0x32f1, 0x01}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0x32f1, 0x02}, + {0x32f6, 0x20}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + //Negative + {0x32f1, 0x03}, + {0x32f6, 0x10}, + {0x0000, 0x00} +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + // Bluish + {0x32f1, 0x05}, + {0x32f6, 0x04}, + {0x32f4, 0x80}, + {0x32f6, 0x0c}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + // Greenish + {0x32f1, 0x05}, + {0x32f4, 0x60}, + {0x32f5, 0x20}, + {0x32f6, 0x0c}, + {0x0000, 0x00} +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + //-3 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure1[]= +{ + //-2 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure2[]= +{ + //-0.3EV + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure3[]= +{ + //default + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure4[]= +{ + // 1 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure5[]= +{ + // 2 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure6[]= +{ + // 3 + {0x0000, 0x00} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_Saturation1[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_Saturation2[]= +{ + {0x0000, 0x00} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + //Contrast -3 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Contrast1[]= +{ + //Contrast -2 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Contrast2[]= +{ + // Contrast -1 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Contrast3[]= +{ + //Contrast 0 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Contrast4[]= +{ + //Contrast +1 + {0x0000, 0x00} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + //Contrast +2 + {0x0000, 0x00} +}; + +static struct reginfo sensor_Contrast6[]= +{ + //Contrast +3 + {0x0000, 0x00} +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + {0x0000, 0x00} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_FlipOff[]= +{ + {0x0000, 0x00} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ + {0x301e, 0x00}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_SceneNight[] = +{ + //30fps ~ 5fps night mode for 60/50Hz light environment, 24Mhz clock input,36Mzh pclk + {0x301e, 0x04}, + {0x0000, 0x00} +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0x0, 0x0}, +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0x0, 0x0}, +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +#define COL_FMT(_name, _depth, _fourcc, _colorspace) \ + { .name = _name, .depth = _depth, .fourcc = _fourcc, \ + .colorspace = _colorspace } + +#define JPG_FMT(_name, _depth, _fourcc) \ + COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) + +static const struct soc_camera_data_format sensor_colour_formats[] = { + JPG_FMT(SENSOR_NAME_STRING(UYVY), 16, V4L2_PIX_FMT_UYVY), + JPG_FMT(SENSOR_NAME_STRING(YUYV), 16, V4L2_PIX_FMT_YUYV), +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + unsigned int pixfmt; + +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + +/* sensor register write */ +static int sensor_write(struct i2c_client *client, u16 reg, u8 val) +{ + int err,cnt; + u8 buf[3]; + struct i2c_msg msg[1]; + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + buf[2] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 8; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u16 reg, u8 *val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[2]; + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + + while (regarray[i].reg != 0) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != 0) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } + return 0; +} +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + char value; + int ret,pid = 0; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + sensor_task_lock(client,1); + ret = sensor_write(client, 0x3021, 0x61); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); //delay 5 microseconds + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x307e, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + pid |= (value << 8); + + ret = sensor_read(client, 0x307f, &value); + if (ret != 0) { + SENSOR_TR("read chip id low byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + pid |= (value & 0xff); + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + #if 1 + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + #endif + + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + sensor_task_lock(client,0); + //icd->user_width = SENSOR_INIT_WIDTH; + //icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + sensor->info_priv.pixfmt = SENSOR_INIT_PIXFMT; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + + return 0; +sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + //u8 reg_val; + + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); + return 0; +} + +static struct reginfo sensor_power_down_sequence[]= +{ + //{0x30ab, 0x00}, + //{0x30ad, 0x0a}, + //{0x30ae,0x27}, + //{0x363b,0x01}, + {0x00,0x00} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = icd->user_width; + pix->height = icd->user_height; + pix->pixelformat = sensor->info_priv.pixfmt; + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_JPEG; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) { + ret = true; + } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) { + ret = true; + } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) { + ret = true; + } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) { + ret = true; + } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 720)) { + ret = true; + } else if ((f->fmt.pix.width == 1920) && (f->fmt.pix.height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + char readval; + int ret=0, set_w,set_h; + +u16 AE_reg, AGC_reg; + u8 temp_reg12,temp_reg13; + u16 shutter,reg_1, reg; + + //turn on scaler for preivew + sensor_read(client ,0x3201, ®_1); + sensor_write(client, 0x3201, (reg_1|0x40) ); + //for preview + sensor_read(client ,0x32f1, ®); + sensor_write(client, 0x32f1, (reg|0x10) ); + + #if 0 //preview_fastmode + // turn off AE for preview + sensor_read(client ,0x3201, &AE_reg); + sensor_write(client, 0x3201, (AE_reg|0x20) ); + // turn off AGC for preview + sensor_read(client ,0x32bb, &AGC_reg); + sensor_write(client, 0x32bb, (AGC_reg|0x01) ); + + sensor_read(client, 0x3012, &temp_reg12); + sensor_read(client, 0x3013, &temp_reg13); + shutter = (temp_reg13 & 0x00FF) | (temp_reg12 << 8); + #endif + if (sensor->info_priv.pixfmt != pix->pixelformat) { + switch (pix->pixelformat) + { + case V4L2_PIX_FMT_YUYV: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_PIX_FMT_UYVY: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.pixfmt = pix->pixelformat; + + SENSOR_DG("%s Pixelformat(0x%x) set success!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } else { + SENSOR_TR("%s Pixelformat(0x%x) is invalidate!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } + } + + set_w = pix->width; + set_h = pix->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + winseqe_set_addr = sensor_vga; + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else if (((set_w <= 1600) && (set_h <= 1200)) && sensor_uxga[0].reg) + { + winseqe_set_addr = sensor_uxga; + set_w = 1600; + set_h = 1200; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + ret = -1; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,pix->width,pix->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if ((set_w <= 640) && (set_h <= 480)) + { + shutter = shutter; + } + else + { + //for capture + sensor_read(client ,0x32f1, ®); + sensor_write(client, 0x32f1, (reg&(~0x10)) ); + if ((set_w <= 1600) && (set_h <= 1200)) + { + //turn off scaler for UXGA capture + sensor_read(client ,0x3201, ®_1); + sensor_write(client, 0x3201, (reg_1&(~0x40)) ); + } + #if 0 //preview_fastmode + // turn off AE + sensor_read(client ,0x3201, &AE_reg); + sensor_write(client, 0x3201, (AE_reg&(~0x20)) ); + // turn off AGC + sensor_read(client ,0x32bb, &AGC_reg); + sensor_write(client, 0x32bb, (AGC_reg&(~0x01)) ); + if ((set_w <= 800) && (set_h <= 600)) + { + shutter = shutter*1984/2434; + } + else if ((set_w <= 2434) && (set_h <= 1024)) + { + shutter = shutter*1984/2434; + } + else if ((set_w <= 1600) && (set_h <= 1200)) + { + shutter = shutter*1984/2434; + } + if (shutter < 1) + { + shutter = 1; + } + sensor_write(client, 0x3012, sizeof((shutter >> 8) & 0xff) ); + sensor_write(client, 0x3013, sizeof(shutter & 0xFF) ); + #endif + } + mdelay(250); + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + pix->width = set_w; + pix->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + bool bayer = pix->pixelformat == V4L2_PIX_FMT_UYVY || + pix->pixelformat == V4L2_PIX_FMT_YUYV; + + /* + * With Bayer format enforce even side lengths, but let the user play + * with the starting pixel + */ + + if (pix->height > SENSOR_MAX_HEIGHT) + pix->height = SENSOR_MAX_HEIGHT; + else if (pix->height < SENSOR_MIN_HEIGHT) + pix->height = SENSOR_MIN_HEIGHT; + else if (bayer) + pix->height = ALIGN(pix->height, 2); + + if (pix->width > SENSOR_MAX_WIDTH) + pix->width = SENSOR_MAX_WIDTH; + else if (pix->width < SENSOR_MIN_WIDTH) + pix->width = SENSOR_MIN_WIDTH; + else if (bayer) + pix->width = ALIGN(pix->width, 2); +/*not support 720p video*/ + if(pix->height == 720 && pix->width == 1280){ + pix->height = 480; + pix->width = 640; + } + return 0; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV2655 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char value; + int ret,pid = 0; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + ret = sensor_write(client, 0x3021, 0x61); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(5); //delay 5 microseconds + + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x307e, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + pid |= (value << 8); + + ret = sensor_read(client, 0x307f, &value); + if (ret != 0) { + SENSOR_TR("read chip id low byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + pid |= (value & 0xff); + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + icd->formats = sensor_colour_formats; + icd->num_formats = ARRAY_SIZE(sensor_colour_formats); + + return 0; + +sensor_video_probe_err: + + return ret; +} +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_fmt = sensor_s_fmt, + .g_fmt = sensor_g_fmt, + .try_fmt = sensor_try_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + icd->y_skip_top = 0; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/ov3640.c b/drivers/media/video/ov3640.c index 8fca3208ea51..51f16390be05 100755 --- a/drivers/media/video/ov3640.c +++ b/drivers/media/video/ov3640.c @@ -16,11 +16,21 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #include #include #include - - #include #include #include +#include +#include "ov3640.h" + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) #define _CONS(a,b) a##b #define CONS(a,b) _CONS(a,b) @@ -29,8 +39,11 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #define _STR(x) __STR(x) #define STR(x) _STR(x) +#define MIN(x,y) ((xy) ? x: y) + /* Sensor Driver Configuration */ -#define SENSOR_NAME ov3640 +#define SENSOR_NAME RK29_CAM_SENSOR_OV3640 #define SENSOR_V4L2_IDENT V4L2_IDENT_OV3640 #define SENSOR_ID 0x364c #define SENSOR_MIN_WIDTH 176 @@ -49,33 +62,23 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #define CONFIG_SENSOR_Effect 1 #define CONFIG_SENSOR_Scene 1 #define CONFIG_SENSOR_DigitalZoom 0 -#define CONFIG_SENSOR_Focus 0 #define CONFIG_SENSOR_Exposure 0 -#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Flash 1 #define CONFIG_SENSOR_Mirror 0 #define CONFIG_SENSOR_Flip 0 -#define CONFIG_SENSOR_I2C_SPEED 200000 /* Hz */ - -#define CONFIG_SENSOR_TR 1 -#define CONFIG_SENSOR_DEBUG 1 - -#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) -#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) - -#define MIN(x,y) ((xy) ? x: y) - -#if (CONFIG_SENSOR_TR) - #define SENSOR_TR(format, ...) printk(format, ## __VA_ARGS__) - #if (CONFIG_SENSOR_DEBUG) - #define SENSOR_DG(format, ...) printk(format, ## __VA_ARGS__) - #else - #define SENSOR_DG(format, ...) - #endif +#ifdef CONFIG_OV3640_AUTOFOCUS +#define CONFIG_SENSOR_Focus 1 +#include "ov3640_af_firmware.c" #else - #define SENSOR_TR(format, ...) +#define CONFIG_SENSOR_Focus 0 #endif +#define CONFIG_SENSOR_I2C_SPEED 100000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + + #define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) @@ -89,15 +92,105 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #define COLOR_TEMPERATURE_HOME_DN 2500 #define COLOR_TEMPERATURE_HOME_UP 3500 -struct reginfo -{ - u16 reg; - u8 val; -}; +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +#define SENSOR_AF_IS_ERR (0x00<<0) +#define SENSOR_AF_IS_OK (0x01<<0) + +#if CONFIG_SENSOR_Focus +#define SENSOR_AF_MODE_INFINITY 0 +#define SENSOR_AF_MODE_MACRO 1 +#define SENSOR_AF_MODE_FIXED 2 +#define SENSOR_AF_MODE_AUTO 3 +#define SENSOR_AF_MODE_CONTINUOUS 4 +#define SENSOR_AF_MODE_CLOSE 5 + +#endif + +#define VCM_FIRMWARE 1 + +#define VCM_STARTADDR 0x8000 + +#define S_IDLE 0x00 +#if (VCM_FIRMWARE==1) +#define S_FOCUSING 0x01 +#define S_FOCUSED 0x02 +#define S_CAPTURE 0x12 +#define STA_FOCUS 0x3f07 +#elif (VCM_FIRMWARE==2) +#define S_FOCUSING 0x01 +#define S_FOCUSED 0x02 +#define S_CAPTURE 0x12 +#define STA_FOCUS 0x3f01 +#else +#define S_FOCUSING 0x65 +#define S_FOCUSED 0x46 +#define S_CAPTURE 0x47 +#define STA_FOCUS 0x3f01 +#endif + + +#if CONFIG_SENSOR_Focus +/* ov3640 VCM Command and Status Registers */ +#define CMD_MAIN_Reg 0x3F00 +#define CMD_TAG_Reg 0x3F01 +#define CMD_PARA0_Reg 0x3F05 +#define CMD_PARA1_Reg 0x3F04 +#define CMD_PARA2_Reg 0x3F03 +#define CMD_PARA3_Reg 0x3F02 +#define STA_ZONE_Reg 0x3F06 +#define STA_FOCUS_Reg 0x3F07 + +/* ov3640 VCM Command */ +#define OverlayEn_Cmd 0x01 +#define OverlayDis_Cmd 0x02 +#define SingleFocus_Cmd 0x03 +#define ConstFocus_Cmd 0x04 +#define StepMode_Cmd 0x05 +#define PauseFocus_Cmd 0x06 +#define ReturnIdle_Cmd 0x08 +#define SetZone_Cmd 0x10 +#define UpdateZone_Cmd 0x12 +#define SetMotor_Cmd 0x20 + +/* ov3640 Focus State */ +#define S_FIRWRE 0xFF +#define S_STARTUP 0xFA +#define S_ERROR 0xFE +#define S_DRVICERR 0xEE +#define S_IDLE 0x00 +#define S_FOCUSING 0x01 +#define S_FOCUSED 0x02 +#define S_CAPTURE 0x12 +#define S_STEP 0x20 + +/* ovxxxx Zone State */ +#define Zone_Is_Focused(a, zone_val) (zone_val&(1<<(a-3))) +#define Zone_Get_ID(zone_val) (zone_val&0x03) + +#define Zone_CenterMode 0x01 +#define Zone_5xMode 0x02 +#define Zone_5PlusMode 0x03 +#define Zone_4fMode 0x04 + +#define ZoneSel_Auto 0x0b +#define ZoneSel_SemiAuto 0x0c +#define ZoneSel_Manual 0x0d +#define ZoneSel_Rotate 0x0e + +/* ovxxxx Step Focus Commands */ +#define StepFocus_Near_Tag 0x01 +#define StepFocus_Far_Tag 0x02 +#define StepFocus_Furthest_Tag 0x03 +#define StepFocus_Nearest_Tag 0x04 +#define StepFocus_Spec_Tag 0x10 +#endif /* init VGA 640*480 */ static struct reginfo sensor_init_data[] = { +#if 1 {0x3078, 0x02}, {0x304d, 0x45}, {0x30a7, 0x5e}, @@ -107,7 +200,8 @@ static struct reginfo sensor_init_data[] = {0x30aa, 0x42}, {0x30b0, 0xff}, {0x30b1, 0xff}, - {0x30b2, 0x10}, + //{0x30b2, 0x10}, + {0x30b2, 0x18}, // by FAE {0x300e, 0x39}, {0x300f, 0x21}, {0x3010, 0x20}, @@ -119,6 +213,9 @@ static struct reginfo sensor_init_data[] = {0x3018, 0x48}, {0x3019, 0x40}, {0x301a, 0x82}, + + {0x30a9, 0xbd},//disable internal DVDD, by FAE. + {0x307d, 0x00}, {0x3087, 0x02}, {0x3082, 0x20}, @@ -247,13 +344,63 @@ static struct reginfo sensor_init_data[] = {0x332e, 0x04}, {0x332f, 0x06}, {0x3331, 0x03}, + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // flip && mirror ,by FAE. + {0x3090, 0xc8}, +#else +//640 480 ;XGA->XGA;; + {0x3012, 0x10}, + {0x3023, 0x06}, + {0x3026, 0x03}, + {0x3027, 0x04}, + {0x302a, 0x03}, + {0x302b, 0x10}, + {0x3075, 0x24}, + {0x300d, 0x01}, + {0x30d7, 0x90}, + {0x3069, 0x04}, + {0x303e, 0x00}, + {0x303f, 0xc0}, + {0x3302, 0xef}, + {0x335f, 0x34}, + {0x3360, 0x0c}, + {0x3361, 0x04}, + {0x3362, 0x34}, + {0x3363, 0x08}, + {0x3364, 0x04}, + {0x3403, 0x42}, + {0x3088, 0x04}, + {0x3089, 0x00}, + {0x308a, 0x03}, + {0x308b, 0x00}, + {0x300e, 0x32}, + {0x300f, 0x21}, + {0x3010, 0x20}, + {0x3011, 0x01}, + {0x304c, 0x82}, +//;XGA->VGA + {0x3302, 0xef}, + {0x335f, 0x34}, + {0x3360, 0x0c}, + {0x3361, 0x04}, + {0x3362, 0x12}, + {0x3363, 0x88}, + {0x3364, 0xe4}, + {0x3403, 0x42}, + {0x3088, 0x12}, + {0x3089, 0x80}, + {0x308a, 0x01}, + {0x308b, 0xe0}, + {0x304c, 0x85}, +#endif {0x0000 ,0x00}, }; /* 2048X1536 QXGA */ static struct reginfo sensor_qxga_preview[] = { +#if 1 {0x3012, 0x00}, {0x3366, 0x10}, {0x3020, 0x01}, @@ -291,7 +438,47 @@ static struct reginfo sensor_qxga_preview[] = {0x3010, 0x20}, {0x3011, 0x01}, {0x304c, 0x81}, - + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // flip && mirror, by FAE. + {0x3090, 0xc8}, + +#else +//[Sensor.YUV.2048x1536] XGA->QXGA + {0x3012, 0x00}, + {0x3020, 0x01}, + {0x3021, 0x1d}, + {0x3022, 0x00}, + {0x3023, 0x0a}, + {0x3024, 0x08}, + {0x3025, 0x18}, + {0x3026, 0x06}, + {0x3027, 0x0c}, + {0x302a, 0x06}, + {0x302b, 0x20}, + {0x3075, 0x44}, + {0x300d, 0x00}, + {0x30d7, 0x10}, + {0x3069, 0x44}, + {0x303e, 0x01}, + {0x303f, 0x80}, + {0x3302, 0xcf}, + {0x335f, 0x68}, + {0x3360, 0x18}, + {0x3361, 0x0c}, + {0x3362, 0x68}, + {0x3363, 0x08}, + {0x3364, 0x04}, + {0x3403, 0x42}, + {0x3088, 0x08}, + {0x3089, 0x00}, + {0x308a, 0x06}, + {0x308b, 0x00}, + {0x300e, 0x39}, + {0x300f, 0x21}, + {0x3010, 0x20}, + {0x3011, 0x01}, + {0x304c, 0x81}, +#endif {0x0000 ,0x00} }; static struct reginfo sensor_qxga_capture[] = { @@ -308,6 +495,7 @@ static struct reginfo sensor_qxga_capture[] = { {0x302a, 0x06}, {0x302b, 0x20}, {0x3075, 0x44}, + //{0x307C, 0x13}, // by FAE. {0x300d, 0x00}, {0x30d7, 0x10}, {0x3069, 0x44}, @@ -332,6 +520,10 @@ static struct reginfo sensor_qxga_capture[] = { {0x3010, 0x20}, {0x3011, 0x01}, {0x304c, 0x81}, + + //{0x307c, 0x13},// flip && mirror + {0x307c, 0x11},// flip && mirror , by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00} }; @@ -378,6 +570,9 @@ static struct reginfo sensor_uxga_preview[] = {0x308a, 0x04}, {0x308b, 0xb0}, {0x304c, 0x81},//56Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // flip && mirror, by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -396,6 +591,9 @@ static struct reginfo sensor_uxga_capture[] = {0x308a, 0x04}, {0x308b, 0xb0}, {0x304c, 0x81},//56Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror, by FAE. + {0x307c, 0x11}, + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -442,6 +640,9 @@ static struct reginfo sensor_sxga_preview[] = {0x308a, 0x03}, {0x308b, 0xc0}, {0x304c, 0x81},//56Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -460,7 +661,9 @@ static struct reginfo sensor_sxga_capture[] = {0x308a, 0x03}, {0x308b, 0xc0}, {0x304c, 0x81},//56Mhz PCLK output - + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; static struct reginfo *sensor_sxga[2] = { @@ -502,6 +705,9 @@ static struct reginfo sensor_xga_preview[] = {0x308a, 0x03}, {0x308b, 0x00}, {0x304c, 0x82},//28Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11},// by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -520,6 +726,9 @@ static struct reginfo sensor_xga_capture[] = {0x308a, 0x03}, {0x308b, 0x00}, {0x304c, 0x82},//28Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -563,6 +772,9 @@ static struct reginfo sensor_svga_preview[] = {0x308b, 0x58}, {0x304c, 0x83},//28Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // flip && mirror, by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; static struct reginfo sensor_svga_capture[] = @@ -581,6 +793,9 @@ static struct reginfo sensor_svga_capture[] = {0x308b, 0x58}, {0x304c, 0x82},//28Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // flip && mirror, by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; static struct reginfo * sensor_svga[2] = { @@ -618,13 +833,29 @@ static struct reginfo sensor_vga_preview[] = {0x3364, 0xe4}, {0x3403, 0x42}, {0x3088, 0x02}, - {0x3089, 0x80}, + {0x3089, 0x88},// 0x80, by FAE. {0x308a, 0x01}, - {0x308b, 0xe0}, - {0x304c, 0x83}, //85 + {0x308b, 0xe4},// 0xe0, by FAE. + {0x304c, 0x84}, //0x83, by FAE. + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // flip && mirror, by FAE. + {0x3090, 0xc8}, +// by FAE. +//AWB short + // {0x33a7, 0x60}, + //{0x33a8, 0x40}, + //{0x33a9, 0x68}, + //{0x332b, 0x08}, + //{0x330a, 0x22}, + + //{0x332b, 0x00}, + //{0x330a, 0x02}, +//end + {0x0000 ,0x00}, }; + static struct reginfo sensor_vga_capture[] = { {0x3302, 0xef}, @@ -640,6 +871,9 @@ static struct reginfo sensor_vga_capture[] = {0x308a, 0x01}, {0x308b, 0xe0}, {0x304c, 0x82},//14Mhz PCLK output 84 + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11},// by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -669,6 +903,7 @@ static struct reginfo sensor_cif_preview[] = {0x3010, 0x20}, {0x3011, 0x01}, //XGA->CIF(352*288) +#if 0 // by FAE. {0x3302, 0xef}, {0x335f, 0x34}, {0x3360, 0x0c}, @@ -682,6 +917,24 @@ static struct reginfo sensor_cif_preview[] = {0x308a, 0x01}, {0x308b, 0x20}, {0x304c, 0x82}, //89 +#else + {0x3302, 0xef}, + {0x335f, 0x34}, + {0x3360, 0x0c}, + {0x3361, 0x04}, + {0x3362, 0x11}, + {0x3363, 0x68}, //? + {0x3364, 0x24},//? + {0x3403, 0x42}, + {0x3088, 0x01}, + {0x3089, 0x68}, + {0x308a, 0x01}, + {0x308b, 0x24}, + {0x304c, 0x85}, //89 +#endif + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // flip && mirror, by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -700,6 +953,9 @@ static struct reginfo sensor_cif_capture[] = {0x308a, 0x01}, {0x308b, 0x20}, {0x304c, 0x84},//14Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11},//by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -742,6 +998,9 @@ static struct reginfo sensor_qvga_preview[] = {0x308a, 0x00}, {0x308b, 0xf0}, {0x304c, 0x89},//14Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; @@ -761,6 +1020,9 @@ static struct reginfo sensor_qvga_capture[] = {0x308b, 0xf0}, {0x304c, 0x84},//14Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11},// by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; static struct reginfo *sensor_qvga[2] = { @@ -802,7 +1064,9 @@ static struct reginfo sensor_qcif_preview[] = {0x308a, 0x00}, {0x308b, 0x90}, {0x304c, 0x82},//14Mhz PCLK output 89 - + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11},// by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; static struct reginfo sensor_qcif_capture[] = @@ -821,6 +1085,9 @@ static struct reginfo sensor_qcif_capture[] = {0x308b, 0x90}, {0x304c, 0x84},//14Mhz PCLK output + //{0x307c, 0x13}, // flip && mirror + {0x307c, 0x11}, // by FAE. + {0x3090, 0xc8}, {0x0000 ,0x00}, }; static struct reginfo *sensor_qcif[2] = { @@ -1636,6 +1903,26 @@ static const struct v4l2_queryctrl sensor_controls[] = .step = 1, .default_value = 125, }, + { + .id = V4L2_CID_FOCUS_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Focus Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, +#if 0 //IF CONTINOUS IS SUPPORT, SET TO 1 + { + .id = V4L2_CID_FOCUS_CONTINUOUS, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Focus Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, +#endif #endif #if CONFIG_SENSOR_Flash @@ -1661,7 +1948,9 @@ static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); static int sensor_resume(struct soc_camera_device *icd); static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); -static int sensor_set_flashLed(struct soc_camera_device *icd, int value); +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_deactivate(struct i2c_client *client); static struct soc_camera_ops sensor_ops = { @@ -1686,6 +1975,19 @@ static const struct soc_camera_data_format sensor_colour_formats[] = { JPG_FMT(SENSOR_NAME_STRING(YUYV), 16, V4L2_PIX_FMT_YUYV), JPG_FMT(SENSOR_NAME_STRING(YUYV), 16, V4L2_PIX_FMT_YUYV), }; + +enum sensor_work_state +{ + sensor_work_ready = 0, + sensor_working, +}; +struct sensor_work +{ + struct i2c_client *client; + struct delayed_work dwork; + enum sensor_work_state state; +}; + typedef struct sensor_info_priv_s { int whiteBalance; @@ -1696,12 +1998,18 @@ typedef struct sensor_info_priv_s int scene; int digitalzoom; int focus; + int auto_focus; + int affm_reinit; int flash; int exposure; + bool snap2preview; + bool video2preview; unsigned char mirror; /* HFLIP */ unsigned char flip; /* VFLIP */ unsigned int winseqe_cur_addr; unsigned int pixfmt; + unsigned int enable; + unsigned int funmodule_state; } sensor_info_priv_t; struct sensor @@ -1709,7 +2017,15 @@ struct sensor struct v4l2_subdev subdev; struct i2c_client *client; sensor_info_priv_t info_priv; + struct workqueue_struct *sensor_wq; + struct sensor_work sensor_wk; + struct mutex wq_lock; int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; }; static struct sensor* to_sensor(const struct i2c_client *client) @@ -1717,6 +2033,44 @@ static struct sensor* to_sensor(const struct i2c_client *client) return container_of(i2c_get_clientdata(client), struct sensor, subdev); } +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + /* sensor register write */ static int sensor_write(struct i2c_client *client, u16 reg, u8 val) { @@ -1738,13 +2092,13 @@ static int sensor_write(struct i2c_client *client, u16 reg, u8 val) cnt = 1; err = -EAGAIN; - while ((cnt--) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ err = i2c_transfer(client->adapter, msg, 1); if (err >= 0) { return 0; } else { - SENSOR_TR("\n %s write reg failed, try to write again! reg:0x%x val:0x%x ,err=%d\n",SENSOR_NAME_STRING(), reg, val,err); + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); udelay(10); } } @@ -1778,14 +2132,14 @@ static int sensor_read(struct i2c_client *client, u16 reg, u8 *val) cnt = 1; err = -EAGAIN; - while ((cnt--) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ err = i2c_transfer(client->adapter, msg, 2); if (err >= 0) { *val = buf[0]; return 0; } else { - SENSOR_TR("\n %s read reg failed, try to read again! reg:0x%x \n",SENSOR_NAME_STRING(),*val); + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); udelay(10); } } @@ -1796,12 +2150,28 @@ static int sensor_read(struct i2c_client *client, u16 reg, u8 *val) /* write a array of registers */ static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) { - int err, cnt; + int err=0, cnt; int i = 0; +#if CONFIG_SENSOR_Focus + struct sensor *sensor = to_sensor(client); +#endif +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; while (regarray[i].reg != 0) { + #if CONFIG_SENSOR_Focus + if ((regarray == sensor_af_firmware) && (sensor->info_priv.enable == 0)) { + SENSOR_DG("%s disable, Download af firmware terminated!\n",SENSOR_NAME_STRING()); + err = -EINVAL; + goto sensor_write_array_end; + } + #endif + err = sensor_write(client, regarray[i].reg, regarray[i].val); if (err < 0) { @@ -1811,14 +2181,400 @@ static int sensor_write_array(struct i2c_client *client, struct reginfo *regarra continue; } else { SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); - return -EPERM; + + err = -EPERM; + goto sensor_write_array_end; } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif } i++; } + + #if CONFIG_SENSOR_Focus + if (((regarray->reg == SEQUENCE_PROPERTY) && (regarray->val == SEQUENCE_INIT)) + || (regarray == sensor_init_data)) { + sensor->info_priv.affm_reinit = 1; + } + #endif + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +#if CONFIG_SENSOR_I2C_RDWRCHK +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != 0) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } return 0; } +#endif +#if CONFIG_SENSOR_Focus +struct af_cmdinfo +{ + char cmd_tag; + char cmd_para[4]; + char validate_bit; +}; +static int sensor_af_cmdset(struct i2c_client *client, int cmd_main, struct af_cmdinfo *cmdinfo) +{ + int i; + char read_tag=0xff,cnt; + if (cmdinfo) { + if (cmdinfo->validate_bit & 0x80) { + if (sensor_write(client, CMD_TAG_Reg, cmdinfo->cmd_tag)) { + SENSOR_TR("%s write CMD_TAG_Reg(main:0x%x tag:0x%x) error!\n",SENSOR_NAME_STRING(),cmd_main,cmdinfo->cmd_tag); + goto sensor_af_cmdset_err; + } + SENSOR_DG("%s write CMD_TAG_Reg(main:0x%x tag:0x%x) success!\n",SENSOR_NAME_STRING(),cmd_main,cmdinfo->cmd_tag); + } + for (i=0; i<4; i++) { + if (cmdinfo->validate_bit & (1<cmd_para[i])) { + SENSOR_TR("%s write CMD_PARA_Reg(main:0x%x para%d:0x%x) error!\n",SENSOR_NAME_STRING(),cmd_main,i,cmdinfo->cmd_para[i]); + goto sensor_af_cmdset_err; + } + SENSOR_DG("%s write CMD_PARA_Reg(main:0x%x para%d:0x%x) success!\n",SENSOR_NAME_STRING(),cmd_main,i,cmdinfo->cmd_para[i]); + } + } + } else { + if (sensor_write(client, CMD_TAG_Reg, 0xff)) { + SENSOR_TR("%s write CMD_TAG_Reg(main:0x%x no tag) error!\n",SENSOR_NAME_STRING(),cmd_main); + goto sensor_af_cmdset_err; + } + SENSOR_DG("%s write CMD_TAG_Reg(main:0x%x no tag) success!\n",SENSOR_NAME_STRING(),cmd_main); + } + + if (sensor_write(client, CMD_MAIN_Reg, cmd_main)) { + SENSOR_TR("%s write CMD_MAIN_Reg(main:0x%x) error!\n",SENSOR_NAME_STRING(),cmd_main); + goto sensor_af_cmdset_err; + } + + cnt = 0; + do + { + msleep(5); + if (sensor_read(client,CMD_TAG_Reg,&read_tag)){ + SENSOR_TR("%s[%d] read TAG failed\n",SENSOR_NAME_STRING(),__LINE__); + break; + } + } while((read_tag != 0x00)&& (cnt++<100)); + + SENSOR_DG("%s write CMD_MAIN_Reg(main:0x%x read tag:0x%x) success!\n",SENSOR_NAME_STRING(),cmd_main,read_tag); + return 0; +sensor_af_cmdset_err: + return -1; +} + +static int sensor_af_idlechk(struct i2c_client *client) +{ + int ret = 0; + char state,cnt; + + cnt = 0; + do + { + ret = sensor_read(client, STA_FOCUS_Reg, &state); + if (ret != 0){ + SENSOR_TR("%s[%d] read focus_status failed\n",SENSOR_NAME_STRING(),__LINE__); + ret = -1; + goto sensor_af_idlechk_end; + } + + if (state != S_IDLE) { + sensor_af_cmdset(client, ReturnIdle_Cmd, NULL); + msleep(1); + cnt++; + } + } while((state != S_IDLE)&& (cnt<100)); + + ret = (state == S_IDLE) ? 0 : -1; + +sensor_af_idlechk_end: + return ret; +} + +static int sensor_af_single(struct i2c_client *client) +{ + int ret = 0; + char state,cnt; + + if (sensor_af_idlechk(client)) + goto sensor_af_single_end; + + if (sensor_af_cmdset(client, SingleFocus_Cmd, NULL)) { + SENSOR_TR("%s single focus mode set error!\n",SENSOR_NAME_STRING()); + ret = -1; + goto sensor_af_single_end; + } + + cnt = 0; + do + { + if (cnt != 0) { + msleep(1); + } + cnt++; + ret = sensor_read(client, STA_FOCUS_Reg, &state); + if (ret != 0){ + SENSOR_TR("%s[%d] read focus_status failed\n",SENSOR_NAME_STRING(),__LINE__); + ret = -1; + goto sensor_af_single_end; + } + }while((state == S_FOCUSING) && (cnt<100)); + + if (state != S_FOCUSED) { + SENSOR_TR("%s[%d] focus state(0x%x) is error!\n",SENSOR_NAME_STRING(),__LINE__,state); + ret = -1; + goto sensor_af_single_end; + } + + //sensor_af_cmdset(client, ReturnIdle_Cmd, NULL); // by duanyp. fix af blur when taking pictures +sensor_af_single_end: + return ret; +} + +static int sensor_af_const(struct i2c_client *client) +{ + int ret = 0; + + if (sensor_af_idlechk(client)) + goto sensor_af_const_end; + + if (sensor_af_cmdset(client, ConstFocus_Cmd, NULL)) { + SENSOR_TR("%s const focus mode set error!\n",SENSOR_NAME_STRING()); + ret = -1; + goto sensor_af_const_end; + } +sensor_af_const_end: + return ret; +} +static int sensor_af_pause2capture(struct i2c_client *client) +{ + int ret = 0; + char state,cnt; + + if (sensor_af_cmdset(client, PauseFocus_Cmd, NULL)) { + SENSOR_TR("%s pause focus mode set error!\n",SENSOR_NAME_STRING()); + ret = -1; + goto sensor_af_pause_end; + } + + cnt = 0; + do + { + if (cnt != 0) { + msleep(1); + } + cnt++; + ret = sensor_read(client, STA_FOCUS_Reg, &state); + if (ret != 0){ + SENSOR_TR("%s[%d] read focus_status failed\n",SENSOR_NAME_STRING(),__LINE__); + ret = -1; + goto sensor_af_pause_end; + } + }while((state != S_CAPTURE) && (cnt<100)); + + if (state != S_CAPTURE) { + SENSOR_TR("%s[%d] focus state(0x%x) is error!\n",SENSOR_NAME_STRING(),__LINE__,state); + ret = -1; + goto sensor_af_pause_end; + } +sensor_af_pause_end: + return ret; +} +static int sensor_af_zoneupdate(struct i2c_client *client) +{ + int ret = 0; + + if (sensor_af_idlechk(client)) + goto sensor_af_zoneupdate_end; + + if (sensor_af_cmdset(client, UpdateZone_Cmd, NULL)) { + SENSOR_TR("%s update zone fail!\n",SENSOR_NAME_STRING()); + ret = -1; + goto sensor_af_zoneupdate_end; + } + +sensor_af_zoneupdate_end: + return ret; +} +static int sensor_af_init(struct i2c_client *client) +{ + int ret = 0; + char state,cnt; + + ret = sensor_write_array(client, sensor_af_firmware); + if (ret != 0) { + SENSOR_TR("%s Download firmware failed\n",SENSOR_NAME_STRING()); + ret = -1; + goto sensor_af_init_end; + } + + cnt = 0; + do + { + if (cnt != 0) { + msleep(1); + } + cnt++; + ret = sensor_read(client, STA_FOCUS_Reg, &state); + if (ret != 0){ + SENSOR_TR("%s[%d] read focus_status failed\n",SENSOR_NAME_STRING(),__LINE__); + ret = -1; + goto sensor_af_init_end; + } + }while((state == S_STARTUP) && (cnt<100)); + + if (state != S_IDLE) { + SENSOR_TR("%s focus state(0x%x) is error!\n",SENSOR_NAME_STRING(),state); + ret = -1; + goto sensor_af_init_end; + } + +sensor_af_init_end: + SENSOR_DG("%s %s ret:0x%x \n",SENSOR_NAME_STRING(),__FUNCTION__,ret); + return ret; +} + +static int sensor_af_wq_function(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct af_cmdinfo cmdinfo; + int ret=0, focus_pos = 0xfe; + + SENSOR_DG("%s %s Enter\n",SENSOR_NAME_STRING(), __FUNCTION__); + + mutex_lock(&sensor->wq_lock); + if (sensor_af_init(client)) { + sensor->info_priv.funmodule_state &= (~SENSOR_AF_IS_OK); + ret = -1; + } else { + sensor->info_priv.funmodule_state |= SENSOR_AF_IS_OK; + + switch (sensor->info_priv.auto_focus) + { + case SENSOR_AF_MODE_INFINITY: + { + focus_pos = 0x00; + } + case SENSOR_AF_MODE_MACRO: + { + if (focus_pos != 0x00) + focus_pos = 0xff; + + sensor_af_idlechk(client); + cmdinfo.cmd_tag = StepFocus_Spec_Tag; + cmdinfo.cmd_para[0] = focus_pos; + cmdinfo.validate_bit = 0x81; + ret = sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo); + break; + } + case SENSOR_AF_MODE_AUTO: + { + ret = sensor_af_single(client); + break; + } + case SENSOR_AF_MODE_CONTINUOUS: + { + ret = sensor_af_const(client); + break; + } + case SENSOR_AF_MODE_CLOSE: + { + ret = 0; + break; + } + default: + { + SENSOR_DG("%s focus mode(0x%x) is unkonwn\n",SENSOR_NAME_STRING(),sensor->info_priv.auto_focus); + goto sensor_af_wq_function_end; + } + } + + SENSOR_DG("%s sensor_af_wq_function set focus mode(0x%x) ret:0x%x\n",SENSOR_NAME_STRING(), sensor->info_priv.auto_focus,ret); + } + +sensor_af_wq_function_end: + sensor->sensor_wk.state = sensor_work_ready; + mutex_unlock(&sensor->wq_lock); + return ret; +} +static void sensor_af_workqueue(struct work_struct *work) +{ + struct sensor_work *sensor_work = container_of(work, struct sensor_work, dwork.work); + struct i2c_client *client = sensor_work->client; + + if (sensor_af_wq_function(client) < 0) { + SENSOR_TR("%s af workqueue return false\n",SENSOR_NAME_STRING()); + } +} +#endif + +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),cmd); + break; + } + } + +sensor_power_end: + return ret; +} static int sensor_init(struct v4l2_subdev *sd, u32 val) { struct i2c_client *client = sd->priv; @@ -1829,11 +2585,16 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) int ret,pid = 0; SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); - + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } /* ddl@rock-chips.com : ov3640_powerOn have hardware reset */ #if 0 /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; ret = sensor_write(client, 0x3012, 0x80); if (ret != 0) { @@ -1877,9 +2638,9 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); goto sensor_INIT_ERR; } - - icd->user_width = SENSOR_INIT_WIDTH; - icd->user_height = SENSOR_INIT_HEIGHT; + sensor_task_lock(client,0); + //icd->user_width = SENSOR_INIT_WIDTH; + //icd->user_height = SENSOR_INIT_HEIGHT; sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; sensor->info_priv.pixfmt = SENSOR_INIT_PIXFMT; @@ -1918,8 +2679,8 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ #if CONFIG_SENSOR_Focus - sensor_set_focus(); - qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + // sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE);//?,JYK if (qctrl) sensor->info_priv.focus = qctrl->default_value; #endif @@ -1931,13 +2692,28 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) sensor->info_priv.flash = qctrl->default_value; #endif - SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,icd->user_width,icd->user_height); + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); return 0; sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); return ret; } +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); + return 0; +} static struct reginfo sensor_power_down_sequence[]= { {0x361e, 0x00}, @@ -1951,56 +2727,40 @@ static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) { int ret; struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct soc_camera_link *icl; - - if (pm_msg.event == PM_EVENT_SUSPEND) - { + if (pm_msg.event == PM_EVENT_SUSPEND) { SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); ret = sensor_write_array(client, sensor_power_down_sequence) ; - if (ret != 0) - { + if (ret != 0) { SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); return ret; - } - else - { - icl = to_soc_camera_link(icd); - if (icl->power) { - ret = icl->power(icd->pdev, 0); - if (ret < 0) { - SENSOR_TR("\n %s suspend fail for turn on power!\n",__FUNCTION__); - return -EINVAL; - } + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; } } - } - else - { + } else { SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); return -EINVAL; } + return 0; } static int sensor_resume(struct soc_camera_device *icd) { - struct soc_camera_link *icl; - int ret; + int ret; - icl = to_soc_camera_link(icd); - if (icl->power) { - ret = icl->power(icd->pdev, 1); - if (ret < 0) { - SENSOR_TR("\n %s resume fail for turn on power!\n",__FUNCTION__); - return -EINVAL; - } + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; } SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); - - return 0; - + return 0; } static int sensor_set_bus_param(struct soc_camera_device *icd, @@ -2034,28 +2794,51 @@ static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) return 0; } -static int sensor_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = sd->priv; - struct soc_camera_device *icd = client->dev.platform_data; - if (!enable) { - sensor_set_flashLed(icd,0); - return 0; +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) { + ret = true; + } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) { + ret = true; + } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) { + ret = true; + } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) { + ret = true; + } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) { + ret = true; } - return 0; + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; } +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 720)) { + ret = true; + } else if ((f->fmt.pix.width == 1920) && (f->fmt.pix.height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { struct i2c_client *client = sd->priv; struct soc_camera_device *icd = client->dev.platform_data; struct sensor *sensor = to_sensor(client); struct v4l2_pix_format *pix = &f->fmt.pix; + const struct v4l2_queryctrl *qctrl; struct reginfo *winseqe_set_addr=NULL; - int ret, set_w,set_h; - int isCapture = 0; // 1--拍照序列 0--预览序列 + int ret=0, set_w,set_h; + int isCapture = 0; if (sensor->info_priv.pixfmt != pix->pixelformat) { switch (pix->pixelformat) @@ -2085,14 +2868,7 @@ static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) set_w = pix->width; set_h = pix->height; - isCapture = pix->priv; - - if(isCapture) - sensor_set_flashLed(icd,1); - - SENSOR_DG("%s %c,%c,%c,%c\n", SENSOR_NAME_STRING(), - ((pix->pixelformat) & 0xff),((pix->pixelformat>>8) & 0xff), - ((pix->pixelformat>>16) & 0xff),((pix->pixelformat>>24) & 0xff)); + isCapture = sensor_fmt_capturechk(sd, f); if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[isCapture][0].reg) { @@ -2108,6 +2884,7 @@ static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) } else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[isCapture][0].reg) { + //printk("===> isCapture: %d!\n", isCapture); winseqe_set_addr = sensor_cif[isCapture]; set_w = 352; set_h = 288; @@ -2148,17 +2925,13 @@ static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) set_w = 2048; set_h = 1536; } - else if (sensor_qcif[isCapture][0].reg) + else { - winseqe_set_addr = sensor_qcif[isCapture]; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ - set_w = 176; - set_h = 144; - } - else - { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,pix->width,pix->height); - return -EINVAL; - } + } if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { @@ -2168,23 +2941,74 @@ static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { SENSOR_DG("%s write sensor_qxga[1]\n", SENSOR_NAME_STRING()); ret = sensor_write_array(client, sensor_qxga[isCapture]); - if (ret != 0) - { - SENSOR_TR("%s write sensor_qxga[1] failed\n", SENSOR_NAME_STRING()); - return ret; - } + if (ret != 0) + { + SENSOR_TR("%s write sensor_qxga[1] failed\n", SENSOR_NAME_STRING()); + return ret; + } } - - ret = sensor_write_array(client, winseqe_set_addr); - if (ret != 0) - { - SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); - return ret; + + #if CONFIG_SENSOR_Focus + //sensor_af_idlechk(client); + if (sensor->info_priv.auto_focus == SENSOR_AF_MODE_CONTINUOUS) + { + sensor_af_idlechk(client); // by duanyp + sensor_af_cmdset(client, PauseFocus_Cmd, NULL); + } + #endif + + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + + ret = sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } else { + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,f) == true) { /* ddl@rock-chips.com : Video */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + mdelay(100); // by FAE. } - - sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; - //mdelay(250); - SENSOR_DG("\n%s..%s.. icd->width=%d..icd->height=%d..isCapture=%d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h,isCapture); } else @@ -2192,7 +3016,11 @@ static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) SENSOR_TR("\n %s .. Current Format is validate. icd->width=%d..icd->height=%d..isCapture=%d\n",SENSOR_NAME_STRING(),set_w,set_h,isCapture); } - return 0; + //add by duanyp. Improve the green phenomenon when startup camera every time. + //mdelay(500); + +sensor_s_fmt_end: + return ret; } static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) @@ -2238,58 +3066,6 @@ static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) return 0; } - - -static int sensor_set_flashLed(struct soc_camera_device *icd, int value) -{ -#if CONFIG_SENSOR_Flash - struct soc_camera_link *icl = to_soc_camera_link(icd); - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct sensor *sensor = to_sensor(client); - int ret; - - SENSOR_DG("sensor_set_flashLed - %d,%d\n", sensor->info_priv.flash,value); - - if(icl->flash_led == NULL) - { - SENSOR_TR("icl->flash_led == NULL\n "); - return -1; - } - - switch(sensor->info_priv.flash) - { - case 0: // off - { - ret = icl->flash_led(icd->pdev, 0); - break; - } - case 1: //auto - { - ret = icl->flash_led(icd->pdev,value); - break; - } - case 2: // on - { - ret = icl->flash_led(icd->pdev,1); - break; - } - default: // off - { - ret = icl->flash_led(icd->pdev,0); - break; - } - - } - - if(ret) - { - SENSOR_TR("icl->flash_led failed\n "); - } -#endif - - return 0; -} - #if CONFIG_SENSOR_Brightness static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) { @@ -2541,6 +3317,150 @@ static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4 return -EINVAL; } #endif + +#if CONFIG_SENSOR_Focus +static int sensor_set_focus_absolute(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + struct af_cmdinfo cmdinfo; + int ret = 0; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (!qctrl_info) + return -EINVAL; + + if ((sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK) && (sensor->info_priv.affm_reinit == 0)) { + if ((value >= qctrl_info->minimum) && (value <= qctrl_info->maximum)) { + + if (sensor_af_idlechk(client)) + goto sensor_set_focus_absolute_end; + + cmdinfo.cmd_tag = StepFocus_Spec_Tag; + cmdinfo.cmd_para[0] = value; + cmdinfo.validate_bit = 0x81; + ret = sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo); + //ret |= sensor_af_cmdset(client, ReturnIdle_Cmd, NULL); + SENSOR_DG("%s..%s : %d ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret); + } else { + ret = -EINVAL; + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + } + } else { + ret = -EACCES; + SENSOR_TR("\n %s..%s AF module state(0x%x, 0x%x) is error!\n",SENSOR_NAME_STRING(),__FUNCTION__, + sensor->info_priv.funmodule_state,sensor->info_priv.affm_reinit); + } + +sensor_set_focus_absolute_end: + return ret; +} +static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + struct af_cmdinfo cmdinfo; + int ret = 0; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_RELATIVE); + if (!qctrl_info) + return -EINVAL; + + if ((sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK) && (sensor->info_priv.affm_reinit == 0)) { + if ((value >= qctrl_info->minimum) && (value <= qctrl_info->maximum)) { + + if (sensor_af_idlechk(client)) + goto sensor_set_focus_relative_end; + + if (value > 0) { + cmdinfo.cmd_tag = StepFocus_Near_Tag; + } else if (value < 0) { + cmdinfo.cmd_tag = StepFocus_Far_Tag; + } + cmdinfo.validate_bit = 0x80; + ret = sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo); + + SENSOR_DG("%s..%s : %d ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret); + } else { + ret = -EINVAL; + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + } + } else { + ret = -EACCES; + SENSOR_TR("\n %s..%s AF module state(0x%x, 0x%x) is error!\n",SENSOR_NAME_STRING(),__FUNCTION__, + sensor->info_priv.funmodule_state,sensor->info_priv.affm_reinit); + } +sensor_set_focus_relative_end: + return ret; +} + +static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int ret = 0; + + if ((sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK) && (sensor->info_priv.affm_reinit == 0)) { + switch (value) + { + case SENSOR_AF_MODE_AUTO: + { + ret = sensor_af_single(client); + break; + } + + case SENSOR_AF_MODE_MACRO: + { + ret = sensor_set_focus_absolute(icd, qctrl, 0xff); + break; + } + + case SENSOR_AF_MODE_INFINITY: + { + ret = sensor_set_focus_absolute(icd, qctrl, 0x00); + break; + } + + case SENSOR_AF_MODE_CONTINUOUS: + { + ret = sensor_af_const(client); + break; + } + default: + SENSOR_TR("\n %s..%s AF value(0x%x) is error!\n",SENSOR_NAME_STRING(),__FUNCTION__,value); + break; + + } + + SENSOR_DG("%s..%s : %d ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret); + } else { + ret = -EACCES; + SENSOR_TR("\n %s..%s AF module state(0x%x, 0x%x) is error!\n",SENSOR_NAME_STRING(),__FUNCTION__, + sensor->info_priv.funmodule_state,sensor->info_priv.affm_reinit); + } + + return ret; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %d\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct i2c_client *client = sd->priv; @@ -2551,7 +3471,7 @@ static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (!qctrl) { - SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + SENSOR_TR("\n %s ioctrl id = 0x%x is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); return -EINVAL; } @@ -2612,7 +3532,7 @@ static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (!qctrl) { - SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + SENSOR_TR("\n %s ioctrl id = 0x%x is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); return -EINVAL; } @@ -2728,7 +3648,7 @@ static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_ if (!qctrl) { - SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + SENSOR_TR("\n %s ioctrl id = 0x%x is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); return -EINVAL; } @@ -2783,7 +3703,7 @@ static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_c if (!qctrl) { - SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + SENSOR_TR("\n %s ioctrl id = 0x%x is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); return -EINVAL; } @@ -2852,31 +3772,61 @@ static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_c if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) return -EINVAL; - if (ext_ctrl->value != sensor->info_priv.focus) - { - val_offset = ext_ctrl->value -sensor->info_priv.focus; - - sensor->info_priv.focus += val_offset; - } + if (sensor_set_focus_absolute(icd, qctrl,ext_ctrl->value) == 0) { + if (ext_ctrl->value == qctrl->minimum) { + sensor->info_priv.auto_focus = SENSOR_AF_MODE_INFINITY; + } else if (ext_ctrl->value == qctrl->maximum) { + sensor->info_priv.auto_focus = SENSOR_AF_MODE_MACRO; + } else { + sensor->info_priv.auto_focus = SENSOR_AF_MODE_FIXED; + } + } break; - } - case V4L2_CID_FOCUS_RELATIVE: + } + case V4L2_CID_FOCUS_RELATIVE: { - if (ext_ctrl->value) - { - sensor->info_priv.focus += ext_ctrl->value; + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; - SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); - } + sensor_set_focus_relative(icd, qctrl,ext_ctrl->value); break; } + case V4L2_CID_FOCUS_AUTO: + { + if (ext_ctrl->value == 1) { + if (sensor_set_focus_mode(icd, qctrl,SENSOR_AF_MODE_AUTO) != 0) + return -EINVAL; + sensor->info_priv.auto_focus = SENSOR_AF_MODE_AUTO; + } else if (SENSOR_AF_MODE_AUTO == sensor->info_priv.auto_focus){ + if (ext_ctrl->value == 0) + sensor->info_priv.auto_focus = SENSOR_AF_MODE_CLOSE; + } + break; + } + /* + case V4L2_CID_FOCUS_CONTINUOUS: + { + if (SENSOR_AF_MODE_CONTINUOUS != sensor->info_priv.auto_focus) { + if (ext_ctrl->value == 1) { + if (sensor_set_focus_mode(icd, qctrl,SENSOR_AF_MODE_CONTINUOUS) != 0) + return -EINVAL; + sensor->info_priv.auto_focus = SENSOR_AF_MODE_CONTINUOUS; + } + } else { + if (ext_ctrl->value == 0) + sensor->info_priv.auto_focus = SENSOR_AF_MODE_CLOSE; + } + break; + }*/ #endif #if CONFIG_SENSOR_Flash case V4L2_CID_FLASH: { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; sensor->info_priv.flash = ext_ctrl->value; - sensor_set_flashLed(icd,0); + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); break; } @@ -2938,6 +3888,54 @@ static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_control } } +static int sensor_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + #if CONFIG_SENSOR_Focus + struct soc_camera_device *icd = client->dev.platform_data; + struct v4l2_format fmt; + #endif + + if (enable == 1) { + sensor->info_priv.enable = 1; + #if CONFIG_SENSOR_Focus + fmt.fmt.pix.width = icd->user_width; + fmt.fmt.pix.height = icd->user_height; + /* If auto focus firmware haven't download success, must download firmware again when in video or preview stream on */ + if (sensor_fmt_capturechk(sd, &fmt) == false) { + if ((sensor->info_priv.affm_reinit == 1) || ((sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK)==0)) { + if (sensor->sensor_wq != NULL) { + mutex_lock(&sensor->wq_lock); + if (sensor->sensor_wk.state == sensor_working) { + SENSOR_DG("%s sensor af firmware thread is runing, Ingore current work",SENSOR_NAME_STRING()); + mutex_unlock(&sensor->wq_lock); + goto sensor_s_stream_end; + } + sensor->sensor_wk.state = sensor_working; + mutex_unlock(&sensor->wq_lock); + sensor->sensor_wk.client = client; + INIT_WORK(&(sensor->sensor_wk.dwork.work), sensor_af_workqueue); + queue_delayed_work(sensor->sensor_wq,&(sensor->sensor_wk.dwork), 0); + } + sensor->info_priv.affm_reinit = 0; + } + } + #endif + } else if (enable == 0) { + sensor->info_priv.enable = 0; + #if CONFIG_SENSOR_Focus + flush_work(&(sensor->sensor_wk.dwork.work)); + mutex_lock(&sensor->wq_lock); + sensor->sensor_wk.state = sensor_work_ready; + mutex_unlock(&sensor->wq_lock); + #endif + } + +sensor_s_stream_end: + return 0; +} + /* Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ static int sensor_video_probe(struct soc_camera_device *icd, @@ -2953,12 +3951,16 @@ static int sensor_video_probe(struct soc_camera_device *icd, to_soc_camera_host(icd->dev.parent)->nr != icd->iface) return -ENODEV; + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } /* soft reset */ ret = sensor_write(client, 0x3012, 0x80); - if (ret != 0) - { + if (ret != 0) { SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); - return -ENODEV; + ret = -ENODEV; + goto sensor_video_probe_err; } mdelay(5); //delay 5 microseconds @@ -2995,9 +3997,68 @@ static int sensor_video_probe(struct soc_camera_device *icd, return 0; sensor_video_probe_err: - return ret; } +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0,i; + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + printk("flash io:%d\n",sensor->sensor_gpio_res->gpio_flash); + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } + +sensor_ioctl_end: + return ret; + +} static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { .init = sensor_init, @@ -3006,13 +4067,14 @@ static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { .g_ext_ctrls = sensor_g_ext_controls, .s_ext_ctrls = sensor_s_ext_controls, .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, }; static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { - .s_stream = sensor_s_stream, .s_fmt = sensor_s_fmt, .g_fmt = sensor_g_fmt, .try_fmt = sensor_try_fmt, + .s_stream = sensor_s_stream, }; static struct v4l2_subdev_ops sensor_subdev_ops = { @@ -3056,12 +4118,24 @@ static int sensor_probe(struct i2c_client *client, /* Second stage probe - when a capture adapter is there */ icd->ops = &sensor_ops; icd->y_skip_top = 0; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif ret = sensor_video_probe(icd, client); - if (ret) { + if (ret < 0) { icd->ops = NULL; i2c_set_clientdata(client, NULL); kfree(sensor); + sensor = NULL; + } else { + #if CONFIG_SENSOR_Focus + sensor->sensor_wq = create_workqueue(SENSOR_NAME_STRING( wq)); + if (sensor->sensor_wq == NULL) + SENSOR_TR("%s workqueue create fail!", SENSOR_NAME_STRING( wq)); + mutex_init(&sensor->wq_lock); + sensor->sensor_wk.state = sensor_work_ready; + #endif } SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); return ret; @@ -3072,11 +4146,18 @@ static int sensor_remove(struct i2c_client *client) struct sensor *sensor = to_sensor(client); struct soc_camera_device *icd = client->dev.platform_data; + #if CONFIG_SENSOR_Focus + if (sensor->sensor_wq) { + destroy_workqueue(sensor->sensor_wq); + sensor->sensor_wq = NULL; + } + #endif + icd->ops = NULL; i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(sensor); - + sensor = NULL; return 0; } @@ -3110,6 +4191,6 @@ device_initcall_sync(sensor_mod_init); module_exit(sensor_mod_exit); MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); -MODULE_AUTHOR("srt "); +MODULE_AUTHOR("ddl "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/ov3640.h b/drivers/media/video/ov3640.h new file mode 100755 index 000000000000..3435c12c466b --- /dev/null +++ b/drivers/media/video/ov3640.h @@ -0,0 +1,26 @@ +/* + * Driver for OV5642 CMOS Image Sensor from OmniVision + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * 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 __OV3640_H__ +#define __OV3640_H__ +struct reginfo +{ + u16 reg; + u8 val; +}; + +#define SEQUENCE_INIT 0x00 +#define SEQUENCE_NORMAL 0x01 + +#define SEQUENCE_PROPERTY 0xFFFD +#define SEQUENCE_WAIT_MS 0xFFFE +#define SEQUENCE_END 0xFFFF +#endif + diff --git a/drivers/media/video/ov3640_af_firmware.c b/drivers/media/video/ov3640_af_firmware.c new file mode 100755 index 000000000000..f11019389bac --- /dev/null +++ b/drivers/media/video/ov3640_af_firmware.c @@ -0,0 +1,3477 @@ +/* + * Driver for OV5642 CMOS Image Sensor from OmniVision + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * 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. + */ + +#define VCM_DRIVER_A3907 0 +#define VCM_DRIVER_AD5820 1 +#define VCM_DRIVER_DW9710 2 +#define VCM_DRIVER VCM_DRIVER_AD5820 + + +#if (VCM_DRIVER == VCM_DRIVER_AD5820) +static struct reginfo sensor_af_firmware[ ]= +{ + {0x308c,0x00}, + {0x3104,0x02}, + {0x3105,0xff}, + {0x3106,0x00}, + {0x3107,0xff}, + {0x8000,0x02}, + {0x8001,0x00}, + {0x8002,0x06}, + {0x8003,0x02}, + {0x8004,0x07}, + {0x8005,0xa9}, + {0x8006,0x78}, + {0x8007,0x7f}, + {0x8008,0xe4}, + {0x8009,0xf6}, + {0x800a,0xd8}, + {0x800b,0xfd}, + {0x800c,0x75}, + {0x800d,0x81}, + {0x800e,0x45}, + {0x800f,0x02}, + {0x8010,0x0a}, + {0x8011,0xdf}, + {0x8012,0x32}, + {0x8013,0x02}, + {0x8014,0x00}, + {0x8015,0x12}, + {0x8016,0xe8}, + {0x8017,0x8f}, + {0x8018,0xf0}, + {0x8019,0xa4}, + {0x801a,0xcc}, + {0x801b,0x8b}, + {0x801c,0xf0}, + {0x801d,0xa4}, + {0x801e,0x2c}, + {0x801f,0xfc}, + {0x8020,0xe9}, + {0x8021,0x8e}, + {0x8022,0xf0}, + {0x8023,0xa4}, + {0x8024,0x2c}, + {0x8025,0xfc}, + {0x8026,0x8a}, + {0x8027,0xf0}, + {0x8028,0xed}, + {0x8029,0xa4}, + {0x802a,0x2c}, + {0x802b,0xfc}, + {0x802c,0xea}, + {0x802d,0x8e}, + {0x802e,0xf0}, + {0x802f,0xa4}, + {0x8030,0xcd}, + {0x8031,0xa8}, + {0x8032,0xf0}, + {0x8033,0x8b}, + {0x8034,0xf0}, + {0x8035,0xa4}, + {0x8036,0x2d}, + {0x8037,0xcc}, + {0x8038,0x38}, + {0x8039,0x25}, + {0x803a,0xf0}, + {0x803b,0xfd}, + {0x803c,0xe9}, + {0x803d,0x8f}, + {0x803e,0xf0}, + {0x803f,0xa4}, + {0x8040,0x2c}, + {0x8041,0xcd}, + {0x8042,0x35}, + {0x8043,0xf0}, + {0x8044,0xfc}, + {0x8045,0xeb}, + {0x8046,0x8e}, + {0x8047,0xf0}, + {0x8048,0xa4}, + {0x8049,0xfe}, + {0x804a,0xa9}, + {0x804b,0xf0}, + {0x804c,0xeb}, + {0x804d,0x8f}, + {0x804e,0xf0}, + {0x804f,0xa4}, + {0x8050,0xcf}, + {0x8051,0xc5}, + {0x8052,0xf0}, + {0x8053,0x2e}, + {0x8054,0xcd}, + {0x8055,0x39}, + {0x8056,0xfe}, + {0x8057,0xe4}, + {0x8058,0x3c}, + {0x8059,0xfc}, + {0x805a,0xea}, + {0x805b,0xa4}, + {0x805c,0x2d}, + {0x805d,0xce}, + {0x805e,0x35}, + {0x805f,0xf0}, + {0x8060,0xfd}, + {0x8061,0xe4}, + {0x8062,0x3c}, + {0x8063,0xfc}, + {0x8064,0x22}, + {0x8065,0x75}, + {0x8066,0xf0}, + {0x8067,0x08}, + {0x8068,0x75}, + {0x8069,0x82}, + {0x806a,0x00}, + {0x806b,0xef}, + {0x806c,0x2f}, + {0x806d,0xff}, + {0x806e,0xee}, + {0x806f,0x33}, + {0x8070,0xfe}, + {0x8071,0xcd}, + {0x8072,0x33}, + {0x8073,0xcd}, + {0x8074,0xcc}, + {0x8075,0x33}, + {0x8076,0xcc}, + {0x8077,0xc5}, + {0x8078,0x82}, + {0x8079,0x33}, + {0x807a,0xc5}, + {0x807b,0x82}, + {0x807c,0x9b}, + {0x807d,0xed}, + {0x807e,0x9a}, + {0x807f,0xec}, + {0x8080,0x99}, + {0x8081,0xe5}, + {0x8082,0x82}, + {0x8083,0x98}, + {0x8084,0x40}, + {0x8085,0x0c}, + {0x8086,0xf5}, + {0x8087,0x82}, + {0x8088,0xee}, + {0x8089,0x9b}, + {0x808a,0xfe}, + {0x808b,0xed}, + {0x808c,0x9a}, + {0x808d,0xfd}, + {0x808e,0xec}, + {0x808f,0x99}, + {0x8090,0xfc}, + {0x8091,0x0f}, + {0x8092,0xd5}, + {0x8093,0xf0}, + {0x8094,0xd6}, + {0x8095,0xe4}, + {0x8096,0xce}, + {0x8097,0xfb}, + {0x8098,0xe4}, + {0x8099,0xcd}, + {0x809a,0xfa}, + {0x809b,0xe4}, + {0x809c,0xcc}, + {0x809d,0xf9}, + {0x809e,0xa8}, + {0x809f,0x82}, + {0x80a0,0x22}, + {0x80a1,0xb8}, + {0x80a2,0x00}, + {0x80a3,0xc1}, + {0x80a4,0xb9}, + {0x80a5,0x00}, + {0x80a6,0x59}, + {0x80a7,0xba}, + {0x80a8,0x00}, + {0x80a9,0x2d}, + {0x80aa,0xec}, + {0x80ab,0x8b}, + {0x80ac,0xf0}, + {0x80ad,0x84}, + {0x80ae,0xcf}, + {0x80af,0xce}, + {0x80b0,0xcd}, + {0x80b1,0xfc}, + {0x80b2,0xe5}, + {0x80b3,0xf0}, + {0x80b4,0xcb}, + {0x80b5,0xf9}, + {0x80b6,0x78}, + {0x80b7,0x18}, + {0x80b8,0xef}, + {0x80b9,0x2f}, + {0x80ba,0xff}, + {0x80bb,0xee}, + {0x80bc,0x33}, + {0x80bd,0xfe}, + {0x80be,0xed}, + {0x80bf,0x33}, + {0x80c0,0xfd}, + {0x80c1,0xec}, + {0x80c2,0x33}, + {0x80c3,0xfc}, + {0x80c4,0xeb}, + {0x80c5,0x33}, + {0x80c6,0xfb}, + {0x80c7,0x10}, + {0x80c8,0xd7}, + {0x80c9,0x03}, + {0x80ca,0x99}, + {0x80cb,0x40}, + {0x80cc,0x04}, + {0x80cd,0xeb}, + {0x80ce,0x99}, + {0x80cf,0xfb}, + {0x80d0,0x0f}, + {0x80d1,0xd8}, + {0x80d2,0xe5}, + {0x80d3,0xe4}, + {0x80d4,0xf9}, + {0x80d5,0xfa}, + {0x80d6,0x22}, + {0x80d7,0x78}, + {0x80d8,0x18}, + {0x80d9,0xef}, + {0x80da,0x2f}, + {0x80db,0xff}, + {0x80dc,0xee}, + {0x80dd,0x33}, + {0x80de,0xfe}, + {0x80df,0xed}, + {0x80e0,0x33}, + {0x80e1,0xfd}, + {0x80e2,0xec}, + {0x80e3,0x33}, + {0x80e4,0xfc}, + {0x80e5,0xc9}, + {0x80e6,0x33}, + {0x80e7,0xc9}, + {0x80e8,0x10}, + {0x80e9,0xd7}, + {0x80ea,0x05}, + {0x80eb,0x9b}, + {0x80ec,0xe9}, + {0x80ed,0x9a}, + {0x80ee,0x40}, + {0x80ef,0x07}, + {0x80f0,0xec}, + {0x80f1,0x9b}, + {0x80f2,0xfc}, + {0x80f3,0xe9}, + {0x80f4,0x9a}, + {0x80f5,0xf9}, + {0x80f6,0x0f}, + {0x80f7,0xd8}, + {0x80f8,0xe0}, + {0x80f9,0xe4}, + {0x80fa,0xc9}, + {0x80fb,0xfa}, + {0x80fc,0xe4}, + {0x80fd,0xcc}, + {0x80fe,0xfb}, + {0x80ff,0x22}, + {0x8100,0x75}, + {0x8101,0xf0}, + {0x8102,0x10}, + {0x8103,0xef}, + {0x8104,0x2f}, + {0x8105,0xff}, + {0x8106,0xee}, + {0x8107,0x33}, + {0x8108,0xfe}, + {0x8109,0xed}, + {0x810a,0x33}, + {0x810b,0xfd}, + {0x810c,0xcc}, + {0x810d,0x33}, + {0x810e,0xcc}, + {0x810f,0xc8}, + {0x8110,0x33}, + {0x8111,0xc8}, + {0x8112,0x10}, + {0x8113,0xd7}, + {0x8114,0x07}, + {0x8115,0x9b}, + {0x8116,0xec}, + {0x8117,0x9a}, + {0x8118,0xe8}, + {0x8119,0x99}, + {0x811a,0x40}, + {0x811b,0x0a}, + {0x811c,0xed}, + {0x811d,0x9b}, + {0x811e,0xfd}, + {0x811f,0xec}, + {0x8120,0x9a}, + {0x8121,0xfc}, + {0x8122,0xe8}, + {0x8123,0x99}, + {0x8124,0xf8}, + {0x8125,0x0f}, + {0x8126,0xd5}, + {0x8127,0xf0}, + {0x8128,0xda}, + {0x8129,0xe4}, + {0x812a,0xcd}, + {0x812b,0xfb}, + {0x812c,0xe4}, + {0x812d,0xcc}, + {0x812e,0xfa}, + {0x812f,0xe4}, + {0x8130,0xc8}, + {0x8131,0xf9}, + {0x8132,0x22}, + {0x8133,0xe8}, + {0x8134,0x60}, + {0x8135,0x0f}, + {0x8136,0xef}, + {0x8137,0xc3}, + {0x8138,0x33}, + {0x8139,0xff}, + {0x813a,0xee}, + {0x813b,0x33}, + {0x813c,0xfe}, + {0x813d,0xed}, + {0x813e,0x33}, + {0x813f,0xfd}, + {0x8140,0xec}, + {0x8141,0x33}, + {0x8142,0xfc}, + {0x8143,0xd8}, + {0x8144,0xf1}, + {0x8145,0x22}, + {0x8146,0xa4}, + {0x8147,0x25}, + {0x8148,0x82}, + {0x8149,0xf5}, + {0x814a,0x82}, + {0x814b,0xe5}, + {0x814c,0xf0}, + {0x814d,0x35}, + {0x814e,0x83}, + {0x814f,0xf5}, + {0x8150,0x83}, + {0x8151,0x22}, + {0x8152,0xd0}, + {0x8153,0x83}, + {0x8154,0xd0}, + {0x8155,0x82}, + {0x8156,0xf8}, + {0x8157,0xe4}, + {0x8158,0x93}, + {0x8159,0x70}, + {0x815a,0x12}, + {0x815b,0x74}, + {0x815c,0x01}, + {0x815d,0x93}, + {0x815e,0x70}, + {0x815f,0x0d}, + {0x8160,0xa3}, + {0x8161,0xa3}, + {0x8162,0x93}, + {0x8163,0xf8}, + {0x8164,0x74}, + {0x8165,0x01}, + {0x8166,0x93}, + {0x8167,0xf5}, + {0x8168,0x82}, + {0x8169,0x88}, + {0x816a,0x83}, + {0x816b,0xe4}, + {0x816c,0x73}, + {0x816d,0x74}, + {0x816e,0x02}, + {0x816f,0x93}, + {0x8170,0x68}, + {0x8171,0x60}, + {0x8172,0xef}, + {0x8173,0xa3}, + {0x8174,0xa3}, + {0x8175,0xa3}, + {0x8176,0x80}, + {0x8177,0xdf}, + {0x8178,0x75}, + {0x8179,0x0c}, + {0x817a,0x0a}, + {0x817b,0xa2}, + {0x817c,0xaf}, + {0x817d,0x92}, + {0x817e,0x22}, + {0x817f,0xc2}, + {0x8180,0xaf}, + {0x8181,0xc2}, + {0x8182,0x23}, + {0x8183,0x12}, + {0x8184,0x04}, + {0x8185,0x07}, + {0x8186,0x12}, + {0x8187,0x04}, + {0x8188,0x4d}, + {0x8189,0x12}, + {0x818a,0x04}, + {0x818b,0x07}, + {0x818c,0x75}, + {0x818d,0x32}, + {0x818e,0x05}, + {0x818f,0xaf}, + {0x8190,0x32}, + {0x8191,0x15}, + {0x8192,0x32}, + {0x8193,0xef}, + {0x8194,0x70}, + {0x8195,0xf9}, + {0x8196,0xd2}, + {0x8197,0x18}, + {0x8198,0x12}, + {0x8199,0x04}, + {0x819a,0x09}, + {0x819b,0x75}, + {0x819c,0x32}, + {0x819d,0x0a}, + {0x819e,0xaf}, + {0x819f,0x32}, + {0x81a0,0x15}, + {0x81a1,0x32}, + {0x81a2,0xef}, + {0x81a3,0x70}, + {0x81a4,0xf9}, + {0x81a5,0xc2}, + {0x81a6,0x19}, + {0x81a7,0x12}, + {0x81a8,0x04}, + {0x81a9,0x09}, + {0x81aa,0x75}, + {0x81ab,0x32}, + {0x81ac,0x05}, + {0x81ad,0xaf}, + {0x81ae,0x32}, + {0x81af,0x15}, + {0x81b0,0x32}, + {0x81b1,0xef}, + {0x81b2,0x70}, + {0x81b3,0xf9}, + {0x81b4,0xc2}, + {0x81b5,0x18}, + {0x81b6,0x12}, + {0x81b7,0x04}, + {0x81b8,0x09}, + {0x81b9,0x75}, + {0x81ba,0x32}, + {0x81bb,0x05}, + {0x81bc,0xaf}, + {0x81bd,0x32}, + {0x81be,0x15}, + {0x81bf,0x32}, + {0x81c0,0xef}, + {0x81c1,0x70}, + {0x81c2,0xf9}, + {0x81c3,0x75}, + {0x81c4,0x0d}, + {0x81c5,0x18}, + {0x81c6,0x12}, + {0x81c7,0x02}, + {0x81c8,0xb8}, + {0x81c9,0x75}, + {0x81ca,0x32}, + {0x81cb,0x0a}, + {0x81cc,0xaf}, + {0x81cd,0x32}, + {0x81ce,0x15}, + {0x81cf,0x32}, + {0x81d0,0xef}, + {0x81d1,0x70}, + {0x81d2,0xf9}, + {0x81d3,0xd2}, + {0x81d4,0x18}, + {0x81d5,0x12}, + {0x81d6,0x04}, + {0x81d7,0x09}, + {0x81d8,0x12}, + {0x81d9,0x04}, + {0x81da,0x97}, + {0x81db,0xaf}, + {0x81dc,0x32}, + {0x81dd,0x15}, + {0x81de,0x32}, + {0x81df,0xef}, + {0x81e0,0x70}, + {0x81e1,0xf9}, + {0x81e2,0xc2}, + {0x81e3,0x18}, + {0x81e4,0x12}, + {0x81e5,0x04}, + {0x81e6,0x09}, + {0x81e7,0x75}, + {0x81e8,0x32}, + {0x81e9,0x0a}, + {0x81ea,0xaf}, + {0x81eb,0x32}, + {0x81ec,0x15}, + {0x81ed,0x32}, + {0x81ee,0xef}, + {0x81ef,0x70}, + {0x81f0,0xf9}, + {0x81f1,0x30}, + {0x81f2,0x11}, + {0x81f3,0x03}, + {0x81f4,0x02}, + {0x81f5,0x02}, + {0x81f6,0x6f}, + {0x81f7,0x12}, + {0x81f8,0x04}, + {0x81f9,0x07}, + {0x81fa,0x12}, + {0x81fb,0x04}, + {0x81fc,0x4d}, + {0x81fd,0xe5}, + {0x81fe,0x0a}, + {0x81ff,0xf5}, + {0x8200,0x0d}, + {0x8201,0x12}, + {0x8202,0x02}, + {0x8203,0xb8}, + {0x8204,0x75}, + {0x8205,0x32}, + {0x8206,0x0a}, + {0x8207,0xaf}, + {0x8208,0x32}, + {0x8209,0x15}, + {0x820a,0x32}, + {0x820b,0xef}, + {0x820c,0x70}, + {0x820d,0xf9}, + {0x820e,0xd2}, + {0x820f,0x18}, + {0x8210,0x12}, + {0x8211,0x04}, + {0x8212,0x09}, + {0x8213,0x12}, + {0x8214,0x04}, + {0x8215,0x97}, + {0x8216,0xaf}, + {0x8217,0x32}, + {0x8218,0x15}, + {0x8219,0x32}, + {0x821a,0xef}, + {0x821b,0x70}, + {0x821c,0xf9}, + {0x821d,0xc2}, + {0x821e,0x18}, + {0x821f,0x12}, + {0x8220,0x04}, + {0x8221,0x09}, + {0x8222,0x75}, + {0x8223,0x32}, + {0x8224,0x0a}, + {0x8225,0xaf}, + {0x8226,0x32}, + {0x8227,0x15}, + {0x8228,0x32}, + {0x8229,0xef}, + {0x822a,0x70}, + {0x822b,0xf9}, + {0x822c,0x30}, + {0x822d,0x11}, + {0x822e,0x04}, + {0x822f,0x15}, + {0x8230,0x0c}, + {0x8231,0x80}, + {0x8232,0x45}, + {0x8233,0x12}, + {0x8234,0x04}, + {0x8235,0x07}, + {0x8236,0x12}, + {0x8237,0x04}, + {0x8238,0x4d}, + {0x8239,0x85}, + {0x823a,0x0b}, + {0x823b,0x0d}, + {0x823c,0x12}, + {0x823d,0x0a}, + {0x823e,0x9b}, + {0x823f,0xc2}, + {0x8240,0x0f}, + {0x8241,0x12}, + {0x8242,0x04}, + {0x8243,0x4f}, + {0x8244,0x75}, + {0x8245,0x32}, + {0x8246,0x0a}, + {0x8247,0xaf}, + {0x8248,0x32}, + {0x8249,0x15}, + {0x824a,0x32}, + {0x824b,0xef}, + {0x824c,0x70}, + {0x824d,0xf9}, + {0x824e,0xd2}, + {0x824f,0x18}, + {0x8250,0x12}, + {0x8251,0x04}, + {0x8252,0x09}, + {0x8253,0x12}, + {0x8254,0x04}, + {0x8255,0x97}, + {0x8256,0xaf}, + {0x8257,0x32}, + {0x8258,0x15}, + {0x8259,0x32}, + {0x825a,0xef}, + {0x825b,0x70}, + {0x825c,0xf9}, + {0x825d,0xc2}, + {0x825e,0x18}, + {0x825f,0x12}, + {0x8260,0x04}, + {0x8261,0x09}, + {0x8262,0x75}, + {0x8263,0x32}, + {0x8264,0x0a}, + {0x8265,0xaf}, + {0x8266,0x32}, + {0x8267,0x15}, + {0x8268,0x32}, + {0x8269,0xef}, + {0x826a,0x70}, + {0x826b,0xf9}, + {0x826c,0x30}, + {0x826d,0x11}, + {0x826e,0x06}, + {0x826f,0x15}, + {0x8270,0x0c}, + {0x8271,0xd2}, + {0x8272,0x23}, + {0x8273,0x80}, + {0x8274,0x03}, + {0x8275,0xe4}, + {0x8276,0xf5}, + {0x8277,0x0c}, + {0x8278,0x12}, + {0x8279,0x04}, + {0x827a,0x07}, + {0x827b,0x12}, + {0x827c,0x04}, + {0x827d,0x4d}, + {0x827e,0xc2}, + {0x827f,0x19}, + {0x8280,0x12}, + {0x8281,0x04}, + {0x8282,0x09}, + {0x8283,0x75}, + {0x8284,0x32}, + {0x8285,0x05}, + {0x8286,0xaf}, + {0x8287,0x32}, + {0x8288,0x15}, + {0x8289,0x32}, + {0x828a,0xef}, + {0x828b,0x70}, + {0x828c,0xf9}, + {0x828d,0xd2}, + {0x828e,0x18}, + {0x828f,0x12}, + {0x8290,0x04}, + {0x8291,0x09}, + {0x8292,0x75}, + {0x8293,0x32}, + {0x8294,0x05}, + {0x8295,0xaf}, + {0x8296,0x32}, + {0x8297,0x15}, + {0x8298,0x32}, + {0x8299,0xef}, + {0x829a,0x70}, + {0x829b,0xf9}, + {0x829c,0x12}, + {0x829d,0x04}, + {0x829e,0x07}, + {0x829f,0x75}, + {0x82a0,0x32}, + {0x82a1,0x05}, + {0x82a2,0xaf}, + {0x82a3,0x32}, + {0x82a4,0x15}, + {0x82a5,0x32}, + {0x82a6,0xef}, + {0x82a7,0x70}, + {0x82a8,0xf9}, + {0x82a9,0xa2}, + {0x82aa,0x22}, + {0x82ab,0x92}, + {0x82ac,0xaf}, + {0x82ad,0xe5}, + {0x82ae,0x0c}, + {0x82af,0xd3}, + {0x82b0,0x94}, + {0x82b1,0x00}, + {0x82b2,0x40}, + {0x82b3,0x03}, + {0x82b4,0x02}, + {0x82b5,0x01}, + {0x82b6,0x7f}, + {0x82b7,0x22}, + {0x82b8,0x12}, + {0x82b9,0x0a}, + {0x82ba,0x9b}, + {0x82bb,0xc2}, + {0x82bc,0x0f}, + {0x82bd,0x90}, + {0x82be,0x30}, + {0x82bf,0xb1}, + {0x82c0,0xe5}, + {0x82c1,0x21}, + {0x82c2,0xf0}, + {0x82c3,0x22}, + {0x82c4,0x90}, + {0x82c5,0x33}, + {0x82c6,0x5f}, + {0x82c7,0xe0}, + {0x82c8,0x54}, + {0x82c9,0x0f}, + {0x82ca,0xfe}, + {0x82cb,0xa3}, + {0x82cc,0xe0}, + {0x82cd,0xfd}, + {0x82ce,0xed}, + {0x82cf,0xff}, + {0x82d0,0xee}, + {0x82d1,0x54}, + {0x82d2,0x0f}, + {0x82d3,0xf5}, + {0x82d4,0x0d}, + {0x82d5,0x8f}, + {0x82d6,0x0e}, + {0x82d7,0x90}, + {0x82d8,0x33}, + {0x82d9,0x5f}, + {0x82da,0xe0}, + {0x82db,0x54}, + {0x82dc,0x70}, + {0x82dd,0x75}, + {0x82de,0xf0}, + {0x82df,0x10}, + {0x82e0,0xa4}, + {0x82e1,0xff}, + {0x82e2,0x90}, + {0x82e3,0x33}, + {0x82e4,0x61}, + {0x82e5,0xe0}, + {0x82e6,0xfd}, + {0x82e7,0xef}, + {0x82e8,0x4d}, + {0x82e9,0xff}, + {0x82ea,0xe5}, + {0x82eb,0xf0}, + {0x82ec,0x54}, + {0x82ed,0x07}, + {0x82ee,0xf5}, + {0x82ef,0x0f}, + {0x82f0,0x8f}, + {0x82f1,0x10}, + {0x82f2,0xe5}, + {0x82f3,0x0e}, + {0x82f4,0xae}, + {0x82f5,0x0d}, + {0x82f6,0x78}, + {0x82f7,0x05}, + {0x82f8,0xce}, + {0x82f9,0xc3}, + {0x82fa,0x13}, + {0x82fb,0xce}, + {0x82fc,0x13}, + {0x82fd,0xd8}, + {0x82fe,0xf9}, + {0x82ff,0xf5}, + {0x8300,0x0e}, + {0x8301,0x8e}, + {0x8302,0x0d}, + {0x8303,0xe5}, + {0x8304,0x10}, + {0x8305,0xae}, + {0x8306,0x0f}, + {0x8307,0x78}, + {0x8308,0x03}, + {0x8309,0xce}, + {0x830a,0xc3}, + {0x830b,0x13}, + {0x830c,0xce}, + {0x830d,0x13}, + {0x830e,0xd8}, + {0x830f,0xf9}, + {0x8310,0xf5}, + {0x8311,0x10}, + {0x8312,0x8e}, + {0x8313,0x0f}, + {0x8314,0x85}, + {0x8315,0x2a}, + {0x8316,0x11}, + {0x8317,0x85}, + {0x8318,0x2b}, + {0x8319,0x13}, + {0x831a,0x85}, + {0x831b,0x2c}, + {0x831c,0x12}, + {0x831d,0x85}, + {0x831e,0x2d}, + {0x831f,0x14}, + {0x8320,0x12}, + {0x8321,0x04}, + {0x8322,0xab}, + {0x8323,0xaf}, + {0x8324,0x11}, + {0x8325,0x12}, + {0x8326,0x03}, + {0x8327,0xdf}, + {0x8328,0x8f}, + {0x8329,0x11}, + {0x832a,0x12}, + {0x832b,0x04}, + {0x832c,0xab}, + {0x832d,0xaf}, + {0x832e,0x12}, + {0x832f,0x12}, + {0x8330,0x03}, + {0x8331,0xdf}, + {0x8332,0x8f}, + {0x8333,0x12}, + {0x8334,0x12}, + {0x8335,0x04}, + {0x8336,0x56}, + {0x8337,0xaf}, + {0x8338,0x13}, + {0x8339,0xfc}, + {0x833a,0xfd}, + {0x833b,0xfe}, + {0x833c,0x12}, + {0x833d,0x00}, + {0x833e,0x16}, + {0x833f,0x12}, + {0x8340,0x03}, + {0x8341,0xfe}, + {0x8342,0x7b}, + {0x8343,0x1e}, + {0x8344,0x12}, + {0x8345,0x03}, + {0x8346,0xf7}, + {0x8347,0x8f}, + {0x8348,0x13}, + {0x8349,0x12}, + {0x834a,0x04}, + {0x834b,0x56}, + {0x834c,0xaf}, + {0x834d,0x14}, + {0x834e,0xfc}, + {0x834f,0xfd}, + {0x8350,0xfe}, + {0x8351,0x12}, + {0x8352,0x00}, + {0x8353,0x16}, + {0x8354,0x12}, + {0x8355,0x03}, + {0x8356,0xfe}, + {0x8357,0xe4}, + {0x8358,0x7b}, + {0x8359,0x1e}, + {0x835a,0x12}, + {0x835b,0x03}, + {0x835c,0xf8}, + {0x835d,0x8f}, + {0x835e,0x14}, + {0x835f,0xc3}, + {0x8360,0xe5}, + {0x8361,0x12}, + {0x8362,0x95}, + {0x8363,0x11}, + {0x8364,0xff}, + {0x8365,0x0f}, + {0x8366,0xef}, + {0x8367,0xc3}, + {0x8368,0x13}, + {0x8369,0xff}, + {0x836a,0xc3}, + {0x836b,0x94}, + {0x836c,0x02}, + {0x836d,0x50}, + {0x836e,0x27}, + {0x836f,0xe5}, + {0x8370,0x11}, + {0x8371,0x9f}, + {0x8372,0x40}, + {0x8373,0x06}, + {0x8374,0xe5}, + {0x8375,0x11}, + {0x8376,0x9f}, + {0x8377,0xfe}, + {0x8378,0x80}, + {0x8379,0x02}, + {0x837a,0x7e}, + {0x837b,0x00}, + {0x837c,0x8e}, + {0x837d,0x11}, + {0x837e,0xef}, + {0x837f,0xfd}, + {0x8380,0xe5}, + {0x8381,0x12}, + {0x8382,0x2d}, + {0x8383,0xfd}, + {0x8384,0xe4}, + {0x8385,0x33}, + {0x8386,0xfc}, + {0x8387,0xc3}, + {0x8388,0xed}, + {0x8389,0x95}, + {0x838a,0x0e}, + {0x838b,0xec}, + {0x838c,0x95}, + {0x838d,0x0d}, + {0x838e,0x50}, + {0x838f,0x02}, + {0x8390,0x80}, + {0x8391,0x02}, + {0x8392,0xad}, + {0x8393,0x0e}, + {0x8394,0x8d}, + {0x8395,0x12}, + {0x8396,0xc3}, + {0x8397,0xe5}, + {0x8398,0x14}, + {0x8399,0x95}, + {0x839a,0x13}, + {0x839b,0xff}, + {0x839c,0xc3}, + {0x839d,0x94}, + {0x839e,0x08}, + {0x839f,0x50}, + {0x83a0,0x29}, + {0x83a1,0xe5}, + {0x83a2,0x13}, + {0x83a3,0x9f}, + {0x83a4,0x40}, + {0x83a5,0x06}, + {0x83a6,0xe5}, + {0x83a7,0x13}, + {0x83a8,0x9f}, + {0x83a9,0xfe}, + {0x83aa,0x80}, + {0x83ab,0x02}, + {0x83ac,0x7e}, + {0x83ad,0x00}, + {0x83ae,0x8e}, + {0x83af,0x13}, + {0x83b0,0xef}, + {0x83b1,0xfd}, + {0x83b2,0xe5}, + {0x83b3,0x14}, + {0x83b4,0x2d}, + {0x83b5,0xfd}, + {0x83b6,0xe4}, + {0x83b7,0x33}, + {0x83b8,0xfc}, + {0x83b9,0xc3}, + {0x83ba,0xed}, + {0x83bb,0x95}, + {0x83bc,0x10}, + {0x83bd,0xec}, + {0x83be,0x95}, + {0x83bf,0x0f}, + {0x83c0,0x50}, + {0x83c1,0x04}, + {0x83c2,0xaf}, + {0x83c3,0x05}, + {0x83c4,0x80}, + {0x83c5,0x02}, + {0x83c6,0xaf}, + {0x83c7,0x10}, + {0x83c8,0x8f}, + {0x83c9,0x14}, + {0x83ca,0x90}, + {0x83cb,0x39}, + {0x83cc,0x0a}, + {0x83cd,0xe5}, + {0x83ce,0x11}, + {0x83cf,0xf0}, + {0x83d0,0xa3}, + {0x83d1,0xe5}, + {0x83d2,0x13}, + {0x83d3,0xf0}, + {0x83d4,0xa3}, + {0x83d5,0xe5}, + {0x83d6,0x12}, + {0x83d7,0xf0}, + {0x83d8,0xa3}, + {0x83d9,0xe5}, + {0x83da,0x14}, + {0x83db,0xf0}, + {0x83dc,0xc2}, + {0x83dd,0x20}, + {0x83de,0x22}, + {0x83df,0xab}, + {0x83e0,0x0c}, + {0x83e1,0xaa}, + {0x83e2,0x0b}, + {0x83e3,0xa9}, + {0x83e4,0x0a}, + {0x83e5,0xa8}, + {0x83e6,0x09}, + {0x83e7,0xfc}, + {0x83e8,0xfd}, + {0x83e9,0xfe}, + {0x83ea,0x12}, + {0x83eb,0x00}, + {0x83ec,0x16}, + {0x83ed,0x8f}, + {0x83ee,0x0c}, + {0x83ef,0x8e}, + {0x83f0,0x0b}, + {0x83f1,0x8d}, + {0x83f2,0x0a}, + {0x83f3,0x8c}, + {0x83f4,0x09}, + {0x83f5,0x7b}, + {0x83f6,0x28}, + {0x83f7,0xe4}, + {0x83f8,0xfa}, + {0x83f9,0xf9}, + {0x83fa,0xf8}, + {0x83fb,0x12}, + {0x83fc,0x00}, + {0x83fd,0xa1}, + {0x83fe,0x8f}, + {0x83ff,0x0c}, + {0x8400,0x8e}, + {0x8401,0x0b}, + {0x8402,0x8d}, + {0x8403,0x0a}, + {0x8404,0x8c}, + {0x8405,0x09}, + {0x8406,0x22}, + {0x8407,0xd2}, + {0x8408,0x19}, + {0x8409,0x90}, + {0x840a,0x30}, + {0x840b,0xb4}, + {0x840c,0xe5}, + {0x840d,0x23}, + {0x840e,0xf0}, + {0x840f,0x22}, + {0x8410,0x85}, + {0x8411,0x2f}, + {0x8412,0x82}, + {0x8413,0x85}, + {0x8414,0x2e}, + {0x8415,0x83}, + {0x8416,0xe5}, + {0x8417,0x43}, + {0x8418,0x75}, + {0x8419,0xf0}, + {0x841a,0x02}, + {0x841b,0x12}, + {0x841c,0x01}, + {0x841d,0x46}, + {0x841e,0xe4}, + {0x841f,0x93}, + {0x8420,0xfe}, + {0x8421,0x74}, + {0x8422,0x01}, + {0x8423,0x93}, + {0x8424,0xff}, + {0x8425,0x85}, + {0x8426,0x2f}, + {0x8427,0x82}, + {0x8428,0x85}, + {0x8429,0x2e}, + {0x842a,0x83}, + {0x842b,0xe4}, + {0x842c,0x93}, + {0x842d,0xfc}, + {0x842e,0x74}, + {0x842f,0x01}, + {0x8430,0x93}, + {0x8431,0xfd}, + {0x8432,0xc3}, + {0x8433,0xef}, + {0x8434,0x9d}, + {0x8435,0xff}, + {0x8436,0xee}, + {0x8437,0x9c}, + {0x8438,0x22}, + {0x8439,0x12}, + {0x843a,0x00}, + {0x843b,0x16}, + {0x843c,0x8f}, + {0x843d,0x3c}, + {0x843e,0x8e}, + {0x843f,0x3b}, + {0x8440,0x8d}, + {0x8441,0x3a}, + {0x8442,0x8c}, + {0x8443,0x39}, + {0x8444,0xaf}, + {0x8445,0x3c}, + {0x8446,0xae}, + {0x8447,0x3b}, + {0x8448,0xad}, + {0x8449,0x3a}, + {0x844a,0xac}, + {0x844b,0x39}, + {0x844c,0x22}, + {0x844d,0xd2}, + {0x844e,0x0f}, + {0x844f,0x90}, + {0x8450,0x30}, + {0x8451,0xb1}, + {0x8452,0xe5}, + {0x8453,0x21}, + {0x8454,0xf0}, + {0x8455,0x22}, + {0x8456,0xe4}, + {0x8457,0x85}, + {0x8458,0x10}, + {0x8459,0x0c}, + {0x845a,0x85}, + {0x845b,0x0f}, + {0x845c,0x0b}, + {0x845d,0xf5}, + {0x845e,0x0a}, + {0x845f,0xf5}, + {0x8460,0x09}, + {0x8461,0xab}, + {0x8462,0x0c}, + {0x8463,0xaa}, + {0x8464,0x0b}, + {0x8465,0xa9}, + {0x8466,0x0a}, + {0x8467,0xa8}, + {0x8468,0x09}, + {0x8469,0x22}, + {0x846a,0x85}, + {0x846b,0x2f}, + {0x846c,0x82}, + {0x846d,0x85}, + {0x846e,0x2e}, + {0x846f,0x83}, + {0x8470,0x22}, + {0x8471,0xff}, + {0x8472,0xe4}, + {0x8473,0x94}, + {0x8474,0x00}, + {0x8475,0xfe}, + {0x8476,0xe4}, + {0x8477,0xfc}, + {0x8478,0xfd}, + {0x8479,0x02}, + {0x847a,0x01}, + {0x847b,0x33}, + {0x847c,0xc2}, + {0x847d,0x07}, + {0x847e,0xc2}, + {0x847f,0x06}, + {0x8480,0xc2}, + {0x8481,0x02}, + {0x8482,0xc2}, + {0x8483,0x01}, + {0x8484,0xc2}, + {0x8485,0x00}, + {0x8486,0xc2}, + {0x8487,0x03}, + {0x8488,0xd2}, + {0x8489,0x04}, + {0x848a,0x22}, + {0x848b,0x90}, + {0x848c,0x33}, + {0x848d,0xb3}, + {0x848e,0xe4}, + {0x848f,0xf0}, + {0x8490,0xa3}, + {0x8491,0xf0}, + {0x8492,0xa3}, + {0x8493,0xf0}, + {0x8494,0xa3}, + {0x8495,0xf0}, + {0x8496,0x22}, + {0x8497,0xa3}, + {0x8498,0xe0}, + {0x8499,0xf5}, + {0x849a,0x22}, + {0x849b,0x75}, + {0x849c,0x32}, + {0x849d,0x0a}, + {0x849e,0x22}, + {0x849f,0x12}, + {0x84a0,0x00}, + {0x84a1,0xa1}, + {0x84a2,0x8f}, + {0x84a3,0x3c}, + {0x84a4,0x8e}, + {0x84a5,0x3b}, + {0x84a6,0x8d}, + {0x84a7,0x3a}, + {0x84a8,0x8c}, + {0x84a9,0x39}, + {0x84aa,0x22}, + {0x84ab,0xe4}, + {0x84ac,0x85}, + {0x84ad,0x0e}, + {0x84ae,0x0c}, + {0x84af,0x85}, + {0x84b0,0x0d}, + {0x84b1,0x0b}, + {0x84b2,0xf5}, + {0x84b3,0x0a}, + {0x84b4,0xf5}, + {0x84b5,0x09}, + {0x84b6,0x22}, + {0x84b7,0xe4}, + {0x84b8,0xfc}, + {0x84b9,0xfd}, + {0x84ba,0xfe}, + {0x84bb,0x02}, + {0x84bc,0x01}, + {0x84bd,0x33}, + {0x84be,0x90}, + {0x84bf,0x0b}, + {0x84c0,0x4c}, + {0x84c1,0xe4}, + {0x84c2,0x93}, + {0x84c3,0xff}, + {0x84c4,0x90}, + {0x84c5,0x30}, + {0x84c6,0x0a}, + {0x84c7,0xe0}, + {0x84c8,0x22}, + {0x84c9,0xc2}, + {0x84ca,0x02}, + {0x84cb,0xc2}, + {0x84cc,0x01}, + {0x84cd,0xd2}, + {0x84ce,0x00}, + {0x84cf,0xc2}, + {0x84d0,0x03}, + {0x84d1,0xc2}, + {0x84d2,0x04}, + {0x84d3,0x22}, + {0x84d4,0x75}, + {0x84d5,0xf0}, + {0x84d6,0x02}, + {0x84d7,0x02}, + {0x84d8,0x01}, + {0x84d9,0x46}, + {0x84da,0xe4}, + {0x84db,0x93}, + {0x84dc,0xf5}, + {0x84dd,0x43}, + {0x84de,0xa3}, + {0x84df,0xe4}, + {0x84e0,0x93}, + {0x84e1,0xf5}, + {0x84e2,0x28}, + {0x84e3,0x22}, + {0x84e4,0xd2}, + {0x84e5,0x02}, + {0x84e6,0xd2}, + {0x84e7,0x01}, + {0x84e8,0xc2}, + {0x84e9,0x00}, + {0x84ea,0x22}, + {0x84eb,0xd3}, + {0x84ec,0xe5}, + {0x84ed,0x3c}, + {0x84ee,0x94}, + {0x84ef,0xff}, + {0x84f0,0xe5}, + {0x84f1,0x3b}, + {0x84f2,0x94}, + {0x84f3,0x03}, + {0x84f4,0x22}, + {0x84f5,0x30}, + {0x84f6,0x04}, + {0x84f7,0x03}, + {0x84f8,0x02}, + {0x84f9,0x05}, + {0x84fa,0xd5}, + {0x84fb,0xd2}, + {0x84fc,0x04}, + {0x84fd,0xe5}, + {0x84fe,0x45}, + {0x84ff,0xb4}, + {0x8500,0x01}, + {0x8501,0x06}, + {0x8502,0x12}, + {0x8503,0x0c}, + {0x8504,0xfe}, + {0x8505,0x02}, + {0x8506,0x05}, + {0x8507,0xce}, + {0x8508,0xe5}, + {0x8509,0x45}, + {0x850a,0xb4}, + {0x850b,0x02}, + {0x850c,0x06}, + {0x850d,0x12}, + {0x850e,0x0d}, + {0x850f,0x0f}, + {0x8510,0x02}, + {0x8511,0x05}, + {0x8512,0xce}, + {0x8513,0xe5}, + {0x8514,0x45}, + {0x8515,0xb4}, + {0x8516,0x03}, + {0x8517,0x05}, + {0x8518,0xe4}, + {0x8519,0xf5}, + {0x851a,0x09}, + {0x851b,0x80}, + {0x851c,0x08}, + {0x851d,0xe5}, + {0x851e,0x45}, + {0x851f,0xb4}, + {0x8520,0x04}, + {0x8521,0x09}, + {0x8522,0x85}, + {0x8523,0x43}, + {0x8524,0x09}, + {0x8525,0x12}, + {0x8526,0x09}, + {0x8527,0xee}, + {0x8528,0x02}, + {0x8529,0x05}, + {0x852a,0xce}, + {0x852b,0xe5}, + {0x852c,0x45}, + {0x852d,0x64}, + {0x852e,0x0f}, + {0x852f,0x70}, + {0x8530,0x15}, + {0x8531,0x12}, + {0x8532,0x04}, + {0x8533,0xeb}, + {0x8534,0x40}, + {0x8535,0x06}, + {0x8536,0x7e}, + {0x8537,0x03}, + {0x8538,0x7f}, + {0x8539,0xff}, + {0x853a,0x80}, + {0x853b,0x04}, + {0x853c,0xae}, + {0x853d,0x3b}, + {0x853e,0xaf}, + {0x853f,0x3c}, + {0x8540,0x12}, + {0x8541,0x05}, + {0x8542,0xd6}, + {0x8543,0x02}, + {0x8544,0x05}, + {0x8545,0xce}, + {0x8546,0xe5}, + {0x8547,0x45}, + {0x8548,0x64}, + {0x8549,0x10}, + {0x854a,0x60}, + {0x854b,0x03}, + {0x854c,0x02}, + {0x854d,0x05}, + {0x854e,0xce}, + {0x854f,0xf5}, + {0x8550,0x39}, + {0x8551,0xf5}, + {0x8552,0x3a}, + {0x8553,0xf5}, + {0x8554,0x3b}, + {0x8555,0xab}, + {0x8556,0x3c}, + {0x8557,0xaa}, + {0x8558,0x3b}, + {0x8559,0xa9}, + {0x855a,0x3a}, + {0x855b,0xa8}, + {0x855c,0x39}, + {0x855d,0x12}, + {0x855e,0x04}, + {0x855f,0x10}, + {0x8560,0xfe}, + {0x8561,0xe4}, + {0x8562,0xfc}, + {0x8563,0xfd}, + {0x8564,0x12}, + {0x8565,0x04}, + {0x8566,0x39}, + {0x8567,0xe4}, + {0x8568,0x7b}, + {0x8569,0xff}, + {0x856a,0xfa}, + {0x856b,0xf9}, + {0x856c,0xf8}, + {0x856d,0x12}, + {0x856e,0x04}, + {0x856f,0x9f}, + {0x8570,0x12}, + {0x8571,0x04}, + {0x8572,0x6a}, + {0x8573,0xe4}, + {0x8574,0x93}, + {0x8575,0xfe}, + {0x8576,0x74}, + {0x8577,0x01}, + {0x8578,0x93}, + {0x8579,0xff}, + {0x857a,0xe4}, + {0x857b,0xfc}, + {0x857c,0xfd}, + {0x857d,0xe5}, + {0x857e,0x3c}, + {0x857f,0x2f}, + {0x8580,0xf5}, + {0x8581,0x3c}, + {0x8582,0xe5}, + {0x8583,0x3b}, + {0x8584,0x3e}, + {0x8585,0xf5}, + {0x8586,0x3b}, + {0x8587,0xed}, + {0x8588,0x35}, + {0x8589,0x3a}, + {0x858a,0xf5}, + {0x858b,0x3a}, + {0x858c,0xec}, + {0x858d,0x35}, + {0x858e,0x39}, + {0x858f,0xf5}, + {0x8590,0x39}, + {0x8591,0x12}, + {0x8592,0x04}, + {0x8593,0xeb}, + {0x8594,0x40}, + {0x8595,0x06}, + {0x8596,0x7e}, + {0x8597,0x03}, + {0x8598,0x7f}, + {0x8599,0xff}, + {0x859a,0x80}, + {0x859b,0x04}, + {0x859c,0xae}, + {0x859d,0x3b}, + {0x859e,0xaf}, + {0x859f,0x3c}, + {0x85a0,0x12}, + {0x85a1,0x05}, + {0x85a2,0xd6}, + {0x85a3,0xe4}, + {0x85a4,0xf5}, + {0x85a5,0x3a}, + {0x85a6,0xf5}, + {0x85a7,0x3a}, + {0x85a8,0xe5}, + {0x85a9,0x3a}, + {0x85aa,0xd3}, + {0x85ab,0x95}, + {0x85ac,0x43}, + {0x85ad,0x50}, + {0x85ae,0x1c}, + {0x85af,0x12}, + {0x85b0,0x04}, + {0x85b1,0x6a}, + {0x85b2,0xaf}, + {0x85b3,0x3a}, + {0x85b4,0x75}, + {0x85b5,0xf0}, + {0x85b6,0x02}, + {0x85b7,0xef}, + {0x85b8,0x12}, + {0x85b9,0x01}, + {0x85ba,0x46}, + {0x85bb,0xc3}, + {0x85bc,0x74}, + {0x85bd,0x01}, + {0x85be,0x93}, + {0x85bf,0x95}, + {0x85c0,0x3c}, + {0x85c1,0xe4}, + {0x85c2,0x93}, + {0x85c3,0x95}, + {0x85c4,0x3b}, + {0x85c5,0x50}, + {0x85c6,0x04}, + {0x85c7,0x05}, + {0x85c8,0x3a}, + {0x85c9,0x80}, + {0x85ca,0xdd}, + {0x85cb,0x85}, + {0x85cc,0x3a}, + {0x85cd,0x44}, + {0x85ce,0x90}, + {0x85cf,0x3f}, + {0x85d0,0x01}, + {0x85d1,0xe4}, + {0x85d2,0xf0}, + {0x85d3,0xd2}, + {0x85d4,0x25}, + {0x85d5,0x22}, + {0x85d6,0x8e}, + {0x85d7,0x3b}, + {0x85d8,0x8f}, + {0x85d9,0x3c}, + {0x85da,0x85}, + {0x85db,0x3b}, + {0x85dc,0x37}, + {0x85dd,0x85}, + {0x85de,0x3c}, + {0x85df,0x38}, + {0x85e0,0xe5}, + {0x85e1,0x3c}, + {0x85e2,0xc4}, + {0x85e3,0xf8}, + {0x85e4,0x54}, + {0x85e5,0x0f}, + {0x85e6,0xc8}, + {0x85e7,0x68}, + {0x85e8,0xf5}, + {0x85e9,0x3c}, + {0x85ea,0xe5}, + {0x85eb,0x3b}, + {0x85ec,0xc4}, + {0x85ed,0x54}, + {0x85ee,0xf0}, + {0x85ef,0x48}, + {0x85f0,0xf5}, + {0x85f1,0x3b}, + {0x85f2,0x85}, + {0x85f3,0x3b}, + {0x85f4,0x0a}, + {0x85f5,0x85}, + {0x85f6,0x3c}, + {0x85f7,0x0b}, + {0x85f8,0x12}, + {0x85f9,0x01}, + {0x85fa,0x78}, + {0x85fb,0x22}, + {0x85fc,0xe5}, + {0x85fd,0x29}, + {0x85fe,0x70}, + {0x85ff,0x03}, + {0x8600,0x02}, + {0x8601,0x06}, + {0x8602,0xd4}, + {0x8603,0xc2}, + {0x8604,0xaf}, + {0x8605,0xaf}, + {0x8606,0x29}, + {0x8607,0xe4}, + {0x8608,0xf5}, + {0x8609,0x29}, + {0x860a,0xd2}, + {0x860b,0xaf}, + {0x860c,0x90}, + {0x860d,0x3f}, + {0x860e,0x01}, + {0x860f,0xe0}, + {0x8610,0xf5}, + {0x8611,0x45}, + {0x8612,0xa3}, + {0x8613,0xe0}, + {0x8614,0xf5}, + {0x8615,0x39}, + {0x8616,0xa3}, + {0x8617,0xe0}, + {0x8618,0xf5}, + {0x8619,0x3a}, + {0x861a,0xa3}, + {0x861b,0xe0}, + {0x861c,0xf5}, + {0x861d,0x3b}, + {0x861e,0xa3}, + {0x861f,0xe0}, + {0x8620,0xf5}, + {0x8621,0x3c}, + {0x8622,0xef}, + {0x8623,0x12}, + {0x8624,0x01}, + {0x8625,0x52}, + {0x8626,0x06}, + {0x8627,0x4b}, + {0x8628,0x03}, + {0x8629,0x06}, + {0x862a,0x5a}, + {0x862b,0x05}, + {0x862c,0x06}, + {0x862d,0x81}, + {0x862e,0x06}, + {0x862f,0x06}, + {0x8630,0x6f}, + {0x8631,0x08}, + {0x8632,0x06}, + {0x8633,0xa2}, + {0x8634,0x09}, + {0x8635,0x06}, + {0x8636,0x8e}, + {0x8637,0x10}, + {0x8638,0x06}, + {0x8639,0xa2}, + {0x863a,0x12}, + {0x863b,0x06}, + {0x863c,0xa7}, + {0x863d,0x20}, + {0x863e,0x06}, + {0x863f,0xb5}, + {0x8640,0x21}, + {0x8641,0x06}, + {0x8642,0xba}, + {0x8643,0x30}, + {0x8644,0x06}, + {0x8645,0xc5}, + {0x8646,0xd0}, + {0x8647,0x00}, + {0x8648,0x00}, + {0x8649,0x06}, + {0x864a,0xc9}, + {0x864b,0x30}, + {0x864c,0x05}, + {0x864d,0x7b}, + {0x864e,0x20}, + {0x864f,0x00}, + {0x8650,0x78}, + {0x8651,0xd2}, + {0x8652,0x07}, + {0x8653,0xc2}, + {0x8654,0x06}, + {0x8655,0x12}, + {0x8656,0x04}, + {0x8657,0xc9}, + {0x8658,0x80}, + {0x8659,0x21}, + {0x865a,0x30}, + {0x865b,0x05}, + {0x865c,0x6c}, + {0x865d,0x20}, + {0x865e,0x00}, + {0x865f,0x69}, + {0x8660,0xc2}, + {0x8661,0x07}, + {0x8662,0xd2}, + {0x8663,0x06}, + {0x8664,0xc2}, + {0x8665,0x03}, + {0x8666,0x12}, + {0x8667,0x04}, + {0x8668,0xe4}, + {0x8669,0xc2}, + {0x866a,0x04}, + {0x866b,0xc2}, + {0x866c,0x21}, + {0x866d,0x80}, + {0x866e,0x5a}, + {0x866f,0x12}, + {0x8670,0x04}, + {0x8671,0x7c}, + {0x8672,0x30}, + {0x8673,0x05}, + {0x8674,0x06}, + {0x8675,0xe4}, + {0x8676,0xf5}, + {0x8677,0x09}, + {0x8678,0x12}, + {0x8679,0x09}, + {0x867a,0xee}, + {0x867b,0xc2}, + {0x867c,0x21}, + {0x867d,0xd2}, + {0x867e,0x25}, + {0x867f,0x80}, + {0x8680,0x48}, + {0x8681,0x30}, + {0x8682,0x07}, + {0x8683,0x45}, + {0x8684,0x30}, + {0x8685,0x06}, + {0x8686,0x42}, + {0x8687,0x12}, + {0x8688,0x04}, + {0x8689,0xc9}, + {0x868a,0xd2}, + {0x868b,0x21}, + {0x868c,0x80}, + {0x868d,0x3b}, + {0x868e,0x20}, + {0x868f,0x07}, + {0x8690,0x03}, + {0x8691,0x30}, + {0x8692,0x06}, + {0x8693,0x09}, + {0x8694,0xe5}, + {0x8695,0x45}, + {0x8696,0x64}, + {0x8697,0x0e}, + {0x8698,0x70}, + {0x8699,0x2f}, + {0x869a,0x20}, + {0x869b,0x00}, + {0x869c,0x2c}, + {0x869d,0x12}, + {0x869e,0x06}, + {0x869f,0xd5}, + {0x86a0,0x80}, + {0x86a1,0x27}, + {0x86a2,0x12}, + {0x86a3,0x02}, + {0x86a4,0xc4}, + {0x86a5,0x80}, + {0x86a6,0x22}, + {0x86a7,0x30}, + {0x86a8,0x05}, + {0x86a9,0x1f}, + {0x86aa,0x20}, + {0x86ab,0x07}, + {0x86ac,0x1c}, + {0x86ad,0x20}, + {0x86ae,0x06}, + {0x86af,0x19}, + {0x86b0,0x12}, + {0x86b1,0x0c}, + {0x86b2,0xa6}, + {0x86b3,0x80}, + {0x86b4,0x14}, + {0x86b5,0x12}, + {0x86b6,0x09}, + {0x86b7,0x85}, + {0x86b8,0x80}, + {0x86b9,0x0f}, + {0x86ba,0x20}, + {0x86bb,0x07}, + {0x86bc,0x0c}, + {0x86bd,0x20}, + {0x86be,0x06}, + {0x86bf,0x09}, + {0x86c0,0x12}, + {0x86c1,0x0d}, + {0x86c2,0x3c}, + {0x86c3,0x80}, + {0x86c4,0x04}, + {0x86c5,0xd2}, + {0x86c6,0x26}, + {0x86c7,0xc2}, + {0x86c8,0x26}, + {0x86c9,0x20}, + {0x86ca,0x07}, + {0x86cb,0x03}, + {0x86cc,0x20}, + {0x86cd,0x06}, + {0x86ce,0x05}, + {0x86cf,0x90}, + {0x86d0,0x3f}, + {0x86d1,0x01}, + {0x86d2,0xe4}, + {0x86d3,0xf0}, + {0x86d4,0x22}, + {0x86d5,0xe5}, + {0x86d6,0x45}, + {0x86d7,0x24}, + {0x86d8,0xfe}, + {0x86d9,0x60}, + {0x86da,0x19}, + {0x86db,0x14}, + {0x86dc,0x60}, + {0x86dd,0x2c}, + {0x86de,0x24}, + {0x86df,0x02}, + {0x86e0,0x60}, + {0x86e1,0x03}, + {0x86e2,0x02}, + {0x86e3,0x07}, + {0x86e4,0xa8}, + {0x86e5,0xe5}, + {0x86e6,0x3c}, + {0x86e7,0xd3}, + {0x86e8,0x94}, + {0x86e9,0x03}, + {0x86ea,0x40}, + {0x86eb,0x03}, + {0x86ec,0x75}, + {0x86ed,0x3c}, + {0x86ee,0x03}, + {0x86ef,0xe4}, + {0x86f0,0xf5}, + {0x86f1,0x09}, + {0x86f2,0x80}, + {0x86f3,0x0d}, + {0x86f4,0xe5}, + {0x86f5,0x3c}, + {0x86f6,0xd3}, + {0x86f7,0x94}, + {0x86f8,0x05}, + {0x86f9,0x40}, + {0x86fa,0x03}, + {0x86fb,0x75}, + {0x86fc,0x3c}, + {0x86fd,0x05}, + {0x86fe,0x75}, + {0x86ff,0x09}, + {0x8700,0x01}, + {0x8701,0x85}, + {0x8702,0x3c}, + {0x8703,0x0a}, + {0x8704,0x12}, + {0x8705,0x08}, + {0x8706,0xfa}, + {0x8707,0xd2}, + {0x8708,0x20}, + {0x8709,0x22}, + {0x870a,0xe5}, + {0x870b,0x39}, + {0x870c,0xd3}, + {0x870d,0x94}, + {0x870e,0x28}, + {0x870f,0x40}, + {0x8710,0x04}, + {0x8711,0x7f}, + {0x8712,0x28}, + {0x8713,0x80}, + {0x8714,0x02}, + {0x8715,0xaf}, + {0x8716,0x39}, + {0x8717,0x8f}, + {0x8718,0x39}, + {0x8719,0xe5}, + {0x871a,0x3a}, + {0x871b,0xd3}, + {0x871c,0x94}, + {0x871d,0x1e}, + {0x871e,0x40}, + {0x871f,0x04}, + {0x8720,0x7f}, + {0x8721,0x1e}, + {0x8722,0x80}, + {0x8723,0x02}, + {0x8724,0xaf}, + {0x8725,0x3a}, + {0x8726,0x8f}, + {0x8727,0x3a}, + {0x8728,0xe5}, + {0x8729,0x3b}, + {0x872a,0xd3}, + {0x872b,0x94}, + {0x872c,0x28}, + {0x872d,0x40}, + {0x872e,0x04}, + {0x872f,0x7f}, + {0x8730,0x28}, + {0x8731,0x80}, + {0x8732,0x02}, + {0x8733,0xaf}, + {0x8734,0x3b}, + {0x8735,0x8f}, + {0x8736,0x3b}, + {0x8737,0xe5}, + {0x8738,0x3c}, + {0x8739,0xd3}, + {0x873a,0x94}, + {0x873b,0x1e}, + {0x873c,0x40}, + {0x873d,0x04}, + {0x873e,0x7f}, + {0x873f,0x1e}, + {0x8740,0x80}, + {0x8741,0x02}, + {0x8742,0xaf}, + {0x8743,0x3c}, + {0x8744,0x8f}, + {0x8745,0x3c}, + {0x8746,0xaf}, + {0x8747,0x3a}, + {0x8748,0x78}, + {0x8749,0x10}, + {0x874a,0x12}, + {0x874b,0x04}, + {0x874c,0xb7}, + {0x874d,0xc0}, + {0x874e,0x04}, + {0x874f,0xc0}, + {0x8750,0x05}, + {0x8751,0xc0}, + {0x8752,0x06}, + {0x8753,0xc0}, + {0x8754,0x07}, + {0x8755,0xaf}, + {0x8756,0x39}, + {0x8757,0x78}, + {0x8758,0x18}, + {0x8759,0x12}, + {0x875a,0x04}, + {0x875b,0xb7}, + {0x875c,0xd0}, + {0x875d,0x03}, + {0x875e,0xd0}, + {0x875f,0x02}, + {0x8760,0xd0}, + {0x8761,0x01}, + {0x8762,0xd0}, + {0x8763,0x00}, + {0x8764,0xef}, + {0x8765,0x4b}, + {0x8766,0xff}, + {0x8767,0xee}, + {0x8768,0x4a}, + {0x8769,0xfe}, + {0x876a,0xed}, + {0x876b,0x49}, + {0x876c,0xfd}, + {0x876d,0xec}, + {0x876e,0x48}, + {0x876f,0xfc}, + {0x8770,0xc0}, + {0x8771,0x04}, + {0x8772,0xc0}, + {0x8773,0x05}, + {0x8774,0xc0}, + {0x8775,0x06}, + {0x8776,0xc0}, + {0x8777,0x07}, + {0x8778,0xaf}, + {0x8779,0x3b}, + {0x877a,0xe4}, + {0x877b,0xfc}, + {0x877c,0xfd}, + {0x877d,0xfe}, + {0x877e,0x78}, + {0x877f,0x08}, + {0x8780,0x12}, + {0x8781,0x01}, + {0x8782,0x33}, + {0x8783,0xd0}, + {0x8784,0x03}, + {0x8785,0xd0}, + {0x8786,0x02}, + {0x8787,0xd0}, + {0x8788,0x01}, + {0x8789,0xd0}, + {0x878a,0x00}, + {0x878b,0xef}, + {0x878c,0x4b}, + {0x878d,0xfb}, + {0x878e,0xee}, + {0x878f,0x4a}, + {0x8790,0xfa}, + {0x8791,0xed}, + {0x8792,0x49}, + {0x8793,0xf9}, + {0x8794,0xec}, + {0x8795,0x48}, + {0x8796,0xf8}, + {0x8797,0xaf}, + {0x8798,0x3c}, + {0x8799,0xeb}, + {0x879a,0x4f}, + {0x879b,0xf5}, + {0x879c,0x2d}, + {0x879d,0xea}, + {0x879e,0xf5}, + {0x879f,0x2c}, + {0x87a0,0xe9}, + {0x87a1,0xf5}, + {0x87a2,0x2b}, + {0x87a3,0xe8}, + {0x87a4,0xf5}, + {0x87a5,0x2a}, + {0x87a6,0xd2}, + {0x87a7,0x20}, + {0x87a8,0x22}, + {0x87a9,0xc0}, + {0x87aa,0xe0}, + {0x87ab,0xc0}, + {0x87ac,0x83}, + {0x87ad,0xc0}, + {0x87ae,0x82}, + {0x87af,0xc0}, + {0x87b0,0xd0}, + {0x87b1,0x75}, + {0x87b2,0xd0}, + {0x87b3,0x00}, + {0x87b4,0xc0}, + {0x87b5,0x00}, + {0x87b6,0xc0}, + {0x87b7,0x06}, + {0x87b8,0xc0}, + {0x87b9,0x07}, + {0x87ba,0x90}, + {0x87bb,0x37}, + {0x87bc,0x08}, + {0x87bd,0xe0}, + {0x87be,0xf5}, + {0x87bf,0x08}, + {0x87c0,0xe5}, + {0x87c1,0x08}, + {0x87c2,0x30}, + {0x87c3,0xe3}, + {0x87c4,0x23}, + {0x87c5,0x20}, + {0x87c6,0x26}, + {0x87c7,0x20}, + {0x87c8,0x90}, + {0x87c9,0x3a}, + {0x87ca,0x00}, + {0x87cb,0x74}, + {0x87cc,0x81}, + {0x87cd,0xf0}, + {0x87ce,0x90}, + {0x87cf,0x3a}, + {0x87d0,0x03}, + {0x87d1,0xe0}, + {0x87d2,0xf5}, + {0x87d3,0x3e}, + {0x87d4,0xe0}, + {0x87d5,0xf5}, + {0x87d6,0x3d}, + {0x87d7,0x90}, + {0x87d8,0x3a}, + {0x87d9,0x00}, + {0x87da,0x74}, + {0x87db,0x85}, + {0x87dc,0xf0}, + {0x87dd,0x90}, + {0x87de,0x3a}, + {0x87df,0x03}, + {0x87e0,0xe0}, + {0x87e1,0xf5}, + {0x87e2,0x40}, + {0x87e3,0xe0}, + {0x87e4,0xf5}, + {0x87e5,0x3f}, + {0x87e6,0xd2}, + {0x87e7,0x2f}, + {0x87e8,0xe5}, + {0x87e9,0x08}, + {0x87ea,0x30}, + {0x87eb,0xe5}, + {0x87ec,0x56}, + {0x87ed,0x90}, + {0x87ee,0x30}, + {0x87ef,0x1b}, + {0x87f0,0xe0}, + {0x87f1,0xf5}, + {0x87f2,0x42}, + {0x87f3,0xe5}, + {0x87f4,0x41}, + {0x87f5,0x24}, + {0x87f6,0x02}, + {0x87f7,0xff}, + {0x87f8,0xe4}, + {0x87f9,0x33}, + {0x87fa,0xfe}, + {0x87fb,0xc3}, + {0x87fc,0xef}, + {0x87fd,0x95}, + {0x87fe,0x42}, + {0x87ff,0x74}, + {0x8800,0x80}, + {0x8801,0xf8}, + {0x8802,0x6e}, + {0x8803,0x98}, + {0x8804,0x50}, + {0x8805,0x02}, + {0x8806,0x80}, + {0x8807,0x01}, + {0x8808,0xc3}, + {0x8809,0x92}, + {0x880a,0x24}, + {0x880b,0xe5}, + {0x880c,0x42}, + {0x880d,0x24}, + {0x880e,0x02}, + {0x880f,0xff}, + {0x8810,0xe4}, + {0x8811,0x33}, + {0x8812,0xfe}, + {0x8813,0xc3}, + {0x8814,0xef}, + {0x8815,0x95}, + {0x8816,0x41}, + {0x8817,0x74}, + {0x8818,0x80}, + {0x8819,0xf8}, + {0x881a,0x6e}, + {0x881b,0x98}, + {0x881c,0x50}, + {0x881d,0x02}, + {0x881e,0x80}, + {0x881f,0x02}, + {0x8820,0xa2}, + {0x8821,0x24}, + {0x8822,0x92}, + {0x8823,0x24}, + {0x8824,0x30}, + {0x8825,0x24}, + {0x8826,0x04}, + {0x8827,0xaf}, + {0x8828,0x42}, + {0x8829,0x80}, + {0x882a,0x02}, + {0x882b,0xaf}, + {0x882c,0x41}, + {0x882d,0x8f}, + {0x882e,0x41}, + {0x882f,0x30}, + {0x8830,0x27}, + {0x8831,0x11}, + {0x8832,0x90}, + {0x8833,0x33}, + {0x8834,0x00}, + {0x8835,0xe0}, + {0x8836,0x30}, + {0x8837,0x29}, + {0x8838,0x05}, + {0x8839,0x44}, + {0x883a,0x40}, + {0x883b,0xf0}, + {0x883c,0x80}, + {0x883d,0x03}, + {0x883e,0x54}, + {0x883f,0xbf}, + {0x8840,0xf0}, + {0x8841,0xc2}, + {0x8842,0x27}, + {0x8843,0xe5}, + {0x8844,0x08}, + {0x8845,0x30}, + {0x8846,0xe1}, + {0x8847,0x08}, + {0x8848,0x90}, + {0x8849,0x3f}, + {0x884a,0x00}, + {0x884b,0xe0}, + {0x884c,0xf5}, + {0x884d,0x29}, + {0x884e,0xe4}, + {0x884f,0xf0}, + {0x8850,0x90}, + {0x8851,0x37}, + {0x8852,0x08}, + {0x8853,0xe5}, + {0x8854,0x08}, + {0x8855,0xf0}, + {0x8856,0xd0}, + {0x8857,0x07}, + {0x8858,0xd0}, + {0x8859,0x06}, + {0x885a,0xd0}, + {0x885b,0x00}, + {0x885c,0xd0}, + {0x885d,0xd0}, + {0x885e,0xd0}, + {0x885f,0x82}, + {0x8860,0xd0}, + {0x8861,0x83}, + {0x8862,0xd0}, + {0x8863,0xe0}, + {0x8864,0x32}, + {0x8865,0x12}, + {0x8866,0x04}, + {0x8867,0xbe}, + {0x8868,0xb5}, + {0x8869,0x07}, + {0x886a,0x03}, + {0x886b,0xd3}, + {0x886c,0x80}, + {0x886d,0x01}, + {0x886e,0xc3}, + {0x886f,0x40}, + {0x8870,0x03}, + {0x8871,0x02}, + {0x8872,0x08}, + {0x8873,0xf9}, + {0x8874,0x90}, + {0x8875,0x31}, + {0x8876,0x00}, + {0x8877,0xe0}, + {0x8878,0x54}, + {0x8879,0xfe}, + {0x887a,0xf0}, + {0x887b,0xe0}, + {0x887c,0x54}, + {0x887d,0xfd}, + {0x887e,0xf0}, + {0x887f,0xa3}, + {0x8880,0xe4}, + {0x8881,0xf0}, + {0x8882,0x90}, + {0x8883,0x33}, + {0x8884,0x00}, + {0x8885,0xe0}, + {0x8886,0x54}, + {0x8887,0xbf}, + {0x8888,0xf0}, + {0x8889,0x12}, + {0x888a,0x04}, + {0x888b,0x8b}, + {0x888c,0x90}, + {0x888d,0x33}, + {0x888e,0xb0}, + {0x888f,0xf0}, + {0x8890,0xa3}, + {0x8891,0xf0}, + {0x8892,0xa3}, + {0x8893,0xf0}, + {0x8894,0x90}, + {0x8895,0x30}, + {0x8896,0xb2}, + {0x8897,0xe0}, + {0x8898,0x44}, + {0x8899,0x08}, + {0x889a,0xf0}, + {0x889b,0x90}, + {0x889c,0x30}, + {0x889d,0xb0}, + {0x889e,0xe0}, + {0x889f,0x44}, + {0x88a0,0x01}, + {0x88a1,0xf0}, + {0x88a2,0xa3}, + {0x88a3,0xe0}, + {0x88a4,0x44}, + {0x88a5,0x0c}, + {0x88a6,0xf0}, + {0x88a7,0x90}, + {0x88a8,0x30}, + {0x88a9,0xb4}, + {0x88aa,0xe0}, + {0x88ab,0x44}, + {0x88ac,0x07}, + {0x88ad,0xf0}, + {0x88ae,0xe0}, + {0x88af,0xf5}, + {0x88b0,0x23}, + {0x88b1,0x90}, + {0x88b2,0x30}, + {0x88b3,0xb1}, + {0x88b4,0xe0}, + {0x88b5,0xf5}, + {0x88b6,0x21}, + {0x88b7,0x90}, + {0x88b8,0x39}, + {0x88b9,0x01}, + {0x88ba,0x74}, + {0x88bb,0x35}, + {0x88bc,0xf0}, + {0x88bd,0x90}, + {0x88be,0x39}, + {0x88bf,0x00}, + {0x88c0,0x74}, + {0x88c1,0x20}, + {0x88c2,0xf0}, + {0x88c3,0x90}, + {0x88c4,0x37}, + {0x88c5,0x00}, + {0x88c6,0x74}, + {0x88c7,0xff}, + {0x88c8,0xf0}, + {0x88c9,0xa3}, + {0x88ca,0xf0}, + {0x88cb,0x90}, + {0x88cc,0x37}, + {0x88cd,0x00}, + {0x88ce,0xe0}, + {0x88cf,0x54}, + {0x88d0,0xf7}, + {0x88d1,0xf0}, + {0x88d2,0xe0}, + {0x88d3,0x54}, + {0x88d4,0xdf}, + {0x88d5,0xf0}, + {0x88d6,0x90}, + {0x88d7,0x31}, + {0x88d8,0x0f}, + {0x88d9,0x74}, + {0x88da,0x3f}, + {0x88db,0xf0}, + {0x88dc,0xa3}, + {0x88dd,0xe4}, + {0x88de,0xf0}, + {0x88df,0xa3}, + {0x88e0,0x74}, + {0x88e1,0x3f}, + {0x88e2,0xf0}, + {0x88e3,0xa3}, + {0x88e4,0x74}, + {0x88e5,0x01}, + {0x88e6,0xf0}, + {0x88e7,0x90}, + {0x88e8,0x37}, + {0x88e9,0x00}, + {0x88ea,0xe0}, + {0x88eb,0x54}, + {0x88ec,0xfd}, + {0x88ed,0xf0}, + {0x88ee,0x90}, + {0x88ef,0x37}, + {0x88f0,0x08}, + {0x88f1,0x74}, + {0x88f2,0xff}, + {0x88f3,0xf0}, + {0x88f4,0xa3}, + {0x88f5,0xf0}, + {0x88f6,0x75}, + {0x88f7,0xa8}, + {0x88f8,0x01}, + {0x88f9,0x22}, + {0x88fa,0xe5}, + {0x88fb,0x0a}, + {0x88fc,0x25}, + {0x88fd,0xe0}, + {0x88fe,0x25}, + {0x88ff,0xe0}, + {0x8900,0xf5}, + {0x8901,0x0b}, + {0x8902,0xe5}, + {0x8903,0x09}, + {0x8904,0x60}, + {0x8905,0x09}, + {0x8906,0xe5}, + {0x8907,0x0a}, + {0x8908,0x75}, + {0x8909,0xf0}, + {0x890a,0x03}, + {0x890b,0xa4}, + {0x890c,0xff}, + {0x890d,0x80}, + {0x890e,0x02}, + {0x890f,0xaf}, + {0x8910,0x0b}, + {0x8911,0x8f}, + {0x8912,0x0c}, + {0x8913,0xc3}, + {0x8914,0x74}, + {0x8915,0x0f}, + {0x8916,0x9f}, + {0x8917,0x78}, + {0x8918,0x10}, + {0x8919,0x12}, + {0x891a,0x04}, + {0x891b,0x71}, + {0x891c,0xc0}, + {0x891d,0x04}, + {0x891e,0xc0}, + {0x891f,0x05}, + {0x8920,0xc0}, + {0x8921,0x06}, + {0x8922,0xc0}, + {0x8923,0x07}, + {0x8924,0xc3}, + {0x8925,0x74}, + {0x8926,0x14}, + {0x8927,0x95}, + {0x8928,0x0b}, + {0x8929,0x78}, + {0x892a,0x18}, + {0x892b,0x12}, + {0x892c,0x04}, + {0x892d,0x71}, + {0x892e,0xd0}, + {0x892f,0x03}, + {0x8930,0xd0}, + {0x8931,0x02}, + {0x8932,0xd0}, + {0x8933,0x01}, + {0x8934,0xd0}, + {0x8935,0x00}, + {0x8936,0xef}, + {0x8937,0x4b}, + {0x8938,0xff}, + {0x8939,0xee}, + {0x893a,0x4a}, + {0x893b,0xfe}, + {0x893c,0xed}, + {0x893d,0x49}, + {0x893e,0xfd}, + {0x893f,0xec}, + {0x8940,0x48}, + {0x8941,0xfc}, + {0x8942,0xc0}, + {0x8943,0x04}, + {0x8944,0xc0}, + {0x8945,0x05}, + {0x8946,0xc0}, + {0x8947,0x06}, + {0x8948,0xc0}, + {0x8949,0x07}, + {0x894a,0xe5}, + {0x894b,0x0b}, + {0x894c,0x24}, + {0x894d,0x14}, + {0x894e,0xff}, + {0x894f,0xe4}, + {0x8950,0x33}, + {0x8951,0xfe}, + {0x8952,0xe4}, + {0x8953,0xfc}, + {0x8954,0xfd}, + {0x8955,0x78}, + {0x8956,0x08}, + {0x8957,0x12}, + {0x8958,0x01}, + {0x8959,0x33}, + {0x895a,0xd0}, + {0x895b,0x03}, + {0x895c,0xd0}, + {0x895d,0x02}, + {0x895e,0xd0}, + {0x895f,0x01}, + {0x8960,0xd0}, + {0x8961,0x00}, + {0x8962,0xef}, + {0x8963,0x4b}, + {0x8964,0xfb}, + {0x8965,0xee}, + {0x8966,0x4a}, + {0x8967,0xfa}, + {0x8968,0xed}, + {0x8969,0x49}, + {0x896a,0xf9}, + {0x896b,0xec}, + {0x896c,0x48}, + {0x896d,0xf8}, + {0x896e,0xe5}, + {0x896f,0x0c}, + {0x8970,0x24}, + {0x8971,0x0f}, + {0x8972,0xff}, + {0x8973,0xe4}, + {0x8974,0x33}, + {0x8975,0xfe}, + {0x8976,0xeb}, + {0x8977,0x4f}, + {0x8978,0xf5}, + {0x8979,0x2d}, + {0x897a,0xea}, + {0x897b,0x4e}, + {0x897c,0xf5}, + {0x897d,0x2c}, + {0x897e,0xe9}, + {0x897f,0xf5}, + {0x8980,0x2b}, + {0x8981,0xe8}, + {0x8982,0xf5}, + {0x8983,0x2a}, + {0x8984,0x22}, + {0x8985,0xe5}, + {0x8986,0x45}, + {0x8987,0x64}, + {0x8988,0x01}, + {0x8989,0x70}, + {0x898a,0x50}, + {0x898b,0x12}, + {0x898c,0x04}, + {0x898d,0x6a}, + {0x898e,0xe5}, + {0x898f,0x44}, + {0x8990,0x12}, + {0x8991,0x04}, + {0x8992,0x18}, + {0x8993,0xfe}, + {0x8994,0xe4}, + {0x8995,0x8f}, + {0x8996,0x3c}, + {0x8997,0x8e}, + {0x8998,0x3b}, + {0x8999,0xf5}, + {0x899a,0x3a}, + {0x899b,0xf5}, + {0x899c,0x39}, + {0x899d,0x12}, + {0x899e,0x04}, + {0x899f,0x44}, + {0x89a0,0x7b}, + {0x89a1,0xff}, + {0x89a2,0xfa}, + {0x89a3,0xf9}, + {0x89a4,0xf8}, + {0x89a5,0x12}, + {0x89a6,0x04}, + {0x89a7,0x39}, + {0x89a8,0xc0}, + {0x89a9,0x04}, + {0x89aa,0xc0}, + {0x89ab,0x05}, + {0x89ac,0xc0}, + {0x89ad,0x06}, + {0x89ae,0xc0}, + {0x89af,0x07}, + {0x89b0,0x12}, + {0x89b1,0x04}, + {0x89b2,0x10}, + {0x89b3,0xab}, + {0x89b4,0x07}, + {0x89b5,0xfa}, + {0x89b6,0xe4}, + {0x89b7,0xf9}, + {0x89b8,0xf8}, + {0x89b9,0xd0}, + {0x89ba,0x07}, + {0x89bb,0xd0}, + {0x89bc,0x06}, + {0x89bd,0xd0}, + {0x89be,0x05}, + {0x89bf,0xd0}, + {0x89c0,0x04}, + {0x89c1,0x12}, + {0x89c2,0x04}, + {0x89c3,0x9f}, + {0x89c4,0x85}, + {0x89c5,0x3c}, + {0x89c6,0x39}, + {0x89c7,0x85}, + {0x89c8,0x44}, + {0x89c9,0x3a}, + {0x89ca,0x12}, + {0x89cb,0x04}, + {0x89cc,0x6a}, + {0x89cd,0xe5}, + {0x89ce,0x44}, + {0x89cf,0x12}, + {0x89d0,0x04}, + {0x89d1,0xd4}, + {0x89d2,0xe4}, + {0x89d3,0x93}, + {0x89d4,0xf5}, + {0x89d5,0x3b}, + {0x89d6,0x74}, + {0x89d7,0x01}, + {0x89d8,0x93}, + {0x89d9,0xf5}, + {0x89da,0x3c}, + {0x89db,0x90}, + {0x89dc,0x3f}, + {0x89dd,0x02}, + {0x89de,0xe5}, + {0x89df,0x39}, + {0x89e0,0xf0}, + {0x89e1,0xa3}, + {0x89e2,0xe5}, + {0x89e3,0x3a}, + {0x89e4,0xf0}, + {0x89e5,0xa3}, + {0x89e6,0xe5}, + {0x89e7,0x3b}, + {0x89e8,0xf0}, + {0x89e9,0xa3}, + {0x89ea,0xe5}, + {0x89eb,0x3c}, + {0x89ec,0xf0}, + {0x89ed,0x22}, + {0x89ee,0xe5}, + {0x89ef,0x09}, + {0x89f0,0xd3}, + {0x89f1,0x95}, + {0x89f2,0x43}, + {0x89f3,0x40}, + {0x89f4,0x01}, + {0x89f5,0x22}, + {0x89f6,0x12}, + {0x89f7,0x04}, + {0x89f8,0x6a}, + {0x89f9,0xe5}, + {0x89fa,0x09}, + {0x89fb,0x12}, + {0x89fc,0x04}, + {0x89fd,0xd4}, + {0x89fe,0xe4}, + {0x89ff,0x93}, + {0x8a00,0xfe}, + {0x8a01,0x74}, + {0x8a02,0x01}, + {0x8a03,0x93}, + {0x8a04,0xff}, + {0x8a05,0x4e}, + {0x8a06,0x60}, + {0x8a07,0x21}, + {0x8a08,0x8e}, + {0x8a09,0x37}, + {0x8a0a,0x8f}, + {0x8a0b,0x38}, + {0x8a0c,0xef}, + {0x8a0d,0xc4}, + {0x8a0e,0xf8}, + {0x8a0f,0x54}, + {0x8a10,0x0f}, + {0x8a11,0xc8}, + {0x8a12,0x68}, + {0x8a13,0xff}, + {0x8a14,0xee}, + {0x8a15,0xc4}, + {0x8a16,0x54}, + {0x8a17,0xf0}, + {0x8a18,0x48}, + {0x8a19,0xfe}, + {0x8a1a,0x43}, + {0x8a1b,0x07}, + {0x8a1c,0x0d}, + {0x8a1d,0x8e}, + {0x8a1e,0x0a}, + {0x8a1f,0x8f}, + {0x8a20,0x0b}, + {0x8a21,0x12}, + {0x8a22,0x01}, + {0x8a23,0x78}, + {0x8a24,0x30}, + {0x8a25,0x23}, + {0x8a26,0x22}, + {0x8a27,0xc3}, + {0x8a28,0x22}, + {0x8a29,0x75}, + {0x8a2a,0x0a}, + {0x8a2b,0x00}, + {0x8a2c,0x75}, + {0x8a2d,0x0b}, + {0x8a2e,0x0d}, + {0x8a2f,0x12}, + {0x8a30,0x01}, + {0x8a31,0x78}, + {0x8a32,0x30}, + {0x8a33,0x23}, + {0x8a34,0x02}, + {0x8a35,0xc3}, + {0x8a36,0x22}, + {0x8a37,0x75}, + {0x8a38,0x0a}, + {0x8a39,0x00}, + {0x8a3a,0x75}, + {0x8a3b,0x0b}, + {0x8a3c,0x64}, + {0x8a3d,0x12}, + {0x8a3e,0x0c}, + {0x8a3f,0x67}, + {0x8a40,0x75}, + {0x8a41,0x0a}, + {0x8a42,0x80}, + {0x8a43,0x75}, + {0x8a44,0x0b}, + {0x8a45,0x00}, + {0x8a46,0x12}, + {0x8a47,0x01}, + {0x8a48,0x78}, + {0x8a49,0x85}, + {0x8a4a,0x09}, + {0x8a4b,0x44}, + {0x8a4c,0xd3}, + {0x8a4d,0x22}, + {0x8a4e,0xc2}, + {0x8a4f,0x25}, + {0x8a50,0x20}, + {0x8a51,0x05}, + {0x8a52,0x05}, + {0x8a53,0x75}, + {0x8a54,0x09}, + {0x8a55,0xee}, + {0x8a56,0x80}, + {0x8a57,0x36}, + {0x8a58,0x20}, + {0x8a59,0x07}, + {0x8a5a,0x08}, + {0x8a5b,0x20}, + {0x8a5c,0x06}, + {0x8a5d,0x05}, + {0x8a5e,0xe4}, + {0x8a5f,0xf5}, + {0x8a60,0x09}, + {0x8a61,0x80}, + {0x8a62,0x2b}, + {0x8a63,0x20}, + {0x8a64,0x07}, + {0x8a65,0x08}, + {0x8a66,0x30}, + {0x8a67,0x06}, + {0x8a68,0x05}, + {0x8a69,0x75}, + {0x8a6a,0x09}, + {0x8a6b,0x20}, + {0x8a6c,0x80}, + {0x8a6d,0x20}, + {0x8a6e,0x30}, + {0x8a6f,0x00}, + {0x8a70,0x05}, + {0x8a71,0x75}, + {0x8a72,0x09}, + {0x8a73,0x01}, + {0x8a74,0x80}, + {0x8a75,0x18}, + {0x8a76,0xe5}, + {0x8a77,0x20}, + {0x8a78,0x54}, + {0x8a79,0x07}, + {0x8a7a,0xff}, + {0x8a7b,0xbf}, + {0x8a7c,0x06}, + {0x8a7d,0x0d}, + {0x8a7e,0x30}, + {0x8a7f,0x21}, + {0x8a80,0x04}, + {0x8a81,0x7f}, + {0x8a82,0x12}, + {0x8a83,0x80}, + {0x8a84,0x02}, + {0x8a85,0x7f}, + {0x8a86,0x02}, + {0x8a87,0x8f}, + {0x8a88,0x09}, + {0x8a89,0x80}, + {0x8a8a,0x03}, + {0x8a8b,0x75}, + {0x8a8c,0x09}, + {0x8a8d,0xfe}, + {0x8a8e,0x90}, + {0x8a8f,0x3f}, + {0x8a90,0x07}, + {0x8a91,0xe5}, + {0x8a92,0x09}, + {0x8a93,0xf0}, + {0x8a94,0x90}, + {0x8a95,0x3f}, + {0x8a96,0x06}, + {0x8a97,0xe5}, + {0x8a98,0x44}, + {0x8a99,0xf0}, + {0x8a9a,0x22}, + {0x8a9b,0x85}, + {0x8a9c,0x0d}, + {0x8a9d,0x0e}, + {0x8a9e,0x7f}, + {0x8a9f,0x08}, + {0x8aa0,0xe5}, + {0x8aa1,0x0e}, + {0x8aa2,0x30}, + {0x8aa3,0xe7}, + {0x8aa4,0x04}, + {0x8aa5,0xd2}, + {0x8aa6,0x19}, + {0x8aa7,0x80}, + {0x8aa8,0x02}, + {0x8aa9,0xc2}, + {0x8aaa,0x19}, + {0x8aab,0x12}, + {0x8aac,0x04}, + {0x8aad,0x09}, + {0x8aae,0x75}, + {0x8aaf,0x32}, + {0x8ab0,0x0a}, + {0x8ab1,0xae}, + {0x8ab2,0x32}, + {0x8ab3,0x15}, + {0x8ab4,0x32}, + {0x8ab5,0xee}, + {0x8ab6,0x70}, + {0x8ab7,0xf9}, + {0x8ab8,0xe5}, + {0x8ab9,0x0e}, + {0x8aba,0x25}, + {0x8abb,0xe0}, + {0x8abc,0xf5}, + {0x8abd,0x0e}, + {0x8abe,0xd2}, + {0x8abf,0x18}, + {0x8ac0,0x12}, + {0x8ac1,0x04}, + {0x8ac2,0x09}, + {0x8ac3,0x75}, + {0x8ac4,0x32}, + {0x8ac5,0x0a}, + {0x8ac6,0xae}, + {0x8ac7,0x32}, + {0x8ac8,0x15}, + {0x8ac9,0x32}, + {0x8aca,0xee}, + {0x8acb,0x70}, + {0x8acc,0xf9}, + {0x8acd,0xc2}, + {0x8ace,0x18}, + {0x8acf,0x12}, + {0x8ad0,0x04}, + {0x8ad1,0x09}, + {0x8ad2,0x75}, + {0x8ad3,0x32}, + {0x8ad4,0x05}, + {0x8ad5,0xae}, + {0x8ad6,0x32}, + {0x8ad7,0x15}, + {0x8ad8,0x32}, + {0x8ad9,0xee}, + {0x8ada,0x70}, + {0x8adb,0xf9}, + {0x8adc,0xdf}, + {0x8add,0xc2}, + {0x8ade,0x22}, + {0x8adf,0x90}, + {0x8ae0,0x3f}, + {0x8ae1,0x07}, + {0x8ae2,0x74}, + {0x8ae3,0xfa}, + {0x8ae4,0xf0}, + {0x8ae5,0x12}, + {0x8ae6,0x08}, + {0x8ae7,0x65}, + {0x8ae8,0x12}, + {0x8ae9,0x0b}, + {0x8aea,0xfb}, + {0x8aeb,0xe4}, + {0x8aec,0xf5}, + {0x8aed,0x29}, + {0x8aee,0xd2}, + {0x8aef,0xaf}, + {0x8af0,0x12}, + {0x8af1,0x05}, + {0x8af2,0xfc}, + {0x8af3,0x30}, + {0x8af4,0x20}, + {0x8af5,0x03}, + {0x8af6,0x12}, + {0x8af7,0x02}, + {0x8af8,0xc4}, + {0x8af9,0x30}, + {0x8afa,0x25}, + {0x8afb,0x03}, + {0x8afc,0x12}, + {0x8afd,0x0a}, + {0x8afe,0x4e}, + {0x8aff,0x30}, + {0x8b00,0x2f}, + {0x8b01,0xee}, + {0x8b02,0xc2}, + {0x8b03,0x2f}, + {0x8b04,0xd2}, + {0x8b05,0x26}, + {0x8b06,0x30}, + {0x8b07,0x00}, + {0x8b08,0x05}, + {0x8b09,0x12}, + {0x8b0a,0x0b}, + {0x8b0b,0x7b}, + {0x8b0c,0x80}, + {0x8b0d,0x09}, + {0x8b0e,0x20}, + {0x8b0f,0x07}, + {0x8b10,0x06}, + {0x8b11,0x30}, + {0x8b12,0x06}, + {0x8b13,0x03}, + {0x8b14,0x12}, + {0x8b15,0x04}, + {0x8b16,0xf5}, + {0x8b17,0xc2}, + {0x8b18,0x26}, + {0x8b19,0x80}, + {0x8b1a,0xd5}, + {0x8b1b,0xe5}, + {0x8b1c,0x44}, + {0x8b1d,0x70}, + {0x8b1e,0x19}, + {0x8b1f,0x12}, + {0x8b20,0x0d}, + {0x8b21,0x4b}, + {0x8b22,0xc2}, + {0x8b23,0x30}, + {0x8b24,0x12}, + {0x8b25,0x0b}, + {0x8b26,0xd2}, + {0x8b27,0xc2}, + {0x8b28,0x30}, + {0x8b29,0x12}, + {0x8b2a,0x0c}, + {0x8b2b,0x89}, + {0x8b2c,0xc2}, + {0x8b2d,0x03}, + {0x8b2e,0x12}, + {0x8b2f,0x0c}, + {0x8b30,0xfe}, + {0x8b31,0xd2}, + {0x8b32,0x02}, + {0x8b33,0xd2}, + {0x8b34,0x01}, + {0x8b35,0xd2}, + {0x8b36,0x00}, + {0x8b37,0x22}, + {0x8b38,0x30}, + {0x8b39,0x03}, + {0x8b3a,0x08}, + {0x8b3b,0xc2}, + {0x8b3c,0x03}, + {0x8b3d,0xc2}, + {0x8b3e,0x04}, + {0x8b3f,0x12}, + {0x8b40,0x04}, + {0x8b41,0xe4}, + {0x8b42,0x22}, + {0x8b43,0xe4}, + {0x8b44,0xf5}, + {0x8b45,0x09}, + {0x8b46,0x12}, + {0x8b47,0x09}, + {0x8b48,0xee}, + {0x8b49,0xd2}, + {0x8b4a,0x03}, + {0x8b4b,0x22}, + {0x8b4c,0x36}, + {0x8b4d,0x0c}, + {0x8b4e,0x04}, + {0x8b4f,0x00}, + {0x8b50,0x00}, + {0x8b51,0x00}, + {0x8b52,0xc8}, + {0x8b53,0x01}, + {0x8b54,0x2c}, + {0x8b55,0x01}, + {0x8b56,0x5e}, + {0x8b57,0x01}, + {0x8b58,0x8b}, + {0x8b59,0x01}, + {0x8b5a,0xb8}, + {0x8b5b,0x01}, + {0x8b5c,0xe5}, + {0x8b5d,0x02}, + {0x8b5e,0x12}, + {0x8b5f,0x02}, + {0x8b60,0x3f}, + {0x8b61,0x02}, + {0x8b62,0x6c}, + {0x8b63,0x02}, + {0x8b64,0x99}, + {0x8b65,0x02}, + {0x8b66,0xc6}, + {0x8b67,0x02}, + {0x8b68,0xf3}, + {0x8b69,0x07}, + {0x8b6a,0x00}, + {0x8b6b,0x02}, + {0x8b6c,0x4e}, + {0x8b6d,0x02}, + {0x8b6e,0x6c}, + {0x8b6f,0x02}, + {0x8b70,0x8a}, + {0x8b71,0x02}, + {0x8b72,0xa8}, + {0x8b73,0x02}, + {0x8b74,0xc6}, + {0x8b75,0x02}, + {0x8b76,0xe4}, + {0x8b77,0x03}, + {0x8b78,0x02}, + {0x8b79,0x03}, + {0x8b7a,0x20}, + {0x8b7b,0xe5}, + {0x8b7c,0x20}, + {0x8b7d,0x54}, + {0x8b7e,0x07}, + {0x8b7f,0xff}, + {0x8b80,0xbf}, + {0x8b81,0x01}, + {0x8b82,0x03}, + {0x8b83,0x02}, + {0x8b84,0x0b}, + {0x8b85,0x1b}, + {0x8b86,0xe5}, + {0x8b87,0x20}, + {0x8b88,0x54}, + {0x8b89,0x07}, + {0x8b8a,0xff}, + {0x8b8b,0xbf}, + {0x8b8c,0x07}, + {0x8b8d,0x03}, + {0x8b8e,0x02}, + {0x8b8f,0x0c}, + {0x8b90,0x44}, + {0x8b91,0xe5}, + {0x8b92,0x20}, + {0x8b93,0x54}, + {0x8b94,0x07}, + {0x8b95,0xff}, + {0x8b96,0xbf}, + {0x8b97,0x03}, + {0x8b98,0x03}, + {0x8b99,0x02}, + {0x8b9a,0x0b}, + {0x8b9b,0xa8}, + {0x8b9c,0xe5}, + {0x8b9d,0x20}, + {0x8b9e,0x54}, + {0x8b9f,0x07}, + {0x8ba0,0xff}, + {0x8ba1,0xbf}, + {0x8ba2,0x05}, + {0x8ba3,0x03}, + {0x8ba4,0x12}, + {0x8ba5,0x0d}, + {0x8ba6,0x59}, + {0x8ba7,0x22}, + {0x8ba8,0x12}, + {0x8ba9,0x0c}, + {0x8baa,0x21}, + {0x8bab,0xd2}, + {0x8bac,0x30}, + {0x8bad,0x12}, + {0x8bae,0x0b}, + {0x8baf,0xd2}, + {0x8bb0,0xd2}, + {0x8bb1,0x30}, + {0x8bb2,0x12}, + {0x8bb3,0x0c}, + {0x8bb4,0x89}, + {0x8bb5,0xe5}, + {0x8bb6,0x43}, + {0x8bb7,0xd3}, + {0x8bb8,0x95}, + {0x8bb9,0x44}, + {0x8bba,0x40}, + {0x8bbb,0x03}, + {0x8bbc,0xd3}, + {0x8bbd,0x80}, + {0x8bbe,0x01}, + {0x8bbf,0xc3}, + {0x8bc0,0x50}, + {0x8bc1,0x0c}, + {0x8bc2,0x20}, + {0x8bc3,0x28}, + {0x8bc4,0x06}, + {0x8bc5,0x30}, + {0x8bc6,0x2d}, + {0x8bc7,0x03}, + {0x8bc8,0x20}, + {0x8bc9,0x2e}, + {0x8bca,0x03}, + {0x8bcb,0x02}, + {0x8bcc,0x0c}, + {0x8bcd,0xfe}, + {0x8bce,0x12}, + {0x8bcf,0x0c}, + {0x8bd0,0xbf}, + {0x8bd1,0x22}, + {0x8bd2,0x30}, + {0x8bd3,0x30}, + {0x8bd4,0x09}, + {0x8bd5,0x30}, + {0x8bd6,0x2d}, + {0x8bd7,0x06}, + {0x8bd8,0xae}, + {0x8bd9,0x33}, + {0x8bda,0xaf}, + {0x8bdb,0x34}, + {0x8bdc,0x80}, + {0x8bdd,0x04}, + {0x8bde,0xae}, + {0x8bdf,0x3d}, + {0x8be0,0xaf}, + {0x8be1,0x3e}, + {0x8be2,0x8e}, + {0x8be3,0x33}, + {0x8be4,0x8f}, + {0x8be5,0x34}, + {0x8be6,0x30}, + {0x8be7,0x30}, + {0x8be8,0x09}, + {0x8be9,0x30}, + {0x8bea,0x2e}, + {0x8beb,0x06}, + {0x8bec,0xae}, + {0x8bed,0x35}, + {0x8bee,0xaf}, + {0x8bef,0x36}, + {0x8bf0,0x80}, + {0x8bf1,0x04}, + {0x8bf2,0xae}, + {0x8bf3,0x3f}, + {0x8bf4,0xaf}, + {0x8bf5,0x40}, + {0x8bf6,0x8e}, + {0x8bf7,0x35}, + {0x8bf8,0x8f}, + {0x8bf9,0x36}, + {0x8bfa,0x22}, + {0x8bfb,0x12}, + {0x8bfc,0x0c}, + {0x8bfd,0xec}, + {0x8bfe,0x12}, + {0x8bff,0x0d}, + {0x8c00,0x67}, + {0x8c01,0x50}, + {0x8c02,0x04}, + {0x8c03,0xd2}, + {0x8c04,0x05}, + {0x8c05,0x80}, + {0x8c06,0x02}, + {0x8c07,0xc2}, + {0x8c08,0x05}, + {0x8c09,0x12}, + {0x8c0a,0x04}, + {0x8c0b,0x7c}, + {0x8c0c,0xc2}, + {0x8c0d,0x28}, + {0x8c0e,0xc2}, + {0x8c0f,0x21}, + {0x8c10,0xd2}, + {0x8c11,0x25}, + {0x8c12,0x12}, + {0x8c13,0x04}, + {0x8c14,0xbe}, + {0x8c15,0xb5}, + {0x8c16,0x07}, + {0x8c17,0x03}, + {0x8c18,0xd3}, + {0x8c19,0x80}, + {0x8c1a,0x01}, + {0x8c1b,0xc3}, + {0x8c1c,0x40}, + {0x8c1d,0x02}, + {0x8c1e,0xc2}, + {0x8c1f,0x05}, + {0x8c20,0x22}, + {0x8c21,0xd3}, + {0x8c22,0xe5}, + {0x8c23,0x34}, + {0x8c24,0x95}, + {0x8c25,0x3e}, + {0x8c26,0xe5}, + {0x8c27,0x33}, + {0x8c28,0x95}, + {0x8c29,0x3d}, + {0x8c2a,0x40}, + {0x8c2b,0x03}, + {0x8c2c,0xd3}, + {0x8c2d,0x80}, + {0x8c2e,0x01}, + {0x8c2f,0xc3}, + {0x8c30,0x92}, + {0x8c31,0x2d}, + {0x8c32,0xd3}, + {0x8c33,0xe5}, + {0x8c34,0x36}, + {0x8c35,0x95}, + {0x8c36,0x40}, + {0x8c37,0xe5}, + {0x8c38,0x35}, + {0x8c39,0x95}, + {0x8c3a,0x3f}, + {0x8c3b,0x40}, + {0x8c3c,0x03}, + {0x8c3d,0xd3}, + {0x8c3e,0x80}, + {0x8c3f,0x01}, + {0x8c40,0xc3}, + {0x8c41,0x92}, + {0x8c42,0x2e}, + {0x8c43,0x22}, + {0x8c44,0x12}, + {0x8c45,0x0c}, + {0x8c46,0x21}, + {0x8c47,0xd2}, + {0x8c48,0x30}, + {0x8c49,0x12}, + {0x8c4a,0x0b}, + {0x8c4b,0xd2}, + {0x8c4c,0xd2}, + {0x8c4d,0x30}, + {0x8c4e,0x12}, + {0x8c4f,0x0c}, + {0x8c50,0x89}, + {0x8c51,0x12}, + {0x8c52,0x0c}, + {0x8c53,0xfe}, + {0x8c54,0xe5}, + {0x8c55,0x28}, + {0x8c56,0xd3}, + {0x8c57,0x95}, + {0x8c58,0x44}, + {0x8c59,0x40}, + {0x8c5a,0x05}, + {0x8c5b,0xe4}, + {0x8c5c,0x95}, + {0x8c5d,0x44}, + {0x8c5e,0x40}, + {0x8c5f,0x06}, + {0x8c60,0xc2}, + {0x8c61,0x02}, + {0x8c62,0xd2}, + {0x8c63,0x01}, + {0x8c64,0xd2}, + {0x8c65,0x00}, + {0x8c66,0x22}, + {0x8c67,0xe4}, + {0x8c68,0xff}, + {0x8c69,0xfe}, + {0x8c6a,0xc3}, + {0x8c6b,0xef}, + {0x8c6c,0x95}, + {0x8c6d,0x0b}, + {0x8c6e,0xee}, + {0x8c6f,0x95}, + {0x8c70,0x0a}, + {0x8c71,0x50}, + {0x8c72,0x15}, + {0x8c73,0x7d}, + {0x8c74,0x8a}, + {0x8c75,0x7c}, + {0x8c76,0x02}, + {0x8c77,0xed}, + {0x8c78,0x1d}, + {0x8c79,0xaa}, + {0x8c7a,0x04}, + {0x8c7b,0x70}, + {0x8c7c,0x01}, + {0x8c7d,0x1c}, + {0x8c7e,0x4a}, + {0x8c7f,0x70}, + {0x8c80,0xf6}, + {0x8c81,0x0f}, + {0x8c82,0xbf}, + {0x8c83,0x00}, + {0x8c84,0x01}, + {0x8c85,0x0e}, + {0x8c86,0x80}, + {0x8c87,0xe2}, + {0x8c88,0x22}, + {0x8c89,0x30}, + {0x8c8a,0x30}, + {0x8c8b,0x07}, + {0x8c8c,0x30}, + {0x8c8d,0x2d}, + {0x8c8e,0x04}, + {0x8c8f,0xaf}, + {0x8c90,0x30}, + {0x8c91,0x80}, + {0x8c92,0x02}, + {0x8c93,0xaf}, + {0x8c94,0x44}, + {0x8c95,0x8f}, + {0x8c96,0x30}, + {0x8c97,0x30}, + {0x8c98,0x30}, + {0x8c99,0x07}, + {0x8c9a,0x30}, + {0x8c9b,0x2e}, + {0x8c9c,0x04}, + {0x8c9d,0xaf}, + {0x8c9e,0x31}, + {0x8c9f,0x80}, + {0x8ca0,0x02}, + {0x8ca1,0xaf}, + {0x8ca2,0x44}, + {0x8ca3,0x8f}, + {0x8ca4,0x31}, + {0x8ca5,0x22}, + {0x8ca6,0xe5}, + {0x8ca7,0x45}, + {0x8ca8,0xb4}, + {0x8ca9,0x01}, + {0x8caa,0x05}, + {0x8cab,0x12}, + {0x8cac,0x0d}, + {0x8cad,0x1e}, + {0x8cae,0x80}, + {0x8caf,0x08}, + {0x8cb0,0xe5}, + {0x8cb1,0x45}, + {0x8cb2,0xb4}, + {0x8cb3,0x02}, + {0x8cb4,0x09}, + {0x8cb5,0x12}, + {0x8cb6,0x0d}, + {0x8cb7,0x2d}, + {0x8cb8,0xe4}, + {0x8cb9,0xf5}, + {0x8cba,0x09}, + {0x8cbb,0x12}, + {0x8cbc,0x09}, + {0x8cbd,0xee}, + {0x8cbe,0x22}, + {0x8cbf,0xaf}, + {0x8cc0,0x31}, + {0x8cc1,0xe5}, + {0x8cc2,0x44}, + {0x8cc3,0xb5}, + {0x8cc4,0x07}, + {0x8cc5,0x03}, + {0x8cc6,0x02}, + {0x8cc7,0x0c}, + {0x8cc8,0xd8}, + {0x8cc9,0x8f}, + {0x8cca,0x09}, + {0x8ccb,0x12}, + {0x8ccc,0x09}, + {0x8ccd,0xee}, + {0x8cce,0xd2}, + {0x8ccf,0x02}, + {0x8cd0,0xc2}, + {0x8cd1,0x01}, + {0x8cd2,0xd2}, + {0x8cd3,0x00}, + {0x8cd4,0x75}, + {0x8cd5,0x27}, + {0x8cd6,0x03}, + {0x8cd7,0x22}, + {0x8cd8,0xc2}, + {0x8cd9,0x03}, + {0x8cda,0xd2}, + {0x8cdb,0x04}, + {0x8cdc,0x12}, + {0x8cdd,0x04}, + {0x8cde,0xe4}, + {0x8cdf,0xc2}, + {0x8ce0,0x30}, + {0x8ce1,0x12}, + {0x8ce2,0x0b}, + {0x8ce3,0xd2}, + {0x8ce4,0xc2}, + {0x8ce5,0x30}, + {0x8ce6,0x12}, + {0x8ce7,0x0c}, + {0x8ce8,0x89}, + {0x8ce9,0xd2}, + {0x8cea,0x25}, + {0x8ceb,0x22}, + {0x8cec,0x12}, + {0x8ced,0x04}, + {0x8cee,0x8b}, + {0x8cef,0xf5}, + {0x8cf0,0x09}, + {0x8cf1,0x75}, + {0x8cf2,0x0a}, + {0x8cf3,0x01}, + {0x8cf4,0x12}, + {0x8cf5,0x08}, + {0x8cf6,0xfa}, + {0x8cf7,0xd2}, + {0x8cf8,0x20}, + {0x8cf9,0xc2}, + {0x8cfa,0x26}, + {0x8cfb,0xc2}, + {0x8cfc,0x2f}, + {0x8cfd,0x22}, + {0x8cfe,0xe5}, + {0x8cff,0x44}, + {0x8d00,0xc3}, + {0x8d01,0x95}, + {0x8d02,0x43}, + {0x8d03,0x40}, + {0x8d04,0x01}, + {0x8d05,0x22}, + {0x8d06,0xe5}, + {0x8d07,0x44}, + {0x8d08,0x04}, + {0x8d09,0xf5}, + {0x8d0a,0x09}, + {0x8d0b,0x12}, + {0x8d0c,0x09}, + {0x8d0d,0xee}, + {0x8d0e,0x22}, + {0x8d0f,0xe5}, + {0x8d10,0x44}, + {0x8d11,0x70}, + {0x8d12,0x02}, + {0x8d13,0xc3}, + {0x8d14,0x22}, + {0x8d15,0xe5}, + {0x8d16,0x44}, + {0x8d17,0x14}, + {0x8d18,0xf5}, + {0x8d19,0x09}, + {0x8d1a,0x12}, + {0x8d1b,0x09}, + {0x8d1c,0xee}, + {0x8d1d,0x22}, + {0x8d1e,0x75}, + {0x8d1f,0x2e}, + {0x8d20,0x0b}, + {0x8d21,0x75}, + {0x8d22,0x2f}, + {0x8d23,0x4f}, + {0x8d24,0x90}, + {0x8d25,0x0b}, + {0x8d26,0x4d}, + {0x8d27,0x12}, + {0x8d28,0x04}, + {0x8d29,0xda}, + {0x8d2a,0xc2}, + {0x8d2b,0x2c}, + {0x8d2c,0x22}, + {0x8d2d,0x75}, + {0x8d2e,0x2e}, + {0x8d2f,0x0b}, + {0x8d30,0x75}, + {0x8d31,0x2f}, + {0x8d32,0x6b}, + {0x8d33,0x90}, + {0x8d34,0x0b}, + {0x8d35,0x69}, + {0x8d36,0x12}, + {0x8d37,0x04}, + {0x8d38,0xda}, + {0x8d39,0xd2}, + {0x8d3a,0x2c}, + {0x8d3b,0x22}, + {0x8d3c,0xe5}, + {0x8d3d,0x45}, + {0x8d3e,0x24}, + {0x8d3f,0xfe}, + {0x8d40,0x60}, + {0x8d41,0x06}, + {0x8d42,0x04}, + {0x8d43,0x70}, + {0x8d44,0x05}, + {0x8d45,0xd2}, + {0x8d46,0x28}, + {0x8d47,0x22}, + {0x8d48,0xc2}, + {0x8d49,0x28}, + {0x8d4a,0x22}, + {0x8d4b,0xe4}, + {0x8d4c,0xf5}, + {0x8d4d,0x33}, + {0x8d4e,0xf5}, + {0x8d4f,0x34}, + {0x8d50,0xf5}, + {0x8d51,0x35}, + {0x8d52,0xf5}, + {0x8d53,0x36}, + {0x8d54,0xc2}, + {0x8d55,0x2d}, + {0x8d56,0xc2}, + {0x8d57,0x2e}, + {0x8d58,0x22}, + {0x8d59,0xe5}, + {0x8d5a,0x27}, + {0x8d5b,0xd3}, + {0x8d5c,0x94}, + {0x8d5d,0x00}, + {0x8d5e,0x40}, + {0x8d5f,0x03}, + {0x8d60,0x15}, + {0x8d61,0x27}, + {0x8d62,0x22}, + {0x8d63,0x12}, + {0x8d64,0x0c}, + {0x8d65,0xd8}, + {0x8d66,0x22}, + {0x8d67,0x12}, + {0x8d68,0x0d}, + {0x8d69,0x1e}, + {0x8d6a,0xe4}, + {0x8d6b,0xf5}, + {0x8d6c,0x09}, + {0x8d6d,0x12}, + {0x8d6e,0x09}, + {0x8d6f,0xee}, + {0x8d70,0x22}, + {0x3F00,0x00}, + {0x3F01,0x00}, + {0x3F02,0x00}, + {0x3F03,0x00}, + {0x3F04,0x00}, + {0x3F05,0x00}, + {0x3F06,0x00}, + {0x3F07,0xFF}, + {0x3104,0x00}, + {0x0000,0x00} +}; +#endif \ No newline at end of file diff --git a/drivers/media/video/ov7675.c b/drivers/media/video/ov7675.c index 809b41ea4ff5..c9a427147d1c 100755 --- a/drivers/media/video/ov7675.c +++ b/drivers/media/video/ov7675.c @@ -22,6 +22,17 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #include #include +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) + + #define _CONS(a,b) a##b #define CONS(a,b) _CONS(a,b) @@ -29,8 +40,11 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #define _STR(x) __STR(x) #define STR(x) _STR(x) +#define MIN(x,y) ((xy) ? x: y) + /* Sensor Driver Configuration */ -#define SENSOR_NAME ov7675 +#define SENSOR_NAME RK29_CAM_SENSOR_OV7675 #define SENSOR_V4L2_IDENT V4L2_IDENT_OV7675 #define SENSOR_ID 0x76 #define SENSOR_MIN_WIDTH 640//176 @@ -55,27 +69,10 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #define CONFIG_SENSOR_Mirror 0 #define CONFIG_SENSOR_Flip 0 -#define CONFIG_SENSOR_I2C_SPEED 100000 /* Hz */ - -#define CONFIG_SENSOR_TR 1 -#define CONFIG_SENSOR_DEBUG 1 - -#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) -#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) - -#define MIN(x,y) ((xy) ? x: y) - -#if (CONFIG_SENSOR_TR) - #define SENSOR_TR(format, ...) printk(format, ## __VA_ARGS__) - #if (CONFIG_SENSOR_DEBUG) - #define SENSOR_DG(format, ...) printk(format, ## __VA_ARGS__) - #else - #define SENSOR_DG(format, ...) - #endif -#else - #define SENSOR_TR(format, ...) -#endif +#define CONFIG_SENSOR_I2C_SPEED 250000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 #define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ @@ -90,6 +87,9 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #define COLOR_TEMPERATURE_HOME_DN 2500 #define COLOR_TEMPERATURE_HOME_UP 3500 +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + struct reginfo { u8 reg; @@ -144,7 +144,7 @@ static struct reginfo sensor_init_data[] = {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, - {0x1e, 0x07}, + {0x1e, 0x07}, //0x27 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, @@ -1082,6 +1082,14 @@ static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); static int sensor_resume(struct soc_camera_device *icd); static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +static int sensor_deactivate(struct i2c_client *client); + static struct soc_camera_ops sensor_ops = { @@ -1119,6 +1127,8 @@ typedef struct sensor_info_priv_s int focus; int flash; int exposure; + bool snap2preview; + bool video2preview; unsigned char mirror; /* HFLIP */ unsigned char flip; /* VFLIP */ unsigned int winseqe_cur_addr; @@ -1132,6 +1142,11 @@ struct sensor struct i2c_client *client; sensor_info_priv_t info_priv; int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; }; static struct sensor* to_sensor(const struct i2c_client *client) @@ -1139,6 +1154,44 @@ static struct sensor* to_sensor(const struct i2c_client *client) return container_of(i2c_get_clientdata(client), struct sensor, subdev); } +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + /* sensor register write */ static int sensor_write(struct i2c_client *client, u8 reg, u8 val) { @@ -1159,14 +1212,14 @@ static int sensor_write(struct i2c_client *client, u8 reg, u8 val) cnt = 3; err = -EAGAIN; - while ((cnt--) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ err = i2c_transfer(client->adapter, msg, 1); if (err >= 0) { return 0; } else { - SENSOR_TR("\n %s write reg failed, try to write again!\n",SENSOR_NAME_STRING()); - udelay(10); + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); } } @@ -1201,14 +1254,14 @@ static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) cnt = 1; err = -EAGAIN; - while ((cnt--) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ err = i2c_transfer(client->adapter, msg, 2); if (err >= 0) { *val = buf[0]; return 0; } else { - SENSOR_TR("\n %s read reg failed, try to read again! reg:0x%x \n",SENSOR_NAME_STRING(),(unsigned int)val); + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); udelay(10); } } @@ -1220,20 +1273,43 @@ static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) #if 1 static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) { - int err; + int err = 0, cnt; int i = 0; +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; while (regarray[i].reg != 0) { err = sensor_write(client, regarray[i].reg, regarray[i].val); - if (err != 0) + if (err < 0) { - SENSOR_TR("%s..write failed current i = %d\n", SENSOR_NAME_STRING(),i); - return err; + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif } i++; } - return 0; + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; } #else static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) @@ -1256,7 +1332,50 @@ static int sensor_write_array(struct i2c_client *client, struct reginfo *regarra return 0; } #endif +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} static int sensor_init(struct v4l2_subdev *sd, u32 val) { struct i2c_client *client = sd->priv; @@ -1267,7 +1386,14 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; ret = sensor_write(client, 0x12, 0x80); if (ret != 0) { @@ -1284,9 +1410,9 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); goto sensor_INIT_ERR; } - - icd->user_width = SENSOR_INIT_WIDTH; - icd->user_height = SENSOR_INIT_HEIGHT; + sensor_task_lock(client,0); + //icd->user_width = SENSOR_INIT_WIDTH; + //icd->user_height = SENSOR_INIT_HEIGHT; sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; sensor->info_priv.pixfmt = SENSOR_INIT_PIXFMT; @@ -1331,30 +1457,35 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) sensor->info_priv.focus = qctrl->default_value; #endif - #if CONFIG_SENSOR_Flash - sensor_set_flash(); + #if CONFIG_SENSOR_Flash qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); if (qctrl) sensor->info_priv.flash = qctrl->default_value; #endif - SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,icd->user_width,icd->user_height); + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); return 0; sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); return ret; } -static int sensor_deactivate(struct v4l2_subdev *sd) +static int sensor_deactivate(struct i2c_client *client) { - //struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; //u8 reg_val; - SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); - + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); return 0; } static struct reginfo sensor_power_down_sequence[]= @@ -1365,32 +1496,21 @@ static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) { int ret; struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct soc_camera_link *icl; - - if (pm_msg.event == PM_EVENT_SUSPEND) - { + if (pm_msg.event == PM_EVENT_SUSPEND) { SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); ret = sensor_write_array(client, sensor_power_down_sequence) ; - if (ret != 0) - { + if (ret != 0) { SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); return ret; - } - else - { - icl = to_soc_camera_link(icd); - if (icl->power) { - ret = icl->power(icd->pdev, 0); - if (ret < 0) { - SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); - return -EINVAL; - } + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; } } - } - else - { + } else { SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); return -EINVAL; } @@ -1399,16 +1519,12 @@ static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) static int sensor_resume(struct soc_camera_device *icd) { - struct soc_camera_link *icl; - int ret; + int ret; - icl = to_soc_camera_link(icd); - if (icl->power) { - ret = icl->power(icd->pdev, 1); - if (ret < 0) { - SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); - return -EINVAL; - } + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; } SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); @@ -1447,11 +1563,48 @@ static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) return 0; } +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) { + ret = true; + } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) { + ret = true; + } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) { + ret = true; + } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) { + ret = true; + } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 720)) { + ret = true; + } else if ((f->fmt.pix.width == 1920) && (f->fmt.pix.height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { struct i2c_client *client = sd->priv; struct sensor *sensor = to_sensor(client); struct v4l2_pix_format *pix = &f->fmt.pix; + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; struct reginfo *winseqe_set_addr=NULL; char readval; int ret=0, set_w,set_h; @@ -1538,22 +1691,76 @@ static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,pix->width,pix->height); } - if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) - { + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif ret |= sensor_write_array(client, winseqe_set_addr); if (ret != 0) { SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif goto sensor_s_fmt_end; } sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + #endif + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,f) == true) { /* ddl@rock-chips.com : Video */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); } else { - SENSOR_TR("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); } pix->width = set_w; @@ -1857,6 +2064,24 @@ static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4 return -EINVAL; } #endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct i2c_client *client = sd->priv; @@ -2191,6 +2416,8 @@ static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_c #if CONFIG_SENSOR_Flash case V4L2_CID_FLASH: { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; sensor->info_priv.flash = ext_ctrl->value; SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); @@ -2269,6 +2496,10 @@ static int sensor_video_probe(struct soc_camera_device *icd, to_soc_camera_host(icd->dev.parent)->nr != icd->iface) return -ENODEV; + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } /* soft reset */ ret = sensor_write(client, 0x12, 0x80); if (ret != 0) @@ -2307,19 +2538,64 @@ sensor_video_probe_err: static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); switch (cmd) { case RK29_CAM_SUBDEV_DEACTIVATE: { - sensor_deactivate(sd); + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif break; } default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); break; + } } - - return 0; +sensor_ioctl_end: + return ret; } static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { @@ -2379,12 +2655,16 @@ static int sensor_probe(struct i2c_client *client, /* Second stage probe - when a capture adapter is there */ icd->ops = &sensor_ops; icd->y_skip_top = 0; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif ret = sensor_video_probe(icd, client); - if (ret) { + if (ret < 0) { icd->ops = NULL; i2c_set_clientdata(client, NULL); kfree(sensor); + sensor = NULL; } SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); return ret; @@ -2399,7 +2679,7 @@ static int sensor_remove(struct i2c_client *client) i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(sensor); - + sensor = NULL; return 0; } diff --git a/drivers/media/video/sid130B.c b/drivers/media/video/sid130B.c new file mode 100755 index 000000000000..3bd908527014 --- /dev/null +++ b/drivers/media/video/sid130B.c @@ -0,0 +1,3052 @@ +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME sid130B +#define SENSOR_V4L2_IDENT V4L2_IDENT_SID130B +#define SENSOR_ID 0x1B +#define SENSOR_MIN_WIDTH 176 +#define SENSOR_MIN_HEIGHT 144 +#define SENSOR_MAX_WIDTH 1600 +#define SENSOR_MAX_HEIGHT 1200 +#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 480 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_PIX_FMT_UYVY + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 0 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 80000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW|\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +struct reginfo +{ + u8 reg; + u8 val; +}; + +/* init 352X288 SVGA */ +static struct reginfo sensor_init_data[] = +{ + {0x00, 0x00}, + {0x04, 0x00}, //Group A 0x10 + {0x05, 0x0F}, //UXGA Output + {0x06, 0x86}, + {0x07, 0x08}, + + + {0x08, 0xa2}, //PLL off + {0x09, 0x12}, + {0x0A, 0x12}, + {0x10, 0x17}, + {0x11, 0x01}, + {0x12, 0x8A}, + {0x13, 0x1a}, + {0x14, 0x27}, + {0x15, 0x22}, + + {0x17, 0xCb}, + {0x18, 0x38}, + + {0x40, 0x0f}, + {0x41, 0x17}, + {0x42, 0x52}, + {0x43, 0x80}, + {0x44, 0x00}, + {0x45, 0x00}, + +//Flicker - 50Hz - Still mode , + {0x00, 0x00}, + {0x20, 0x00}, + {0x21, 0x02}, + {0x23, 0x29},//15}, + {0x00, 0x01}, + {0x35, 0x50},//3c}, + +//Flicker - 50Hz - Preview mode 24MHz MCLK + {0x00, 0x00}, + {0x24, 0x00}, + {0x25, 0xe6},//10}, + {0x27, 0x0d},//4b}, + {0x00, 0x01}, + {0x34, 0x80},//64}, + + +//AE Block + {0x00, 0x01}, + {0x10, 0x00}, + {0x11, 0x0a}, //.0c + {0x12, 0x78}, + {0x13, 0x78}, + {0x14, 0x78}, + {0x17, 0xC4}, + {0x1c, 0x05}, + + {0x36, 0x28}, //26 + + {0x40, 0x40}, //Max Again //anyuan + //{0x41, 0x20}, + //{0x42, 0x20}, + //{0x43, 0x00}, + //{0x44, 0x00}, + //{0x45, 0x01}, + //{0x46, 0x1c}, + //{0x47, 0x11}, + //{0x48, 0x15}, + //{0x49, 0x17}, + //{0x4A, 0x1a}, + //{0x4B, 0x1c}, + //{0x4C, 0x1e}, + //{0x4D, 0x1e}, + //{0x4E, 0x0f}, + //{0x4F, 0x09}, + //{0x50, 0x07}, + //{0x51, 0x05}, + //{0x52, 0x04}, + //{0x53, 0x03}, + //{0x54, 0x02}, + //{0x55, 0x01}, + //{0x66, 0x00}, + //{0x67, 0x00}, + //{0x68, 0x00}, + //{0x69, 0x00}, + //{0x6a, 0x00}, + //{0x6b, 0x00}, + + {0x70, 0xc4}, + {0x73, 0x22}, + {0x74, 0x07}, + {0x77, 0xd0}, + {0x78, 0xd8}, + {0x79, 0x70}, + // + {0x90, 0x00}, + {0x92, 0x0c}, //0bank 0x11 苞 悼老 + {0x95, 0x40}, //0 bank 0x40 苞 悼老 + //AWB Block + + {0x00, 0x02}, + {0x10, 0xD3}, + {0x11, 0x11}, + {0x13, 0x7e}, + {0x14, 0x7c}, + {0x15, 0xee}, + {0x16, 0x80}, + {0x17, 0xd0}, + {0x18, 0x80}, + {0x19, 0x98}, + {0x1A, 0x68}, + {0x1B, 0x98}, + {0x1C, 0x68}, + {0x1D, 0x90}, + {0x1E, 0x74}, + {0x20, 0xF0}, + {0x21, 0x85}, + {0x22, 0xB4}, + {0x23, 0x20}, + {0x25, 0x20}, + {0x26, 0x05}, + {0x27, 0x78}, + {0x28, 0xd8}, + {0x29, 0xb8}, + {0x2A, 0x88}, + {0x30, 0x00}, + {0x31, 0x10}, + {0x32, 0x00}, + {0x33, 0x10}, + {0x34, 0x06}, + {0x35, 0x30}, + {0x36, 0x04}, + {0x37, 0xA0}, + {0x40, 0x01}, + {0x41, 0x04}, + {0x42, 0x08}, + {0x43, 0x10}, + {0x44, 0x13}, + {0x45, 0x6B}, + {0x46, 0x82}, + + + +//CMA change -D65~A + {0x53, 0xa1}, //AWB R Gain for D30 to D20 + {0x54, 0xc0}, //AWB B Gain for D30 to D20 + {0x55, 0xa1}, //AWB R Gain for D20 to D30 + {0x56, 0xc0}, //AWB B Gain for D20 to D30 + {0x57, 0xc8}, //AWB R Gain for D65 to D30 + {0x58, 0xa0}, //AWB B Gain for D65 to D30 + {0x59, 0xc8}, //AWB R Gain for D30 to D65 + {0x5A, 0xa0}, //AWB B Gain for D30 to D65 + + {0x64, 0x00}, + {0x65, 0x00}, + {0x66, 0x00}, + {0x67, 0x00}, + {0x68, 0xa5}, + {0x69, 0xb4}, + {0x6a, 0xb3}, + {0x6b, 0xac}, + {0x6c, 0xb7}, + {0x6d, 0x98}, + {0x6e, 0xba}, + {0x6f, 0x90}, + + {0x70, 0xbf}, + {0x71, 0x9b}, + {0x72, 0xce}, + {0x73, 0x8c}, + {0x74, 0x7f}, + {0x75, 0x8c}, + {0x76, 0xad}, + {0x77, 0xba}, + {0x78, 0x8f}, + {0x79, 0x9a}, + {0x7A, 0xa3}, + {0x7B, 0xac}, + {0x7C, 0xa0}, + {0x7D, 0xa9}, + {0x7E, 0x95}, + {0x7F, 0xac}, + {0x80, 0xad}, + {0x81, 0xbc}, + {0x82, 0x98}, + {0x83, 0xa4}, + {0x84, 0x00}, + {0x85, 0x00}, + {0x86, 0x00}, + {0x87, 0x00}, + {0x88, 0xc9}, + {0x89, 0xd5}, + {0x8a, 0x70}, + {0x8b, 0x7b}, + {0x8c, 0xd0}, + {0x8d, 0xe5}, + {0x8e, 0x58}, + {0x8f, 0x70}, + + {0xB4, 0x05}, + {0xB5, 0x0F}, + {0xB6, 0x06}, + {0xB7, 0x06}, + {0xB8, 0x40}, + {0xB9, 0x10}, + {0xBA, 0x06}, + +//IDP + {0x00, 0x03}, + {0x10, 0xFF}, + {0x11, 0x1D}, + {0x12, 0x1D}, + {0x13, 0xFF}, + {0x14, 0x00}, + {0x15, 0xc0}, + +//DPC + {0x30, 0x88}, //DPCNRCTRL + {0x31, 0x14}, //DPTHR @ AGAIN = 00 + {0x32, 0x10}, //DPTHR @ AGAIN = 20 + {0x33, 0x0c}, //DPTHR @ AGAIN = 40 + {0x34, 0x08}, //DPTHR @ AGAIN = 60 + {0x35, 0x04}, //DPTHR @ AGAIN = 80 + {0x36, 0x44}, //DPTHVRNG + {0x37, 0x66}, //DPNUMBER + {0x38, 0x00}, //0x00 // NRTHR0 @ AGAIN = 00 + {0x39, 0x04}, //0x0C // NRTHR1 @ AGAIN = 20 + {0x3A, 0x04}, //0x18 // NRTHR2 @ AGAIN = 40 + {0x3B, 0x2c}, //0x30 // NRTHR3 @ AGAIN = 60 + {0x3C, 0x3c}, // NRTHR4 @ AGAIN = 80 + {0x3D, 0x04}, //NRTHVRNG0 @ AGAIN = 00 + {0x3E, 0x04}, //NRTHVRNG1 @ AGAIN = 20 + {0x3F, 0x04}, //NRTHVRNG2 @ AGAIN = 40 + {0x40, 0x2c}, //NRTHVRNG3 @ AGAIN = 60 + {0x41, 0x3c}, //NRTHVRNG4 @ AGAIN = 80 + {0x42, 0xff}, //NRTHVRNGMAX + {0x43, 0x40}, //NRTHRWGT + {0x44, 0x40}, //BASELVL + {0x45, 0x06}, //SHUMAXH + {0x46, 0x40}, //SHUMAXL + {0x47, 0x30}, //ILLUMITHDRK + +// shading + {0x50, 0x0a}, //0x00 + {0x51, 0x20}, //0x45 + {0x52, 0x12}, //0x24 + {0x53, 0x12}, //0x24 + + {0x54, 0x22}, //0x00 + {0x55, 0x18}, //0x40 + {0x56, 0x08}, //0x10 + {0x57, 0x10}, //0x20 + + {0x58, 0x22}, //0x00 + {0x59, 0x18}, //0x40 + {0x5A, 0x08}, //0x10 + {0x5B, 0x10}, //0x20 + + {0x5C, 0x25}, //0x04 + {0x5D, 0x1a}, //0x55 + {0x5E, 0x12}, //0x25 + {0x5F, 0x10}, //0x20 + + {0x60, 0x32}, //0x32 + {0x61, 0x20}, //20// + {0x62, 0x58}, //67 +// {0x63, 0x89 //8c R Center start gain +// {0x66, 0x79 //B Center start gain 73 + {0x6B, 0x00}, //01 //01 + {0x6C, 0x01}, //22 + {0x6D, 0x23}, //22 + {0x6E, 0x55}, //55 + {0x6F, 0x55}, //77 + {0x70, 0x55}, //65 + {0x71, 0x00}, //01 //AB (6) + {0x72, 0x01}, //23 (5) + {0x73, 0x23}, //33 (4) + {0x74, 0x44}, //45 (3) + {0x75, 0x45}, //55 (2) + {0x76, 0x66}, //55 (1) + {0x77, 0x00}, //01 //AB (6) + {0x78, 0x01}, //23 (5) + {0x79, 0x23}, //33 (4) + {0x7A, 0x44}, //45 (3) + {0x7B, 0x45}, //55 (2) + {0x7C, 0x66}, //55 (1) + {0x7D, 0x00}, //00 //00 + {0x7E, 0x00}, //00 //00 + {0x7F, 0x12}, //11 //12 + {0x80, 0x33}, //33 //33 //44 + {0x81, 0x44}, //33 //33 //44 + {0x82, 0x55}, //22 //44 //45 + //{0x83, 0x14}, + //{0x84, 0x0f}, + + {0x94,0x02}, + {0x95,0x80}, + {0x96,0x01}, + {0x97,0xe0}, + +//Interpolation + {0xA0, 0x3F}, + {0xA1, 0x05}, + {0xA2, 0xB7}, + {0xA3, 0xB7}, + {0xA4, 0x04}, + {0xA5, 0xFF}, + {0xA6, 0x04}, + {0xA7, 0xFF}, + {0xA8, 0x00}, + {0xA9, 0x00}, + {0xAA, 0x00}, + {0xAB, 0x00}, + {0xAC, 0x60}, + {0xAD, 0x18}, + {0xAE, 0x10}, + {0xAF, 0x20}, + {0xB0, 0x08}, + {0xB1, 0x00}, + +//Color Matrix for D65 +#if 0 + {0xC0, 0x2F}, // CMASB D20 or D30 or Dark Condition Color Matrix Selection + {0xC1, 0x66}, + {0xC2, 0xd4}, + {0xC3, 0x05}, + {0xC4, 0xf0}, + {0xC5, 0x5a}, + {0xC6, 0xf5}, + {0xC7, 0xf9}, + {0xC8, 0xbf}, + {0xC9, 0x88}, + {0xCA, 0xa0}, + {0xCB, 0x50}, + {0xCC, 0xe2}, + {0xCD, 0x00}, + {0xCE, 0x00}, +#else +{0xC0, 0x2F}, // CMASB D20 or D30 or Dark Condition Color Matrix Selection +{0xC1, 0x71}, +{0xC2, 0xcc}, +{0xC3, 0x01}, +{0xC4, 0xe8}, +{0xC5, 0x68}, +{0xC6, 0xef}, +{0xC7, 0xfa}, +{0xC8, 0xc6}, +{0xC9, 0x7e}, +{0xCA, 0xec}, +{0xCB, 0x67}, +{0xCC, 0x34}, +{0xCD, 0x3a}, +{0xCE, 0x08}, + +#endif +//Color Matrix for CWF + {0xD0, 0x2F}, + {0xD1, 0x66}, + {0xD2, 0xd4}, + {0xD3, 0x05}, + {0xD4, 0xf0}, + {0xD5, 0x5a}, + {0xD6, 0xf5}, + {0xD7, 0xe9}, + {0xD8, 0xbf}, + {0xD9, 0x88}, + {0xDA, 0xa0}, + {0xDB, 0x50}, + {0xDC, 0xe2}, + {0xDD, 0x00}, + {0xDE, 0x00}, + +//Color Matrix for A + {0xE0, 0x2F}, + {0xE1, 0x6e}, + {0xE2, 0xc7}, + {0xE3, 0x0d}, + {0xE4, 0xe3}, + {0xE5, 0x61}, + {0xE6, 0xfa}, + {0xE7, 0xe5}, + {0xE8, 0xcb}, + {0xE9, 0x8e}, + {0xEA, 0xc4}, + {0xEB, 0x04}, + {0xEC, 0xf3}, + {0xED, 0xdd}, + {0xEE, 0x06}, + +//IDP 4 + {0x00, 0x04}, + +//Gamma - r + {0x10, 0x00}, + {0x11, 0x04}, + {0x12, 0x10}, + {0x13, 0x20}, + {0x14, 0x40}, + {0x15, 0x5c}, + {0x16, 0x74}, + {0x17, 0x84}, + {0x18, 0x98}, + {0x19, 0xa4}, + {0x1A, 0xb0}, + {0x1B, 0xc8}, + {0x1C, 0xdc}, + {0x1D, 0xf0}, + {0x1E, 0xf8}, + {0x1F, 0xFF}, + +//Gamma - G + {0x20, 0x00}, + {0x21, 0x04}, + {0x22, 0x10}, + {0x23, 0x20}, + {0x24, 0x40}, + {0x25, 0x5c}, + {0x26, 0x74}, + {0x27, 0x84}, + {0x28, 0x98}, + {0x29, 0xa4}, + {0x2A, 0xb0}, + {0x2B, 0xc8}, + {0x2C, 0xdc}, + {0x2D, 0xf0}, + {0x2E, 0xf8}, + {0x2F, 0xFF}, + +//Gamma - B + {0x30, 0x00}, + {0x31, 0x04}, + {0x32, 0x10}, + {0x33, 0x20}, + {0x34, 0x40}, + {0x35, 0x5c}, + {0x36, 0x74}, + {0x37, 0x84}, + {0x38, 0x98}, + {0x39, 0xa4}, + {0x3A, 0xb0}, + {0x3B, 0xc8}, + {0x3C, 0xdc}, + {0x3D, 0xf0}, + {0x3E, 0xf8}, + {0x3F, 0xFF}, + +//DARK GAMMA + {0x40, 0x00}, + {0x41, 0x0b}, + {0x42, 0x15}, + {0x43, 0x29}, + {0x44, 0x47}, + {0x45, 0x5D}, + {0x46, 0x72}, + {0x47, 0x83}, + {0x48, 0x92}, + {0x49, 0xA0}, + {0x4A, 0xac}, + {0x4B, 0xc6}, + {0x4C, 0xdA}, + {0x4D, 0xeC}, + {0x4E, 0xf6}, + {0x4F, 0xFF}, + + {0x50, 0x00}, //DARK GAMMA on/off + +//CSC + {0x60, 0x33}, + {0x61, 0x20}, + {0x62, 0xE4}, + {0x63, 0xFA}, + {0x64, 0x13}, + {0x65, 0x25}, + {0x66, 0x07}, + {0x67, 0xF5}, + {0x68, 0xEA}, + {0x69, 0x20}, + {0x6A, 0xC8}, + {0x6B, 0xC4}, + {0x6C, 0x84}, + {0x6D, 0x04}, + {0x6E, 0x0C}, + {0x6F, 0x00}, + +//Edge +// {0x70, 0x00}, +// {0x71, 0x18}, +// {0x72, 0x18}, +// {0x73, 0x04}, +// {0x74, 0x08}, +// {0x76, 0x20}, +// {0x77, 0x04}, +// {0x78, 0x08}, +// {0x7a, 0x20}, +// {0x7d, 0x08}, +// {0X7e, 0x30}, + + {0x80, 0x22}, + {0x81, 0x14}, + {0x82, 0x14}, + {0x83, 0x04}, + {0x84, 0x06}, + {0x85, 0x06}, + {0x87, 0x04}, + {0x88, 0x10}, + {0x89, 0x06}, + {0X90, 0x06}, + {0x91, 0x03}, + {0x93, 0xe0}, + +//Cr/Cb Coring + {0x94, 0x00}, + {0x95, 0x00}, + {0x96, 0x4C}, + {0x97, 0x76}, + {0x9A, 0xf5}, + + {0xA1, 0x08}, //@ 0 + {0xA2, 0x10}, //@ 20 + {0xA3, 0x16}, //@ 40 + {0xA4, 0x20}, //@ 60 + {0xA5, 0x30}, //@ 80 + {0xA6, 0xa0}, + {0xA7, 0x06}, + {0xA8, 0x40}, + + {0xA9, 0x38}, + {0xAa, 0x35}, + + {0xAc, 0xff}, + {0xAd, 0x09}, + {0xAe, 0x96}, + {0xAf, 0x18}, + + {0xB2, 0x38}, //color suppression start + {0xB3, 0x53}, + {0xB6, 0x00}, + +//Color Saturation + {0xBC, 0x10}, + {0xBD, 0x10}, + {0xBE, 0x10}, + {0xBF, 0x10}, + {0xc0, 0x10}, + {0xc1, 0x10}, + {0xc2, 0x10}, + {0xc3, 0x10}, + {0xc4, 0x10}, + {0xc5, 0x10}, + + {0xcc, 0x04}, + {0xcd, 0x40}, + {0xce, 0x00}, + +//IDP 3 + {0x00, 0x05}, + +//Memory + {0x40, 0x15}, + {0x41, 0x28}, + {0x42, 0x04}, + {0x43, 0x15}, + {0x44, 0x28}, + {0x45, 0x04}, + {0x46, 0x15}, + {0x47, 0x28}, + {0x48, 0x04}, + +//Knee + {0x90, 0xca}, // + {0x91, 0x81}, //knee function selection/knee point H + {0x92, 0x00}, //knee point L + {0x93, 0x50}, //Knee gain + {0x94, 0x41}, //[6:4]knee start H/[2:0]Knee END H + {0x95, 0x7e}, //knee start L + {0x96, 0x48}, //knee END L + +//ADG + {0x99, 0xC0}, + {0xA0, 0x10}, + {0xA1, 0x22}, + {0xA2, 0x36}, + {0xA3, 0x49}, + {0xA4, 0x5D}, + {0xA5, 0x70}, + {0xA6, 0x82}, + {0xA7, 0x94}, + {0xA8, 0xA5}, + {0xA9, 0xB5}, + {0xAA, 0xC3}, + {0xAB, 0xD1}, + {0xAC, 0xDE}, + {0xAD, 0xEA}, + {0xAE, 0xF5}, + {0xAF, 0xFF}, + +//YXGMA + {0xB0, 0xc0}, //YGMACTRL + {0xB1, 0x04}, //YGMASLOP + {0xB8, 0x0f}, //DRKTHR1 + {0xB9, 0x10}, //DRKTHR2 + //{0xBA, 0x38}, //DRKTHR3 + //{0xBB, 0x39}, //DRKTHR4 + {0xC0, 0x03}, + {0xC1, 0x0E}, + {0xC2, 0x16}, + {0xC3, 0x24}, + {0xC4, 0x3F}, + {0xC5, 0x56}, + {0xC6, 0x6A}, + {0xC7, 0x7C}, + {0xC8, 0x8C}, + {0xC9, 0x98}, + {0xCA, 0xA2}, + {0xCB, 0xB8}, + {0xCC, 0xCD}, + {0xCD, 0xE2}, + {0xCE, 0xF0}, + {0xCF, 0xFF}, + + +// edge value adjustment + {0xe0, 0x81}, + {0xe1, 0x83}, + {0xe2, 0x07}, + {0xe3, 0x0c}, + {0xe4, 0x14}, + {0xe5, 0x1c}, + + +//Sensor on + {0x00, 0x00}, + {0x03, 0xc5}, + {0x00, 0x01}, + {0x10, 0x84}, + {0x00, 0x02}, + {0x10, 0xd3}, + {0xff, 0xff}, + + +}; + +/* 1600X1200 UXGA */ +static struct reginfo sensor_uxga[] = +{ + {0x00,0x00}, + {0x04,0x10}, + {0x05,0x8f}, + {0x00,0x03}, + {0x94,0x06}, + {0x95,0x40}, + {0x96,0x04}, + {0x97,0xb0}, + {0xff, 0xff}, +}; + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {0x00,0x00}, + {0x04,0x10}, + {0x05,0x8b}, + {0x00,0x03}, + {0x94,0x05}, + {0x95,0x00}, + {0x96,0x04}, + {0x97,0x00}, + {0xff, 0xff}, +}; +static struct reginfo sensor_xga[] = +{ + {0xff, 0xff} +}; +/* 800X600 SVGA*/ +static struct reginfo sensor_svga[] = +{ + {0x00,0x03}, + {0x94,0x03}, + {0x95,0x20}, + {0x96,0x02}, + {0x97,0x58}, + {0xff, 0xff} +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ + {0x00,0x00}, + {0x04,0x00}, + {0x05,0x0f}, + {0x00,0x03}, + {0x94,0x02}, //0x02 + {0x95,0x80}, //0x80 + {0x96,0x01},//0x01 + {0x97,0xe0}, //0xe0 + {0xff, 0xff}, +}; + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{ + {0x00,0x03}, + {0x94,0x01}, + {0x95,0x60}, + {0x96,0x01}, + {0x97,0x20}, + {0xff, 0xff}, +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ + {0x00,0x03}, + {0x94,0x01}, + {0x95,0x40}, + {0x96,0x00}, + {0x97,0xf0}, + {0xff, 0xff}, +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {0x00,0x03}, + {0x94,0x00}, + {0x95,0xB0}, + {0x96,0x00}, + {0x97,0x90}, + {0xff, 0xff}, +}; + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + {0xff, 0xff} +}; + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]={ + {0x00, 0x02}, + {0x10, 0xd3}, + {0xff, 0xff} +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0x00, 0x02}, + {0x10, 0x00}, + {0x50, 0xd0}, + {0x51, 0x88}, + {0xff, 0xff} +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + {0x00, 0x02}, + {0x10, 0x00}, + {0x50, 0xaa}, + {0x51, 0x90}, + {0xff, 0xff} + +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + {0x00, 0x02}, + {0x10, 0x00}, + {0x50, 0xc2}, + {0x51, 0x9e}, + {0xff, 0xff} +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + {0x00, 0x02}, + {0x10, 0x00}, + {0x50, 0xaa}, + {0x51, 0xbe}, + {0xff, 0xff} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + {0x00, 0x04}, + {0xb6, 0xa0}, + {0xff, 0xff} + +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + {0x00, 0x04}, + {0xb6, 0x90}, + {0xff, 0xff} + +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + {0x00, 0x04}, + {0xb6, 0x00}, + {0xff, 0xff} + +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + {0x00, 0x04}, + {0xb6, 0x10}, + {0xff, 0xff} + +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + {0x00, 0x04}, + {0xb6, 0x20}, + {0xff, 0xff} + +}; + +static struct reginfo sensor_Brightness5[]= +{ + {0x00, 0x04}, + {0xb6, 0x30}, + {0xff, 0xff} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0x00, 0x04}, + {0xd9, 0x00}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0x00, 0x04}, + {0xd9, 0x40}, + {0x00, 0x00}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0x00, 0x04}, + {0xd9, 0x80}, + {0xda, 0x60}, + {0xdb, 0xa0}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + {0x00, 0x04}, + {0xd9, 0x20}, + {0xff, 0xff} +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + // Bluish + {0x00, 0x04}, + {0xd9, 0x80}, + {0xda, 0xc0}, + {0xdb, 0x60}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + // Greenish + {0x00, 0x04}, + {0xd9, 0x80}, + {0xda, 0x50}, + {0xdb, 0x50}, + {0xff, 0xff} +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + //-3 + {0xff, 0xff} +}; + +static struct reginfo sensor_Exposure1[]= +{ + //-2 + {0xff, 0xff} +}; + +static struct reginfo sensor_Exposure2[]= +{ + //-0.3EV + {0xff, 0xff} +}; + +static struct reginfo sensor_Exposure3[]= +{ + //default + {0xff, 0xff} +}; + +static struct reginfo sensor_Exposure4[]= +{ + // 1 + {0xff, 0xff} +}; + +static struct reginfo sensor_Exposure5[]= +{ + // 2 + {0xff, 0xff} +}; + +static struct reginfo sensor_Exposure6[]= +{ + // 3 + {0xff, 0xff} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Saturation1[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Saturation2[]= +{ + {0xff, 0xff} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Contrast1[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Contrast2[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Contrast3[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Contrast4[]= +{ + {0xff, 0xff} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Contrast6[]= +{ + {0xff, 0xff} +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + {0xff, 0xff} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_FlipOff[]= +{ + {0xff, 0xff} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ + {0x00, 0x01}, + {0x11, 0x0a}, + {0x00, 0x04}, + {0xb6, 0x00}, + {0xff, 0xff} +}; + +static struct reginfo sensor_SceneNight[] = +{ + {0x00, 0x01}, + {0x11, 0x14}, + {0x00, 0x04}, + {0xb6, 0x10}, + {0xff, 0xff} +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0xff, 0xff} +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0xff, 0xff} +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0xff, 0xff} +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +#define COL_FMT(_name, _depth, _fourcc, _colorspace) \ + { .name = _name, .depth = _depth, .fourcc = _fourcc, \ + .colorspace = _colorspace } + +#define JPG_FMT(_name, _depth, _fourcc) \ + COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) + +static const struct soc_camera_data_format sensor_colour_formats[] = { + JPG_FMT(SENSOR_NAME_STRING(UYVY), 16, V4L2_PIX_FMT_UYVY), + JPG_FMT(SENSOR_NAME_STRING(YUYV), 16, V4L2_PIX_FMT_YUYV), +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + unsigned int pixfmt; + +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + +/* sensor register write */ +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + //buf[0] = reg >> 8; + buf[0] = reg & 0xFF; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + u8 buf[1]; + struct i2c_msg msg[2]; + + // buf[0] = reg >> 8; + buf[0] = reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + while (regarray[i].reg != 0xff) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +#if CONFIG_SENSOR_I2C_RDWRCHK +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != 0xff) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } + return 0; +} +#endif +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + char value; + int ret,pid = 0; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + msleep(100); +#if 0 + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + ret = sensor_write(client, 0x3012, 0x80); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); //delay 5 microseconds + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x300a, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + pid |= (value << 8); + + ret = sensor_read(client, 0x300b, &value); + if (ret != 0) { + SENSOR_TR("read chip id low byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + pid |= (value & 0xff); + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_INIT_ERR; + } +#endif +#if 0 + sensor_read(client,0x01,&value); + pid = (value & 0xff); + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_INIT_ERR; + } +#endif + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + sensor_task_lock(client,0); + // icd->user_width = SENSOR_INIT_WIDTH; + //icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + sensor->info_priv.pixfmt = SENSOR_INIT_PIXFMT; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + sensor_set_flash(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + + return 0; +sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + //sensor_task_lock(client, 1); + //sensor_write(client, 0x30b0, 0x00); + //sensor_write(client, 0x30b1, 0x00); + //sensor_task_lock(client, 0); + sensor_ioctrl(icd, Sensor_PowerDown, 1); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); + return 0; +} + +static struct reginfo sensor_power_down_sequence[]= +{ + {0xff,0xff} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = icd->user_width; + pix->height = icd->user_height; + pix->pixelformat = sensor->info_priv.pixfmt; + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_JPEG; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) { + ret = true; + } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) { + ret = true; + } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) { + ret = true; + } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) { + ret = true; + } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + bool ret = false; + + if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 720)) { + ret = true; + } else if ((f->fmt.pix.width == 1920) && (f->fmt.pix.height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + if (sensor->info_priv.pixfmt != pix->pixelformat) { + switch (pix->pixelformat) + { + case V4L2_PIX_FMT_YUYV: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_PIX_FMT_UYVY: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.pixfmt = pix->pixelformat; + + SENSOR_DG("%s Pixelformat(0x%x) set success!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } else { + SENSOR_TR("%s Pixelformat(0x%x) is invalidate!\n", SENSOR_NAME_STRING(),pix->pixelformat); + } + } + + set_w = pix->width; + set_h = pix->height; + + if (((set_w <= 176) && (set_h <= 144)) &&( sensor_qcif[0].reg!=0xff)) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && (sensor_qvga[0].reg!=0xff)) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && (sensor_cif[0].reg!=0xff)) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) &&( sensor_vga[0].reg!=0xff)) + { + winseqe_set_addr = sensor_vga; + set_w =640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && (sensor_svga[0].reg!=0xff)) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1024) && (set_h <= 768)) &&( sensor_xga[0].reg!=0xff)) + { + winseqe_set_addr = sensor_xga; + set_w = 1024; + set_h = 768; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && (sensor_sxga[0].reg!=0xff)) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else if (((set_w <= 1600) && (set_h <= 1200)) && (sensor_uxga[0].reg!=0xff)) + { + winseqe_set_addr = sensor_uxga; + set_w = 1600; + set_h = 1200; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + ret = -1; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,pix->width,pix->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,f) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,f) == true) { /* ddl@rock-chips.com : Capture */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + #endif + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,f) == true) { /* ddl@rock-chips.com : Video */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + pix->width = set_w; + pix->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + bool bayer = pix->pixelformat == V4L2_PIX_FMT_UYVY || + pix->pixelformat == V4L2_PIX_FMT_YUYV; + + /* + * With Bayer format enforce even side lengths, but let the user play + * with the starting pixel + */ + if (pix->height > SENSOR_MAX_HEIGHT) + pix->height = SENSOR_MAX_HEIGHT; + else if (pix->height < SENSOR_MIN_HEIGHT) + pix->height = SENSOR_MIN_HEIGHT; + else if (bayer) + pix->height = ALIGN(pix->height, 2); + + if (pix->width > SENSOR_MAX_WIDTH) + pix->width = SENSOR_MAX_WIDTH; + else if (pix->width < SENSOR_MIN_WIDTH) + pix->width = SENSOR_MIN_WIDTH; + else if (bayer) + pix->width = ALIGN(pix->width, 2); + return 0; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV2655 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char value; + int ret,pid = 0; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } +#if 0 + /* soft reset */ + ret = sensor_write(client, 0x3012, 0x80); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(5); //delay 5 microseconds + + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x300a, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + + ret = sensor_read(client, 0x01, &value); + if (ret != 0) { + SENSOR_TR("read chip id low byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + pid = (value & 0xff); + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } +#endif + icd->formats = sensor_colour_formats; + icd->num_formats = ARRAY_SIZE(sensor_colour_formats); + + return 0; + +sensor_video_probe_err: + + return ret; +} +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_fmt = sensor_s_fmt, + .g_fmt = sensor_g_fmt, + .try_fmt = sensor_try_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + icd->y_skip_top = 0; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c index 70d75240c8aa..8a4477522ad5 100755 --- a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c @@ -45,7 +45,7 @@ #define _GC_OBJ_ZONE gcvZONE_OS -#define PAGE_ALLOC_LIMIT 1 // 限制Page申请 +#define PAGE_ALLOC_LIMIT 0 // 限制Page申请 #define PAGE_ALLOC_LIMIT_SIZE 0 // 限制Page申请的大小,单位为M #if PAGE_ALLOC_LIMIT diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 59700c73eb58..64e8b17da990 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -281,7 +281,15 @@ enum { V4L2_IDENT_GT2005 = 64100, /* ddl@rock-chips.com : GT2005 support */ V4L2_IDENT_GC0308 = 64101, /* ddl@rock-chips.com : GC0308 support */ - V4L2_IDENT_SIV120B = 64102, /* ddl@rock-chips.com : siv120b support */ + V4L2_IDENT_GC0309 = 64102, /* ddl@rock-chips.com : GC0309 support */ + V4L2_IDENT_SIV120B = 64103, /* ddl@rock-chips.com : siv120b support */ + + V4L2_IDENT_GC2015 = 64105, /* ddl@rock-chips.com : gc2015 support */ + V4L2_IDENT_HI253 = 64106, /* ddl@rock-chips.com : hi253 support */ + V4L2_IDENT_HI704 = 64107, /* ddl@rock-chips.com : hi704 support */ + V4L2_IDENT_NT99250 = 64108, /* ddl@rock-chips.com : nt99250 support */ + V4L2_IDENT_SID130B = 64109, /* ddl@rock-chips.com : sid130B support */ + }; #endif diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 7722e2e43713..c95ec5e755ad 100755 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -147,8 +147,8 @@ #define WM8900_LRC_MASK 0xfc00 #define SPK_CON RK29_PIN6_PB6 +#define WM8900_IS_SHUTDOWN 0 #define WM8900_IS_STARTUP 1 -#define WM8900_IS_SHUTDOWN 2 static void wm8900_work(struct work_struct *work); @@ -225,454 +225,36 @@ static void wm8900_reset(struct snd_soc_codec *codec) sizeof(codec->reg_cache)); } -static int wm8900_hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static void wm8900_powerdown(void) { - struct snd_soc_codec *codec = w->codec; - u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1); - - WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + printk("Power down wm8900\n"); - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Clamp headphone outputs */ - hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP | - WM8900_REG_HPCTL1_HP_CLAMP_OP; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - WM8900_DBG("Enter:%s, %d, HPCTL=0x%04X \n", __FUNCTION__, __LINE__, hpctl1); - break; - - case SND_SOC_DAPM_POST_PMU: - /* Enable the input stage */ - hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP; - hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT | - WM8900_REG_HPCTL1_HP_SHORT2 | - WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - - msleep(400); - - /* Enable the output stage */ - hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP; - hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - - /* Remove the shorts */ - hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - WM8900_DBG("Enter:%s, %d, HPCTL=0x%04X \n", __FUNCTION__, __LINE__, hpctl1); - break; - - case SND_SOC_DAPM_PRE_PMD: - /* Short the output */ - hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - - /* Disable the output stage */ - hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - - /* Clamp the outputs and power down input */ - hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP | - WM8900_REG_HPCTL1_HP_CLAMP_OP; - hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - WM8900_DBG("Enter:%s, %d, HPCTL=0x%04X \n", __FUNCTION__, __LINE__, hpctl1); - break; - - case SND_SOC_DAPM_POST_PMD: - /* Disable everything */ - snd_soc_write(codec, WM8900_REG_HPCTL1, 0); - WM8900_DBG("Enter:%s, %d, HPCTL=0x%04X \n", __FUNCTION__, __LINE__, hpctl1); - break; - - default: - BUG(); + if (wm8900_current_status != WM8900_IS_SHUTDOWN) { +#ifdef SPK_CON + gpio_set_value(SPK_CON, GPIO_LOW); +#endif + msleep(20); + snd_soc_write(wm8900_codec, WM8900_REG_RESET, 0); + wm8900_current_status = WM8900_IS_SHUTDOWN; } - - return 0; -} - -static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0); - -static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0); - -static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0); - -static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0); - -static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); - -static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1); - -static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0); - -static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); - -static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; - -static const struct soc_enum mic_bias_level = -SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); - -static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; - -static const struct soc_enum dac_mute_rate = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); - -static const char *dac_deemphasis_txt[] = { - "Disabled", "32kHz", "44.1kHz", "48kHz" -}; - -static const struct soc_enum dac_deemphasis = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); - -static const char *adc_hpf_cut_txt[] = { - "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" -}; - -static const struct soc_enum adc_hpf_cut = -SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); - -static const char *lr_txt[] = { - "Left", "Right" -}; - -static const struct soc_enum aifl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); - -static const struct soc_enum aifr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); - -static const struct soc_enum dacl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); - -static const struct soc_enum dacr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); - -static const char *sidetone_txt[] = { - "Disabled", "Left ADC", "Right ADC" -}; - -static const struct soc_enum dacl_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); - -static const struct soc_enum dacr_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); - -static const struct snd_kcontrol_new wm8900_snd_controls[] = { -SOC_ENUM("Mic Bias Level", mic_bias_level), - -SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0, - in_pga_tlv), -SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1), -SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0), - -SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0, - in_pga_tlv), -SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1), -SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0), - -SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1), -SOC_ENUM("DAC Mute Rate", dac_mute_rate), -SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0), -SOC_ENUM("DAC Deemphasis", dac_deemphasis), -SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL, - 12, 1, 0), - -SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0), -SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut), -SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0), -SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0, - adc_svol_tlv), -SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0, - adc_svol_tlv), -SOC_ENUM("Left Digital Audio Source", aifl_src), -SOC_ENUM("Right Digital Audio Source", aifr_src), - -SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0, - dac_boost_tlv), -SOC_ENUM("Left DAC Source", dacl_src), -SOC_ENUM("Right DAC Source", dacr_src), -SOC_ENUM("Left DAC Sidetone", dacl_sidetone), -SOC_ENUM("Right DAC Sidetone", dacr_sidetone), -SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0), - -SOC_DOUBLE_R_TLV("Digital Playback Volume", - WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV, - 1, 96, 0, dac_tlv), -SOC_DOUBLE_R_TLV("Digital Capture Volume", - WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv), - -SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0, - out_mix_tlv), - -SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0, - out_mix_tlv), - -SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0, - in_boost_tlv), - -SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, - 0, 63, 0, out_pga_tlv), -SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, - 6, 1, 1), -SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, - 7, 1, 0), - -SOC_DOUBLE_R_TLV("LINEOUT2 Volume", - WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, - 0, 63, 0, out_pga_tlv), -SOC_DOUBLE_R("LINEOUT2 Switch", - WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1), -SOC_DOUBLE_R("LINEOUT2 ZC Switch", - WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0), -SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1, - 0, 1, 1), - -}; - -static const struct snd_kcontrol_new wm8900_dapm_loutput2_control[] = { -SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0),}; - -static const struct snd_kcontrol_new wm8900_dapm_routput2_control[] = { -SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0),}; - -static const struct snd_kcontrol_new wm8900_loutmix_controls[] = { -SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0), -SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0), -SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0), -SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0), -SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0), -}; - -static const struct snd_kcontrol_new wm8900_routmix_controls[] = { -SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0), -SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0), -SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0), -SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0), -SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0), -}; - -static const struct snd_kcontrol_new wm8900_linmix_controls[] = { -SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1), -SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1), -SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1), -SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0), -}; - -static const struct snd_kcontrol_new wm8900_rinmix_controls[] = { -SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1), -SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1), -SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1), -SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0), -}; - -static const struct snd_kcontrol_new wm8900_linpga_controls[] = { -SOC_SINGLE("MIC LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0), -SOC_SINGLE("MIC LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0), -SOC_SINGLE("MIC LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0), -}; - -static const struct snd_kcontrol_new wm8900_rinpga_controls[] = { -SOC_SINGLE("MIC RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0), -SOC_SINGLE("MIC RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0), -SOC_SINGLE("MIC RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0), -}; - -static const struct snd_kcontrol_new wm8900_inmix_controls[] = { -SOC_SINGLE("LINPUT PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0), -SOC_SINGLE("RINPUT PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0), -}; - -static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" }; - -static const struct soc_enum wm8900_lineout2_lp_mux = -SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux); - -static const struct snd_kcontrol_new wm8900_lineout2_lp = -SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); - -static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = { - -/* Externally visible pins */ -SND_SOC_DAPM_OUTPUT("LINEOUT1L"), -SND_SOC_DAPM_OUTPUT("LINEOUT1R"), -SND_SOC_DAPM_OUTPUT("LINEOUT2L"), -SND_SOC_DAPM_OUTPUT("LINEOUT2R"), -SND_SOC_DAPM_OUTPUT("HP_L"), -SND_SOC_DAPM_OUTPUT("HP_R"), - -SND_SOC_DAPM_INPUT("RINPUT1"), -SND_SOC_DAPM_INPUT("LINPUT1"), -SND_SOC_DAPM_INPUT("RINPUT2"), -SND_SOC_DAPM_INPUT("LINPUT2"), -SND_SOC_DAPM_INPUT("RINPUT3"), -SND_SOC_DAPM_INPUT("LINPUT3"), -SND_SOC_DAPM_INPUT("AUX"), - -SND_SOC_DAPM_VMID("VMID"), - -/* Input */ -SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0, - wm8900_linpga_controls, - ARRAY_SIZE(wm8900_linpga_controls)), -SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0, - wm8900_rinpga_controls, - ARRAY_SIZE(wm8900_rinpga_controls)), - -SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0, - wm8900_linmix_controls, - ARRAY_SIZE(wm8900_linmix_controls)), -SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0, - wm8900_rinmix_controls, - ARRAY_SIZE(wm8900_rinmix_controls)), - -SND_SOC_DAPM_MICBIAS("Mic Bias", WM8900_REG_POWER1, 4, 0), - -SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0), -SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0), - -/* Output */ -SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0), -SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0), - -/*SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0, - wm8900_hp_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),*/ - -SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0), - -SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp), -SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0), - -SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0, - wm8900_loutmix_controls, - ARRAY_SIZE(wm8900_loutmix_controls)), -SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0, - wm8900_routmix_controls, - ARRAY_SIZE(wm8900_routmix_controls)), -}; - -/* Target, Path, Source */ -static const struct snd_soc_dapm_route audio_map[] = { -/* Inputs */ -{"Left Input PGA", "LINPUT1 Switch", "LINPUT1"}, -{"Left Input PGA", "LINPUT2 Switch", "LINPUT2"}, -{"Left Input PGA", "LINPUT3 Switch", "LINPUT3"}, - -{"Right Input PGA", "RINPUT1 Switch", "RINPUT1"}, -{"Right Input PGA", "RINPUT2 Switch", "RINPUT2"}, -{"Right Input PGA", "RINPUT3 Switch", "RINPUT3"}, - -{"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"}, -{"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"}, -{"Left Input Mixer", "AUX Switch", "AUX"}, -{"Left Input Mixer", "Input PGA Switch", "Left Input PGA"}, - -{"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"}, -{"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"}, -{"Right Input Mixer", "AUX Switch", "AUX"}, -{"Right Input Mixer", "Input PGA Switch", "Right Input PGA"}, - -{"ADCL", NULL, "Left Input Mixer"}, -{"ADCR", NULL, "Right Input Mixer"}, - -/* Outputs */ -{"LINEOUT1L", NULL, "LINEOUT1L PGA"}, -{"LINEOUT1L PGA", NULL, "Left Output Mixer"}, -{"LINEOUT1R", NULL, "LINEOUT1R PGA"}, -{"LINEOUT1R PGA", NULL, "Right Output Mixer"}, - -{"LINEOUT2L PGA", NULL, "Left Output Mixer"}, -{"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"}, -{"LINEOUT2 LP", "Enabled", "Left Output Mixer"}, -{"LINEOUT2L", NULL, "LINEOUT2 LP"}, - -{"LINEOUT2R PGA", NULL, "Right Output Mixer"}, -{"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"}, -{"LINEOUT2 LP", "Enabled", "Right Output Mixer"}, -{"LINEOUT2R", NULL, "LINEOUT2 LP"}, - -{"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"}, -{"Left Output Mixer", "AUX Bypass Switch", "AUX"}, -{"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, -{"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, -{"Left Output Mixer", "DACL Switch", "DACL"}, - -{"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"}, -{"Right Output Mixer", "AUX Bypass Switch", "AUX"}, -{"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, -{"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, -{"Right Output Mixer", "DACR Switch", "DACR"}, - -/* Note that the headphone output stage needs to be connected - * externally to LINEOUT2 via DC blocking capacitors. Other - * configurations are not supported. - * - * Note also that left and right headphone paths are treated as a - * mono path. - */ -{"Headphone Amplifier", NULL, "LINEOUT2 LP"}, -{"Headphone Amplifier", NULL, "LINEOUT2 LP"}, -{"HP_L", NULL, "Headphone Amplifier"}, -{"HP_R", NULL, "Headphone Amplifier"}, -}; - -static int wm8900_add_widgets(struct snd_soc_codec *codec) -{ - WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); - - snd_soc_dapm_new_controls(codec, wm8900_dapm_widgets, - ARRAY_SIZE(wm8900_dapm_widgets)); - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); - - return 0; } static void wm8900_work(struct work_struct *work) { - WM8900_DBG("Enter::wm8900 work, power down wm8900\n"); + WM8900_DBG("Enter::wm8900_work\n"); -#ifdef SPK_CON - gpio_set_value(SPK_CON, GPIO_LOW); -#endif - snd_soc_write(wm8900_codec, WM8900_REG_RESET, 0); - - wm8900_current_status = WM8900_IS_SHUTDOWN; + wm8900_powerdown(); } static void wm8900_set_hw(struct snd_soc_codec *codec) { + u16 reg; + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + //snd_soc_write(codec, WM8900_REG_LOUT2CTL, 0x140); + //snd_soc_write(codec, WM8900_REG_ROUT2CTL, 0x140); + snd_soc_write(codec, WM8900_REG_HPCTL1, 0x30); snd_soc_write(codec, WM8900_REG_POWER1, 0x0100); snd_soc_write(codec, WM8900_REG_POWER3, 0x60); @@ -682,7 +264,7 @@ static void wm8900_set_hw(struct snd_soc_codec *codec) snd_soc_write(codec, WM8900_REG_ADDCTL, 0x02); snd_soc_write(codec, WM8900_REG_POWER1, 0x09); snd_soc_write(codec, WM8900_REG_POWER3, 0xEF); - snd_soc_write(codec, WM8900_REG_DACCTRL, 0x00); + snd_soc_write(codec, WM8900_REG_DACCTRL, WM8900_REG_DACCTRL_MUTE); snd_soc_write(codec, WM8900_REG_LOUTMIXCTL1, 0x150); snd_soc_write(codec, WM8900_REG_ROUTMIXCTL1, 0x150); @@ -705,6 +287,26 @@ static void wm8900_set_hw(struct snd_soc_codec *codec) snd_soc_write(codec, WM8900_REG_INBOOSTMIX2, 0x0042); snd_soc_write(codec, WM8900_REG_ADCPATH, 0x0055); + reg = snd_soc_read(codec, WM8900_REG_DACCTRL); + + reg &= ~WM8900_REG_DACCTRL_MUTE; + snd_soc_write(codec, WM8900_REG_DACCTRL, reg); + + snd_soc_write(codec, WM8900_REG_LOUT1CTL, 0x130); + snd_soc_write(codec, WM8900_REG_ROUT1CTL, 0x130); + + /* Turn up vol slowly, for HP out pop noise */ + + for (reg = 0; reg <= 0x33; reg += 0x10) { + snd_soc_write(codec, WM8900_REG_LOUT2CTL, 0x100 + reg); + snd_soc_write(codec, WM8900_REG_ROUT2CTL, 0x100 + reg); + msleep(5); + } + snd_soc_write(codec, WM8900_REG_LOUT2CTL, 0x133); + snd_soc_write(codec, WM8900_REG_ROUT2CTL, 0x133); + + msleep(20); + #ifdef SPK_CON gpio_set_value(SPK_CON, GPIO_HIGH); #endif @@ -1074,41 +676,8 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) { - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; - WM8900_DBG("Enter:%s, %d , mute = %d \n", __FUNCTION__, __LINE__, mute); - if (mute) - return 0; - - reg = snd_soc_read(codec, WM8900_REG_DACCTRL); - - reg &= ~WM8900_REG_DACCTRL_MUTE; - snd_soc_write(codec, WM8900_REG_DACCTRL, reg); - - /* Turn up vol slowly, for SPK out pop */ - for (reg = 0; reg <= 0x30; reg += 0x10) { - if (snd_soc_read(codec, WM8900_REG_LOUT1CTL) < 0x30) - snd_soc_write(codec, WM8900_REG_LOUT1CTL, 0x100 + reg); - - if (snd_soc_read(codec, WM8900_REG_ROUT1CTL) < 0x30) - snd_soc_write(codec, WM8900_REG_ROUT1CTL, 0x100 + reg); - } - snd_soc_write(codec, WM8900_REG_LOUT1CTL, 0x130); - snd_soc_write(codec, WM8900_REG_ROUT1CTL, 0x130); - - /* Turn up vol slowly, for HP out pop */ - for (reg = 0; reg <= 0x33; reg += 0x10) { - if (snd_soc_read(codec, WM8900_REG_LOUT2CTL) < 0x33) - snd_soc_write(codec, WM8900_REG_LOUT2CTL, 0x100 + reg); - - if (snd_soc_read(codec, WM8900_REG_ROUT2CTL) < 0x33) - snd_soc_write(codec, WM8900_REG_ROUT2CTL, 0x100 + reg); - } - snd_soc_write(codec, WM8900_REG_LOUT2CTL, 0x133); - snd_soc_write(codec, WM8900_REG_ROUT2CTL, 0x133); - return 0; } @@ -1117,21 +686,16 @@ static int wm8900_startup(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->card->codec; WM8900_DBG("Enter::%s----%d substream->stream:%s \n",__FUNCTION__,__LINE__, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE"); - if (!(codec_dai->playback.active || codec_dai->capture.active)) { + cancel_delayed_work_sync(&delayed_work); - cancel_delayed_work_sync(&delayed_work); + if (wm8900_current_status == WM8900_IS_SHUTDOWN) { - if (wm8900_current_status & WM8900_IS_STARTUP) - return 0; - - WM8900_DBG("Power up wm8900\n"); + printk("Power up wm8900\n"); wm8900_set_hw(codec); wm8900_current_status |= WM8900_IS_STARTUP; @@ -1140,7 +704,7 @@ static int wm8900_startup(struct snd_pcm_substream *substream, } static void wm8900_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *machine = rtd->dai; @@ -1159,8 +723,14 @@ static void wm8900_shutdown(struct snd_pcm_substream *substream, WM8900_DBG("Is going to power down wm8900\n"); - queue_delayed_work(wm8900_workq, &delayed_work, - msecs_to_jiffies(3000)); + /* If codec is useless, queue work to close it */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + queue_delayed_work(wm8900_workq, &delayed_work, + msecs_to_jiffies(1000)); + } else { + queue_delayed_work(wm8900_workq, &delayed_work, + msecs_to_jiffies(3000)); + } } } @@ -1320,7 +890,6 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, break; } - codec->bias_level = level; return 0; } @@ -1337,7 +906,9 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state) WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); - snd_soc_write(codec, WM8900_REG_RESET, 0); + cancel_delayed_work_sync(&delayed_work); + + wm8900_powerdown(); /* Stop the FLL in an orderly fashion */ ret = wm8900_set_fll(codec, 0, 0, 0); @@ -1481,7 +1052,7 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client) void wm8900_i2c_shutdown(struct i2c_client *client) { WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); - snd_soc_write(wm8900_codec, WM8900_REG_RESET, 0); + wm8900_powerdown(); } #ifdef CONFIG_PM @@ -1531,6 +1102,7 @@ static int wm8900_probe(struct platform_device *pdev) dev_err(&pdev->dev, "I2C client not yet instantiated\n"); return -ENODEV; } + #if defined(SPK_CON) gpio_request(SPK_CON,NULL); gpio_direction_output(SPK_CON, GPIO_LOW); @@ -1546,17 +1118,6 @@ static int wm8900_probe(struct platform_device *pdev) goto pcm_err; } - snd_soc_add_controls(codec, wm8900_snd_controls, - ARRAY_SIZE(wm8900_snd_controls)); - snd_soc_add_controls(codec, wm8900_linpga_controls, - ARRAY_SIZE(wm8900_linpga_controls)); - snd_soc_add_controls(codec, wm8900_rinpga_controls, - ARRAY_SIZE(wm8900_rinpga_controls)); - snd_soc_add_controls(codec, wm8900_inmix_controls, - ARRAY_SIZE(wm8900_inmix_controls)); - - wm8900_add_widgets(codec); - ret = snd_soc_init_card(socdev); if (ret < 0) { dev_err(&pdev->dev, "Failed to register card\n");