--- /dev/null
+#include <linux/videodev2.h>\r
+#include <linux/slab.h>\r
+#include <linux/i2c.h>\r
+#include <linux/log2.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/delay.h>\r
+#include <linux/circ_buf.h>\r
+#include <linux/miscdevice.h>\r
+#include <media/v4l2-common.h>\r
+#include <media/v4l2-chip-ident.h>\r
+#include <media/soc_camera.h>\r
+#include <plat/rk_camera.h>\r
+#include <linux/fs.h>\r
+#include <asm/uaccess.h>\r
+#include <linux/mm.h>\r
+#include <linux/firmware.h>\r
+\r
+static int debug = 3;\r
+module_param(debug, int, S_IRUGO|S_IWUSR);\r
+\r
+#define dprintk(level, fmt, arg...) do { \\r
+ if (debug >= level) \\r
+ printk(KERN_WARNING fmt , ## arg); } while (0)\r
+\r
+#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__)\r
+#define SENSOR_DG(format, ...) dprintk(1, format, ## __VA_ARGS__)\r
+\r
+#define _CONS(a,b) a##b\r
+#define CONS(a,b) _CONS(a,b)\r
+\r
+#define __STR(x) #x\r
+#define _STR(x) __STR(x)\r
+#define STR(x) _STR(x)\r
+\r
+#define MIN(x,y) ((x<y) ? x: y)\r
+#define MAX(x,y) ((x>y) ? x: y)\r
+\r
+/* Sensor Driver Configuration */\r
+#define SENSOR_NAME RK29_CAM_ISP_MTK9335\r
+#define SENSOR_V4L2_IDENT V4L2_IDENT_MTK9335ISP\r
+#define SENSOR_ID 0x35\r
+#define SENSOR_MIN_WIDTH 640//176\r
+#define SENSOR_MIN_HEIGHT 480//144\r
+#define SENSOR_MAX_WIDTH 2592\r
+#define SENSOR_MAX_HEIGHT 1944\r
+#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */\r
+#define SENSOR_INIT_HEIGHT 480\r
+#define SENSOR_INIT_WINSEQADR sensor_vga\r
+#define SENSOR_INIT_PIXFMT V4L2_MBUS_FMT_YUYV8_2X8\r
+\r
+#define CONFIG_SENSOR_WhiteBalance 1\r
+#define CONFIG_SENSOR_Brightness 0\r
+#define CONFIG_SENSOR_Contrast 0\r
+#define CONFIG_SENSOR_Saturation 0\r
+#define CONFIG_SENSOR_Effect 1\r
+#define CONFIG_SENSOR_Scene 1\r
+#define CONFIG_SENSOR_DigitalZoom 0\r
+#define CONFIG_SENSOR_Focus 1\r
+#define CONFIG_SENSOR_Exposure 1\r
+#define CONFIG_SENSOR_Flash 0\r
+#define CONFIG_SENSOR_Mirror 0\r
+#define CONFIG_SENSOR_Flip 0\r
+#define CONFIG_SENSOR_FOCUS_ZONE 1\r
+#define CONFIG_SENSOR_FACE_DETECT 1\r
+\r
+#if CONFIG_SENSOR_Focus\r
+#define SENSOR_AF_MODE_CLOSE 0 \r
+#define SENSOR_AF_SINGLE 1\r
+#define SENSOR_AF_MACRO 2\r
+#define SENSOR_AF_CONTINUOUS 5\r
+#define SENSOR_AF_CONTINUOUS_OFF 6\r
+static int sensor_set_auto_focus(struct i2c_client *client, int value);\r
+#endif\r
+\r
+#define CONFIG_SENSOR_I2C_SPEED 400000 /* Hz */\r
+/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */\r
+#define CONFIG_SENSOR_I2C_NOSCHED 0\r
+#define CONFIG_SENSOR_I2C_RDWRCHK 0\r
+\r
+#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING|\\r
+ SOCAM_HSYNC_ACTIVE_HIGH| SOCAM_VSYNC_ACTIVE_HIGH|\\r
+ SOCAM_DATA_ACTIVE_HIGH|SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ)\r
+\r
+#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a))\r
+#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a)\r
+// Using define data \r
+\r
+#define I2C_IDLE 1 \r
+#define I2C_STATUS_REG2 0x0D \r
+#define DEV_ID_MV9335_I2CSLAVE_FLASH_PRO (0x40 >> 1) \r
+#define get_lsb(x) (char)((u16)(x)& 0xFF)\r
+#define get_msb(x) (char)(((u16)(x)>>8)& 0xFF)\r
+#define FLASH_ERASE_BY_SECTOR 0\r
+#define FLASH_ERASE_ALL 1\r
+#define WRITE_READ_CHECK 0\r
+#define FLASH_WRITE_CHECK 0\r
+\r
+#define PRODUCT_ID_VALUE_REG0 0x93\r
+#define PRODUCT_VERSION_VALUE_REG1 0x35\r
+#define I2C_CHECKE_VALUE_REG5 0x50\r
+#define CHECKE_VALUE_REG6 0x80\r
+\r
+#define FWVERSION (0x09)\r
+#if (FWVERSION == 0x03)\r
+const char fw_name[] = {"mv9335_DS1001B_RK3066_OV5653_v1_0x03.bin"};\r
+#define FIRMWARE_MAJOR_VERSION_VALUE_REG2 0x01\r
+#define FIRMWARE_MINOR_VERSION_VALUE_REG3 0x03\r
+#define CHECKE_VALUE_REG0X90 0x3c\r
+#define CHECKE_VALUE_REG0X91 0x88\r
+#elif(FWVERSION == 0x04)\r
+const char fw_name[] = {"mv9335_DS1001B_RK3066_OV5653_v1_0x04.bin"};\r
+#define FIRMWARE_MAJOR_VERSION_VALUE_REG2 0x01\r
+#define FIRMWARE_MINOR_VERSION_VALUE_REG3 0x04\r
+#define CHECKE_VALUE_REG0X90 0xa4\r
+#define CHECKE_VALUE_REG0X91 0x5e\r
+#elif(FWVERSION == 0x05) //no focus\r
+const char fw_name[] = {"mv9335_DS1001B_RK3066_OV5653_v1_0x05.bin"};\r
+#define FIRMWARE_MAJOR_VERSION_VALUE_REG2 0x01\r
+#define FIRMWARE_MINOR_VERSION_VALUE_REG3 0x05\r
+#define CHECKE_VALUE_REG0X90 0x51\r
+#define CHECKE_VALUE_REG0X91 0x54\r
+#elif(FWVERSION == 0x06) \r
+const char fw_name[] = {"mv9335_DS1001B_RK3066_OV5653_v1_0x06.bin"};\r
+#define FIRMWARE_MAJOR_VERSION_VALUE_REG2 0x01\r
+#define FIRMWARE_MINOR_VERSION_VALUE_REG3 0x06\r
+#define CHECKE_VALUE_REG0X90 0x90\r
+#define CHECKE_VALUE_REG0X91 0xe7\r
+#elif(FWVERSION == 0x07) \r
+const char fw_name[] = {"mv9335_DS1001B_RK3066_OV5653_v1_0x07.bin"};\r
+#define FIRMWARE_MAJOR_VERSION_VALUE_REG2 0x01\r
+#define FIRMWARE_MINOR_VERSION_VALUE_REG3 0x07\r
+#define CHECKE_VALUE_REG0X90 0x22\r
+#define CHECKE_VALUE_REG0X91 0x8a\r
+#elif(FWVERSION == 0x08) \r
+const char fw_name[] = {"mv9335_DS1001B_RK3066_OV5653_v1_0x08.bin"};\r
+#define FIRMWARE_MAJOR_VERSION_VALUE_REG2 0x01\r
+#define FIRMWARE_MINOR_VERSION_VALUE_REG3 0x08\r
+#define CHECKE_VALUE_REG0X90 0x7a\r
+#define CHECKE_VALUE_REG0X91 0x32\r
+#elif(FWVERSION == 0x09) \r
+const char fw_name[] = {"mv9335_DS1001B_RK3066_OV5653_v1_0x09.bin"};\r
+#define FIRMWARE_MAJOR_VERSION_VALUE_REG2 0x01\r
+#define FIRMWARE_MINOR_VERSION_VALUE_REG3 0x09\r
+#define CHECKE_VALUE_REG0X90 0x48\r
+#define CHECKE_VALUE_REG0X91 0x3e\r
+\r
+#else\r
+const char fw_name[] = {"mv9335_DS1001B_RK3066_OV5653_v1_0x09.bin"};\r
+#define FIRMWARE_MAJOR_VERSION_VALUE_REG2 0x01\r
+#define FIRMWARE_MINOR_VERSION_VALUE_REG3 0x09\r
+#define CHECKE_VALUE_REG0X90 0x48\r
+#define CHECKE_VALUE_REG0X91 0x3e\r
+#endif\r
+struct reginfo\r
+{\r
+ u8 reg;\r
+ u8 val;\r
+};\r
+ \r
+/* only one fixed colorspace per pixelcode */\r
+struct sensor_datafmt {\r
+ enum v4l2_mbus_pixelcode code;\r
+ enum v4l2_colorspace colorspace;\r
+}; \r
+\r
+enum ISP_OUTPUT_RES{\r
+ OUTPUT_QCIF =0x0001, // 176*144\r
+ OUTPUT_HQVGA=0x0002,// 240*160\r
+ OUTPUT_QVGA =0x0004, // 320*240\r
+ OUTPUT_CIF =0x0008, // 352*288\r
+ OUTPUT_VGA =0x0010, // 640*480\r
+ OUTPUT_SVGA =0x0020, // 800*600\r
+ OUTPUT_720P =0x0040, // 1280*720\r
+ OUTPUT_XGA =0x0080, // 1024*768\r
+ OUTPUT_SXGA =0x0100, // 1280*1024\r
+ OUTPUT_UXGA =0x0200, // 1600*1200\r
+ OUTPUT_1080P=0x0400, //1920*1080\r
+ OUTPUT_QXGA =0x0800, // 2048*1536\r
+ OUTPUT_QSXGA=0x1000, // 2592*1944\r
+};\r
+static u8 sendI2cCmd(struct i2c_client *client,u8 cmd, u8 dat); \r
+static int isp_i2c_read(struct i2c_client *client, u8 reg, u8 *val,u16 ext_addr);\r
+static int flash_read_firmware_data(struct i2c_client *client,u16 addr,u8* rd_data,int readcount);\r
+static int flash_read_data(struct i2c_client *client,u8* rd_data,int readcount);\r
+static int isp_init_check(struct i2c_client *client);\r
+static int isp_init_cmds(struct i2c_client *client);\r
+static struct soc_camera_ops sensor_ops;\r
+\r
+#if CONFIG_SENSOR_DigitalZoom\r
+static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value);\r
+#endif \r
+\r
+\r
+struct focus_zone_s{\r
+u8 lx;\r
+u8 ty;\r
+u8 rx;\r
+u8 dy;\r
+};\r
+\r
+//flash and focus must be considered.\r
+\r
+//soft isp or external isp used\r
+//if soft isp is defined , the value in this sturct is used in cif driver . cif driver use this value to do isp func.\r
+//value of this sturct MUST be defined(initialized) correctly. \r
+struct isp_data{\r
+\r
+ //focus\r
+ //flash\r
+ int focus;\r
+ int auto_focus;\r
+ int flash;\r
+ //awb\r
+ //ae\r
+ //scence\r
+ //effect\r
+ //brightness\r
+ //digitalzoom\r
+ int whiteBalance;\r
+ int brightness;\r
+ int contrast;\r
+ int saturation;\r
+ int effect;\r
+ int scene;\r
+ int digitalzoom;\r
+ int exposure;\r
+ int face;\r
+ //mirror or flip\r
+ unsigned char mirror; /* HFLIP */\r
+ unsigned char flip; /* VFLIP */\r
+ //preview or capture\r
+ int outputSize; // supported resolution\r
+ int curRes;\r
+ struct focus_zone_s focus_zone;\r
+ struct sensor_datafmt fmt;\r
+ //mutex for access the isp data\r
+ struct mutex access_data_lock;\r
+};\r
+\r
+\r
+struct isp_func_ops{\r
+ int (*isp_power_on)(void);\r
+ int (*isp_power_off)(void);\r
+ //realized by isp or external dev\r
+ int (*isp_set_focus_mode)(int value,struct isp_data* data);\r
+ int (*isp_set_flash_mode)( int value,struct isp_data* data);\r
+\r
+ //by soft isp or external isp\r
+ int (*isp_set_wb_mode)( int value,struct isp_data* data);\r
+ int (*isp_set_effect_mode)( int value,struct isp_data* data);\r
+ int (*isp_set_scence_mode)( int value,struct isp_data* data);\r
+ int (*isp_set_expose_mode)( int value,struct isp_data* data);\r
+ int (*isp_set_digitalzoom_mode)( int value,struct isp_data* data);\r
+ int (*isp_set_flip)( int value,struct isp_data* data);\r
+ int (*isp_set_mirror)( int value,struct isp_data* data);\r
+};\r
+\r
+struct isp_dev{\r
+ struct v4l2_subdev subdev;\r
+ struct i2c_client *client;\r
+ struct workqueue_struct *sensor_wq;\r
+ struct mutex wq_lock;\r
+ int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */\r
+ struct isp_func_ops* isp_ops;\r
+ struct isp_data isp_priv_info; \r
+ };\r
+\r
+static struct isp_dev* to_sensor(const struct i2c_client *client)\r
+{\r
+ return container_of(i2c_get_clientdata(client), struct isp_dev, subdev);\r
+}\r
+\r
+/* Find a data format by a pixel code in an array */\r
+static const struct sensor_datafmt *sensor_find_datafmt(\r
+ enum v4l2_mbus_pixelcode code, const struct sensor_datafmt *fmt,\r
+ int n)\r
+{\r
+ int i;\r
+ for (i = 0; i < n; i++)\r
+ if (fmt[i].code == code)\r
+ return fmt + i;\r
+\r
+ return NULL;\r
+}\r
+\r
+static const struct sensor_datafmt sensor_colour_fmts[] = {\r
+ {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG} \r
+};\r
+\r
+static int isp_reg_value_check(struct i2c_client *client,u8 checked_reg,u8 checked_value){\r
+ int cnt = 100;\r
+ u8 check_val = 0;\r
+ // msleep(10);\r
+ while((cnt-- > 0) && (isp_i2c_read(client,checked_reg,&check_val,0) || (check_val != checked_value))){\r
+ // SENSOR_TR("error: %s:%d check_val = 0x%x, exp = 0x%x\n", __func__,__LINE__, check_val,checked_value);\r
+ mdelay(30);\r
+ }\r
+ if(cnt <= 0){\r
+ SENSOR_TR("error: %s:%d reg value checked erro,check_val = 0x%x, exp = 0x%x!\n", __func__,__LINE__,check_val,checked_value);\r
+ return -1;\r
+ }\r
+ return 0;\r
+\r
+}\r
+\r
+#if CONFIG_SENSOR_WhiteBalance\r
+static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value)\r
+{\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ u8 set_val = 0;\r
+\r
+ if ((value >= qctrl->minimum) && (value <= qctrl->maximum))\r
+ {\r
+ switch(value){\r
+ case 0: //enable auto\r
+ set_val = 0x1;\r
+ break;\r
+ case 1: //incandescent\r
+ set_val = 0x45;\r
+ break;\r
+ case 2: //fluorescent\r
+ set_val = 0x25;\r
+ break;\r
+ case 3: //daylight\r
+ set_val = 0x15;\r
+ break;\r
+ case 4: //cloudy-daylight\r
+ set_val = 0x35;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ //awb\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x1c, set_val);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ return 0;\r
+ }\r
+ SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value);\r
+ return -1;\r
+}\r
+#endif\r
+#if CONFIG_SENSOR_Effect\r
+static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value)\r
+{\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ u8 set_val = 0;\r
+ printk("set effect,value = %d ......\n",value);\r
+ if ((value >= qctrl->minimum) && (value <= qctrl->maximum))\r
+ {\r
+ switch(value){\r
+ case 0: //none\r
+ set_val = 0x00;\r
+ break;\r
+ case 1: //mono\r
+ set_val = 0x01;\r
+ break;\r
+ case 2: //negative\r
+ set_val = 0x02;\r
+ break;\r
+ case 3: //sepia\r
+ set_val = 0x03;\r
+ break;\r
+ case 4: //aqua\r
+ set_val = 0x04;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ //image effect\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x26, set_val);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ return 0;\r
+ }\r
+ SENSOR_TR("\n%s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value);\r
+ return -1;\r
+}\r
+#endif\r
+\r
+static const struct v4l2_querymenu sensor_menus[] =\r
+{\r
+ #if CONFIG_SENSOR_Effect\r
+ { .id = V4L2_CID_EFFECT, .index = 0, .name = "normal", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,},\r
+ { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,},\r
+ { .id = V4L2_CID_EFFECT, .index = 4, .name = "aqua", .reserved = 0,},\r
+ #endif\r
+ \r
+ #if CONFIG_SENSOR_WhiteBalance\r
+ { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,},\r
+ { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,},\r
+ { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,},\r
+ #endif\r
+\r
+\r
+ #if CONFIG_SENSOR_Scene\r
+ { .id = V4L2_CID_SCENE, .index = 0, .name = "normal", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "auto", .reserved = 0,},\r
+ { .id = V4L2_CID_SCENE, .index = 2, .name = "landscape", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 3, .name = "night", .reserved = 0,},\r
+ { .id = V4L2_CID_SCENE, .index = 4, .name = "night_portrait", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 5, .name = "snow", .reserved = 0,},\r
+ { .id = V4L2_CID_SCENE, .index = 6, .name = "sports", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 7, .name = "candlelight", .reserved = 0,},\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Flash\r
+ { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,},\r
+ { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,},\r
+ #endif\r
+};\r
+\r
+static struct v4l2_queryctrl sensor_controls[] =\r
+{\r
+ #if CONFIG_SENSOR_WhiteBalance\r
+ {\r
+ .id = V4L2_CID_DO_WHITE_BALANCE,\r
+ .type = V4L2_CTRL_TYPE_MENU,\r
+ .name = "White Balance Control",\r
+ .minimum = 0,\r
+ .maximum = 4,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Brightness\r
+ {\r
+ .id = V4L2_CID_BRIGHTNESS,\r
+ .type = V4L2_CTRL_TYPE_INTEGER,\r
+ .name = "Brightness Control",\r
+ .minimum = -3,\r
+ .maximum = 2,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Effect\r
+ {\r
+ .id = V4L2_CID_EFFECT,\r
+ .type = V4L2_CTRL_TYPE_MENU,\r
+ .name = "Effect Control",\r
+ .minimum = 0,\r
+ .maximum = 4,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Exposure\r
+ {\r
+ .id = V4L2_CID_EXPOSURE,\r
+ .type = V4L2_CTRL_TYPE_INTEGER,\r
+ .name = "Exposure Control",\r
+ .minimum = 0,\r
+ .maximum = 5,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Saturation\r
+ {\r
+ .id = V4L2_CID_SATURATION,\r
+ .type = V4L2_CTRL_TYPE_INTEGER,\r
+ .name = "Saturation Control",\r
+ .minimum = 0,\r
+ .maximum = 2,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Contrast\r
+ {\r
+ .id = V4L2_CID_CONTRAST,\r
+ .type = V4L2_CTRL_TYPE_INTEGER,\r
+ .name = "Contrast Control",\r
+ .minimum = -3,\r
+ .maximum = 3,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Mirror\r
+ {\r
+ .id = V4L2_CID_HFLIP,\r
+ .type = V4L2_CTRL_TYPE_BOOLEAN,\r
+ .name = "Mirror Control",\r
+ .minimum = 0,\r
+ .maximum = 1,\r
+ .step = 1,\r
+ .default_value = 1,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Flip\r
+ {\r
+ .id = V4L2_CID_VFLIP,\r
+ .type = V4L2_CTRL_TYPE_BOOLEAN,\r
+ .name = "Flip Control",\r
+ .minimum = 0,\r
+ .maximum = 1,\r
+ .step = 1,\r
+ .default_value = 1,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Scene\r
+ {\r
+ .id = V4L2_CID_SCENE,\r
+ .type = V4L2_CTRL_TYPE_MENU,\r
+ .name = "Scene Control",\r
+ .minimum = 0,\r
+ .maximum = 7,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_DigitalZoom\r
+ {\r
+ .id = V4L2_CID_ZOOM_ABSOLUTE,\r
+ .type = V4L2_CTRL_TYPE_INTEGER,\r
+ .name = "DigitalZoom Control",\r
+ .minimum = 100,\r
+ .maximum = 275, // app pass 275-25 maximum\r
+ .step = 25,\r
+ .default_value = 100,\r
+ }, \r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Focus\r
+ /*{\r
+ .id = V4L2_CID_FOCUS_RELATIVE,\r
+ .type = V4L2_CTRL_TYPE_INTEGER,\r
+ .name = "Focus Control",\r
+ .minimum = -1,\r
+ .maximum = 1,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ }, */\r
+ {\r
+ .id = V4L2_CID_FOCUS_ABSOLUTE,\r
+ .type = V4L2_CTRL_TYPE_INTEGER,\r
+ .name = "Focus Control",\r
+ .minimum = 0,\r
+ .maximum = 2,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ {\r
+ .id = V4L2_CID_FOCUS_AUTO,\r
+ .type = V4L2_CTRL_TYPE_BOOLEAN,\r
+ .name = "Focus Control",\r
+ .minimum = 0,\r
+ .maximum = 1,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },{\r
+ .id = V4L2_CID_FOCUS_CONTINUOUS,\r
+ .type = V4L2_CTRL_TYPE_BOOLEAN,\r
+ .name = "Focus Control",\r
+ .minimum = 0,\r
+ .maximum = 1,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+\r
+ #if CONFIG_SENSOR_Flash\r
+ {\r
+ .id = V4L2_CID_FLASH,\r
+ .type = V4L2_CTRL_TYPE_BOOLEAN,\r
+ .name = "Flash Control Focus",\r
+ .minimum = 0,\r
+ .maximum = 3,\r
+ .step = 1,\r
+ .default_value = 0,\r
+ },\r
+ #endif\r
+ #if CONFIG_SENSOR_FOCUS_ZONE\r
+ {\r
+ .id = V4L2_CID_FOCUSZONE,\r
+ .type = V4L2_CTRL_TYPE_BOOLEAN,\r
+ .name = "Focus Zone support",\r
+ .minimum = 0,\r
+ .maximum = 1,\r
+ .step = 1,\r
+ .default_value = 1,\r
+ },\r
+ #endif\r
+ #if CONFIG_SENSOR_FACE_DETECT\r
+ {\r
+ .id = V4L2_CID_FACEDETECT,\r
+ .type = V4L2_CTRL_TYPE_BOOLEAN,\r
+ .name = "face dectect support",\r
+ .minimum = 0,\r
+ .maximum = 1,\r
+ .step = 1,\r
+ .default_value = 1,\r
+ },\r
+ #endif\r
+\r
+};\r
+\r
+\r
+static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl)\r
+{\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ const struct v4l2_queryctrl *qctrl;\r
+\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id);\r
+\r
+ if (!qctrl)\r
+ {\r
+ SENSOR_TR("\n %s ioctrl id = 0x%x is invalidate \n", SENSOR_NAME_STRING(), ctrl->id);\r
+ return -EINVAL;\r
+ }\r
+\r
+ switch (ctrl->id)\r
+ {\r
+ case V4L2_CID_BRIGHTNESS:\r
+ {\r
+ ctrl->value = sensor->isp_priv_info.brightness;\r
+ break;\r
+ }\r
+ case V4L2_CID_SATURATION:\r
+ {\r
+ ctrl->value = sensor->isp_priv_info.saturation;\r
+ break;\r
+ }\r
+ case V4L2_CID_CONTRAST:\r
+ {\r
+ ctrl->value = sensor->isp_priv_info.contrast;\r
+ break;\r
+ }\r
+ case V4L2_CID_DO_WHITE_BALANCE:\r
+ {\r
+ ctrl->value = sensor->isp_priv_info.whiteBalance;\r
+ break;\r
+ }\r
+ case V4L2_CID_EXPOSURE:\r
+ {\r
+ ctrl->value = sensor->isp_priv_info.exposure;\r
+ break;\r
+ }\r
+ case V4L2_CID_HFLIP:\r
+ {\r
+ ctrl->value = sensor->isp_priv_info.mirror;\r
+ break;\r
+ }\r
+ case V4L2_CID_VFLIP:\r
+ {\r
+ ctrl->value = sensor->isp_priv_info.flip;\r
+ break;\r
+ }\r
+ case V4L2_CID_ZOOM_ABSOLUTE:\r
+ {\r
+ ctrl->value = sensor->isp_priv_info.digitalzoom;\r
+ break;\r
+ }\r
+ default :\r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+static int sensor_set_face_detect(struct i2c_client *client, int value);\r
+#if CONFIG_SENSOR_Exposure\r
+static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value)\r
+{\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ u8 set_val = 0x0 ,ac_val = 0x01;\r
+ printk("set iso ,value = %d......\n", value);\r
+\r
+ if ((value >= qctrl->minimum) && (value <= qctrl->maximum))\r
+ {\r
+ switch(value){\r
+ case 0: //iso auto\r
+ set_val = 0x0;\r
+ break;\r
+ case 1: //iso 100\r
+ set_val = 0x1;\r
+ break;\r
+ case 2: //iso 200\r
+ set_val = 0x2;\r
+ break;\r
+ case 3: //iso 400\r
+ set_val = 0x3;\r
+ break;\r
+ case 4: //iso 800\r
+ set_val = 0x4;\r
+ break;\r
+ case 5: //iso 1600\r
+ set_val = 0x5;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ \r
+ //iso\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x17, set_val);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ //AC freq :50Hz\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x16, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ return 0;\r
+ }\r
+ SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value);\r
+ return -EINVAL;\r
+}\r
+#endif\r
+\r
+\r
+static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl)\r
+{\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+ const struct v4l2_queryctrl *qctrl;\r
+\r
+\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id);\r
+\r
+ if (!qctrl)\r
+ {\r
+ SENSOR_TR("\n %s ioctrl id = 0x%x is invalidate \n", SENSOR_NAME_STRING(), ctrl->id);\r
+ return -EINVAL;\r
+ }\r
+\r
+ switch (ctrl->id)\r
+ {\r
+#if CONFIG_SENSOR_Brightness\r
+ case V4L2_CID_BRIGHTNESS:\r
+ {\r
+ if (ctrl->value != sensor->isp_priv_info.brightness)\r
+ {\r
+ if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0)\r
+ {\r
+ return -EINVAL;\r
+ }\r
+ sensor->isp_priv_info.brightness = ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_Exposure\r
+ case V4L2_CID_EXPOSURE:\r
+ {\r
+ if (ctrl->value != sensor->isp_priv_info.exposure)\r
+ {\r
+ if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0)\r
+ {\r
+ return -EINVAL;\r
+ }\r
+ sensor->isp_priv_info.exposure = ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_Saturation\r
+ case V4L2_CID_SATURATION:\r
+ {\r
+ if (ctrl->value != sensor->isp_priv_info.saturation)\r
+ {\r
+ if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0)\r
+ {\r
+ return -EINVAL;\r
+ }\r
+ sensor->isp_priv_info.saturation = ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_Contrast\r
+ case V4L2_CID_CONTRAST:\r
+ {\r
+ if (ctrl->value != sensor->isp_priv_info.contrast)\r
+ {\r
+ if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0)\r
+ {\r
+ return -EINVAL;\r
+ }\r
+ sensor->isp_priv_info.contrast = ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_WhiteBalance\r
+ case V4L2_CID_DO_WHITE_BALANCE:\r
+ {\r
+ if (ctrl->value != sensor->isp_priv_info.whiteBalance)\r
+ {\r
+ if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0)\r
+ {\r
+ return -EINVAL;\r
+ }\r
+ sensor->isp_priv_info.whiteBalance = ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_Mirror\r
+ case V4L2_CID_HFLIP:\r
+ {\r
+ if (ctrl->value != sensor->isp_priv_info.mirror)\r
+ {\r
+ if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.mirror = ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_Flip\r
+ case V4L2_CID_VFLIP:\r
+ {\r
+ if (ctrl->value != sensor->isp_priv_info.flip)\r
+ {\r
+ if (sensor_set_flip(icd, qctrl,ctrl->value) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.flip = ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_DigitalZoom\r
+ case V4L2_CID_ZOOM_ABSOLUTE:\r
+ {\r
+ int val_offset = 0;\r
+ printk("V4L2_CID_ZOOM_ABSOLUTE ...... ctrl->value = %d\n",ctrl->value);\r
+ if ((ctrl->value < qctrl->minimum) || (ctrl->value > qctrl->maximum)){\r
+ return -EINVAL;\r
+ }\r
+\r
+ if (ctrl->value != sensor->isp_priv_info.digitalzoom)\r
+ {\r
+ val_offset = ctrl->value -sensor->isp_priv_info.digitalzoom;\r
+\r
+ if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.digitalzoom += val_offset;\r
+\r
+ SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->isp_priv_info.digitalzoom);\r
+ }\r
+\r
+ break;\r
+ }\r
+ case V4L2_CID_ZOOM_RELATIVE:\r
+ {\r
+ if (ctrl->value)\r
+ {\r
+ if (sensor_set_digitalzoom(icd, qctrl,&ctrl->value) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.digitalzoom += ctrl->value;\r
+\r
+ SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->isp_priv_info.digitalzoom);\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return 0;\r
+}\r
+static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl)\r
+{\r
+ const struct v4l2_queryctrl *qctrl;\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ struct isp_dev *sensor = to_sensor(client);\r
+\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id);\r
+\r
+ if (!qctrl)\r
+ {\r
+ SENSOR_TR("\n %s ioctrl id = 0x%x is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id);\r
+ return -EINVAL;\r
+ }\r
+\r
+ switch (ext_ctrl->id)\r
+ {\r
+ case V4L2_CID_SCENE:\r
+ {\r
+ ext_ctrl->value = sensor->isp_priv_info.scene;\r
+ break;\r
+ }\r
+ case V4L2_CID_EFFECT:\r
+ {\r
+ ext_ctrl->value = sensor->isp_priv_info.effect;\r
+ break;\r
+ }\r
+ case V4L2_CID_ZOOM_ABSOLUTE:\r
+ {\r
+ ext_ctrl->value = sensor->isp_priv_info.digitalzoom;\r
+ break;\r
+ }\r
+ case V4L2_CID_ZOOM_RELATIVE:\r
+ {\r
+ return -EINVAL;\r
+ }\r
+ case V4L2_CID_FOCUS_ABSOLUTE:\r
+ {\r
+ return -EINVAL;\r
+ }\r
+ case V4L2_CID_FOCUS_RELATIVE:\r
+ {\r
+ return -EINVAL;\r
+ }\r
+ case V4L2_CID_FLASH:\r
+ {\r
+ ext_ctrl->value = sensor->isp_priv_info.flash;\r
+ break;\r
+ }\r
+ case V4L2_CID_FACEDETECT:\r
+ {\r
+ ext_ctrl->value =sensor->isp_priv_info.face ;\r
+ break;\r
+ }\r
+ default :\r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+#if CONFIG_SENSOR_Focus\r
+static int sensor_set_auto_focus(struct i2c_client *client, int value)\r
+{\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ u8 zone_x = 0x0,zone_y = 0x0; // 0->0x0f\r
+ int ret = 0;\r
+// return 0;\r
+ //set the zone\r
+ // printk("lx = %x,rx = %x,ty = %x,dy = %x\n",sensor->isp_priv_info.focus_zone.lx,sensor->isp_priv_info.focus_zone.rx,sensor->isp_priv_info.focus_zone.ty,sensor->isp_priv_info.focus_zone.dy);\r
+ zone_x = (sensor->isp_priv_info.focus_zone.lx << 4) | (sensor->isp_priv_info.focus_zone.rx & 0x0f);\r
+ zone_y = (sensor->isp_priv_info.focus_zone.ty << 4) | (sensor->isp_priv_info.focus_zone.dy & 0x0f);\r
+ //auto focus\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ if((zone_x != 0) && (zone_y !=0)){\r
+ sendI2cCmd(client, 0x21, zone_x);\r
+ sendI2cCmd(client, 0x22, zone_y);\r
+ }else{\r
+ sendI2cCmd(client, 0x21, 0x6a);\r
+ sendI2cCmd(client, 0x22, 0x6a);\r
+ }\r
+ printk("%s:auto focus, val = %d,zone_x = %x, zone_y = %x\n",__func__,value,zone_x,zone_y);\r
+ sendI2cCmd(client, 0x23, value);\r
+ ret = isp_reg_value_check(client,0x0E,0xBB);\r
+ if(ret == 0xCC){\r
+ printk("%s:%d,auto focus failed!\n",__func__,__LINE__);\r
+ }\r
+ // printk("%s:auto focus done\n",__func__);\r
+ return 0;\r
+}\r
+\r
+enum sensor_work_state\r
+{\r
+ sensor_work_ready = 0,\r
+ sensor_working,\r
+};\r
+enum sensor_wq_result\r
+{\r
+ WqRet_success = 0,\r
+ WqRet_fail = -1,\r
+ WqRet_inval = -2\r
+};\r
+enum sensor_wq_cmd\r
+{\r
+ WqCmd_af_init,\r
+ WqCmd_af_single,\r
+ WqCmd_af_special_pos,\r
+ WqCmd_af_far_pos,\r
+ WqCmd_af_near_pos,\r
+ WqCmd_af_continues,\r
+ WqCmd_af_return_idle,\r
+};\r
+struct sensor_work\r
+{\r
+ struct i2c_client *client;\r
+ struct delayed_work dwork;\r
+ enum sensor_wq_cmd cmd;\r
+ wait_queue_head_t done;\r
+ enum sensor_wq_result result;\r
+ bool wait;\r
+ int var; \r
+};\r
+\r
+static void sensor_af_workqueue(struct work_struct *work)\r
+{\r
+ struct sensor_work *sensor_work = container_of(work, struct sensor_work, dwork.work);\r
+ struct i2c_client *client = sensor_work->client;\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ \r
+ SENSOR_DG("%s %s Enter, cmd:0x%x \n",SENSOR_NAME_STRING(), __FUNCTION__,sensor_work->cmd);\r
+ \r
+ mutex_lock(&sensor->wq_lock);\r
+ \r
+// printk("%s:auto focus, val = %d\n",__func__,sensor_work->var);\r
+ //auto focus\r
+ if(sensor_set_auto_focus(client,sensor_work->var) == 0){\r
+ sensor_work->result = WqRet_success;\r
+ }else{\r
+ printk("%s:auto focus failed\n",__func__);\r
+ }\r
+// printk("%s:auto focus done\n",__func__);\r
+ \r
+//set_end:\r
+ if (sensor_work->wait == false) {\r
+ kfree((void*)sensor_work);\r
+ } else {\r
+ wake_up(&sensor_work->done); \r
+ }\r
+ mutex_unlock(&sensor->wq_lock); \r
+ return;\r
+}\r
+\r
+static int sensor_af_workqueue_set(struct soc_camera_device *icd, enum sensor_wq_cmd cmd, int var, bool wait)\r
+{\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ struct isp_dev *sensor = to_sensor(client); \r
+ struct sensor_work *wk;\r
+ int ret=0;\r
+\r
+ if (sensor->sensor_wq == NULL) { \r
+ ret = -EINVAL;\r
+ goto sensor_af_workqueue_set_end;\r
+ }\r
+\r
+ wk = kzalloc(sizeof(struct sensor_work), GFP_KERNEL);\r
+ if (wk) {\r
+ wk->client = client;\r
+ INIT_WORK(&(wk->dwork.work), sensor_af_workqueue);\r
+ wk->cmd = cmd;\r
+ wk->result = WqRet_inval;\r
+ wk->wait = wait;\r
+ wk->var = var;\r
+ init_waitqueue_head(&wk->done);\r
+ \r
+ queue_delayed_work(sensor->sensor_wq,&(wk->dwork),0);\r
+ \r
+ /* ddl@rock-chips.com: \r
+ * video_lock is been locked in v4l2_ioctl function, but auto focus may slow,\r
+ * As a result any other ioctl calls will proceed very, very slowly since each call\r
+ * will have to wait for the AF to finish. Camera preview is pause,because VIDIOC_QBUF \r
+ * and VIDIOC_DQBUF is sched. so unlock video_lock here.\r
+ */\r
+ if (wait == true) {\r
+ mutex_unlock(&icd->video_lock);\r
+ if (wait_event_timeout(wk->done, (wk->result != WqRet_inval), msecs_to_jiffies(5000)) == 0) { //hhb\r
+ SENSOR_TR("%s %s cmd(%d) is timeout!\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd);\r
+ }\r
+ ret = wk->result;\r
+ kfree((void*)wk);\r
+ mutex_lock(&icd->video_lock); \r
+ }\r
+ \r
+ } else {\r
+ SENSOR_TR("%s %s cmd(%d) ingore,because struct sensor_work malloc failed!",SENSOR_NAME_STRING(),__FUNCTION__,cmd);\r
+ ret = -1;\r
+ }\r
+sensor_af_workqueue_set_end:\r
+ return ret;\r
+}\r
+#endif\r
+\r
+\r
+#if CONFIG_SENSOR_Scene\r
+static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value)\r
+{\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+//when scene mod is working , face deteciton and awb and iso are not recomemnded.\r
+ if ((value >= qctrl->minimum) && (value <= qctrl->maximum))\r
+ {\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ // sendI2cCmd(client, 0x13, value);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value);\r
+ return 0;\r
+ }\r
+ SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value);\r
+ return -EINVAL;\r
+}\r
+#endif\r
+static int sensor_set_face_detect(struct i2c_client *client, int value)\r
+{\r
+ u8 orien, window;\r
+ window = (value & 0x100)>>8;\r
+ //face detect\r
+ switch (value & 0x1f){\r
+ case 0:\r
+ orien = 0x02; //off\r
+ break;\r
+ case 1:\r
+ orien = 0x80; //default on\r
+ break;\r
+ case 2:\r
+ orien = 0x90; //90 degree\r
+ break;\r
+ case 3:\r
+ orien = 0xb0; //180 degree\r
+ break;\r
+ case 4:\r
+ orien = 0xa0; //270 degree\r
+ break;\r
+ default:\r
+ orien = 0x02; //off\r
+\r
+ }\r
+ printk("orien = %x,window = %d \n",orien,window);\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x2a, orien);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x29, window);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value);\r
+ return 0;\r
+}\r
+#if CONFIG_SENSOR_Flip\r
+//off 0x00;mirror 0x01,flip 0x10;\r
+static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value)\r
+{\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x28, 0x10);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ return 0;\r
+\r
+}\r
+#endif\r
+#if CONFIG_SENSOR_Mirror\r
+static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value)\r
+{\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x28, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ return 0;\r
+}\r
+#endif\r
+\r
+#if CONFIG_SENSOR_DigitalZoom\r
+static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value)\r
+{\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ const struct v4l2_queryctrl *qctrl_info;\r
+ int digitalzoom_cur, digitalzoom_total;\r
+ u8 zoom_val = 0;\r
+\r
+ qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE);\r
+ if (!qctrl_info){\r
+ return -EINVAL;\r
+ }\r
+\r
+ digitalzoom_cur = sensor->isp_priv_info.digitalzoom;\r
+ digitalzoom_total = qctrl_info->maximum;\r
+\r
+ if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total))\r
+ {\r
+ SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur);\r
+ return -EINVAL;\r
+ }\r
+\r
+ if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum))\r
+ {\r
+ SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur);\r
+ return -EINVAL;\r
+ }\r
+\r
+ if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total))\r
+ {\r
+ *value = digitalzoom_total - digitalzoom_cur;\r
+ }\r
+\r
+ if ((*value < 0) && ((digitalzoom_cur + *value) < 0))\r
+ {\r
+ *value = 0 - digitalzoom_cur;\r
+ }\r
+\r
+ digitalzoom_cur += *value;\r
+ printk("digitalzoom_cur = %d =====\n",digitalzoom_cur);\r
+ switch(digitalzoom_cur){\r
+ case 100 :\r
+ zoom_val = 0;\r
+ break;\r
+ case 125 :\r
+ zoom_val = 1;\r
+ break;\r
+ case 150 :\r
+ zoom_val = 2;\r
+ break;\r
+ case 175 :\r
+ zoom_val = 3;\r
+ break;\r
+ case 200 :\r
+ zoom_val = 4;\r
+ break;\r
+ case 225 :\r
+ zoom_val = 5;\r
+ break;\r
+ case 250 :\r
+ zoom_val = 6;\r
+ break;\r
+ case 275 :\r
+ zoom_val = 7;\r
+ break;\r
+ case 300 :\r
+ zoom_val = 8;\r
+ break;\r
+ }\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x2b, zoom_val);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ mdelay(5);\r
+ return 0;\r
+}\r
+#endif\r
+static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl)\r
+{\r
+ const struct v4l2_queryctrl *qctrl;\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ int val_offset;\r
+\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id);\r
+\r
+ if (!qctrl)\r
+ {\r
+ SENSOR_TR("\n %s ioctrl id = 0x%x is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id);\r
+ return -EINVAL;\r
+ }\r
+\r
+ val_offset = 0;\r
+ switch (ext_ctrl->id)\r
+ {\r
+#if CONFIG_SENSOR_Scene\r
+ case V4L2_CID_SCENE:\r
+ {\r
+ if (ext_ctrl->value != sensor->isp_priv_info.scene)\r
+ {\r
+ if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.scene = ext_ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_Effect\r
+ case V4L2_CID_EFFECT:\r
+ { \r
+ if (ext_ctrl->value != sensor->isp_priv_info.effect)\r
+ { \r
+ if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.effect= ext_ctrl->value;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_DigitalZoom\r
+ case V4L2_CID_ZOOM_ABSOLUTE:\r
+ {\r
+ printk("V4L2_CID_ZOOM_ABSOLUTE ...... ext_ctrl->value = %d\n",ext_ctrl->value);\r
+ if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)){\r
+ return -EINVAL;\r
+ }\r
+\r
+ if (ext_ctrl->value != sensor->isp_priv_info.digitalzoom)\r
+ {\r
+ val_offset = ext_ctrl->value -sensor->isp_priv_info.digitalzoom;\r
+\r
+ if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.digitalzoom += val_offset;\r
+\r
+ SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->isp_priv_info.digitalzoom);\r
+ }\r
+\r
+ break;\r
+ }\r
+ case V4L2_CID_ZOOM_RELATIVE:\r
+ {\r
+ if (ext_ctrl->value)\r
+ {\r
+ if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.digitalzoom += ext_ctrl->value;\r
+\r
+ SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->isp_priv_info.digitalzoom);\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_Focus\r
+ case V4L2_CID_FOCUS_ABSOLUTE:\r
+ {\r
+ //DO MACRO\r
+ if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum))\r
+ return -EINVAL;\r
+ \r
+ if (SENSOR_AF_CONTINUOUS == sensor->isp_priv_info.auto_focus) {\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_CONTINUOUS_OFF,true);\r
+ }\r
+ if (ext_ctrl->value == 1) {\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_MACRO,true);\r
+ sensor->isp_priv_info.auto_focus = SENSOR_AF_MACRO;\r
+ } else if(ext_ctrl->value == 0){\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_MODE_CLOSE,true);\r
+ sensor->isp_priv_info.auto_focus = SENSOR_AF_MODE_CLOSE;\r
+ }\r
+ break;\r
+ }\r
+ case V4L2_CID_FOCUS_RELATIVE:\r
+ {\r
+ // if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum))\r
+ // return -EINVAL;\r
+\r
+ // sensor_set_focus_relative(icd, qctrl,ext_ctrl->value);\r
+ break;\r
+ }\r
+ \r
+ case V4L2_CID_FOCUS_AUTO:\r
+ {\r
+ \r
+ if (SENSOR_AF_CONTINUOUS == sensor->isp_priv_info.auto_focus) {\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_CONTINUOUS_OFF,true);\r
+ }\r
+ if (ext_ctrl->value == 1) {\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_SINGLE,true);\r
+ sensor->isp_priv_info.auto_focus = SENSOR_AF_SINGLE;\r
+ } else if(ext_ctrl->value == 0){\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_MODE_CLOSE,true);\r
+ sensor->isp_priv_info.auto_focus = SENSOR_AF_MODE_CLOSE;\r
+ }\r
+ break;\r
+ }\r
+ case V4L2_CID_FOCUS_CONTINUOUS:\r
+ {\r
+ if ((ext_ctrl->value == 1) && (SENSOR_AF_CONTINUOUS != sensor->isp_priv_info.auto_focus)) {\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_MODE_CLOSE,true);\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_CONTINUOUS,true);\r
+ sensor->isp_priv_info.auto_focus = SENSOR_AF_CONTINUOUS;\r
+ }else if(ext_ctrl->value == 0){\r
+ sensor_af_workqueue_set(icd,0,SENSOR_AF_CONTINUOUS_OFF,true);\r
+ sensor->isp_priv_info.auto_focus = SENSOR_AF_CONTINUOUS_OFF;\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_Flash\r
+ case V4L2_CID_FLASH:\r
+ {\r
+ if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0)\r
+ return -EINVAL;\r
+ sensor->info_priv.flash = ext_ctrl->value;\r
+\r
+ SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->isp_priv_info.flash);\r
+ break;\r
+ }\r
+#endif\r
+#if CONFIG_SENSOR_FACE_DETECT\r
+ case V4L2_CID_FACEDETECT:\r
+ {\r
+ if(sensor->isp_priv_info.face != ext_ctrl->value){\r
+ if (sensor_set_face_detect(client, ext_ctrl->value) != 0)\r
+ return -EINVAL;\r
+ sensor->isp_priv_info.face = ext_ctrl->value;\r
+ SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->isp_priv_info.face);\r
+ }\r
+ break;\r
+ }\r
+#endif\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl)\r
+{\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+ int i, error_cnt=0, error_idx=-1;\r
+\r
+ for (i=0; i<ext_ctrl->count; i++) {\r
+ if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) {\r
+ error_cnt++;\r
+ error_idx = i;\r
+ }\r
+ }\r
+\r
+ if (error_cnt > 1)\r
+ error_idx = ext_ctrl->count;\r
+\r
+ if (error_idx != -1) {\r
+ ext_ctrl->error_idx = error_idx;\r
+ return -EINVAL;\r
+ } else {\r
+ return 0;\r
+ }\r
+}\r
+static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl)\r
+{\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+ struct isp_dev *sensor = to_sensor(client);\r
+\r
+ int i, error_cnt=0, error_idx=-1;\r
+ for (i=0; i<ext_ctrl->count; i++) {\r
+ if(ext_ctrl->controls[i].id == V4L2_CID_FOCUS_AUTO){\r
+ int lx,ty,rx,dy;\r
+ /*\r
+ lx = (s16)((int)(ext_ctrl->reserved[0])>>16);\r
+ ty = (s16)(ext_ctrl->reserved[0]);\r
+ rx = (s16)((int)(ext_ctrl->reserved[1])>>16);\r
+ dy = (s16)(ext_ctrl->reserved[1]);\r
+ */\r
+ //\r
+ lx = ext_ctrl->controls[i].rect[0];\r
+ ty = ext_ctrl->controls[i].rect[1];\r
+ rx = ext_ctrl->controls[i].rect[2];\r
+ dy = ext_ctrl->controls[i].rect[3];\r
+ printk("lx = %d,ty = %d,rx = %d,dy = %d\n",lx,ty,rx,dy);\r
+ sensor->isp_priv_info.focus_zone.lx = (lx+1000)*16/2000;\r
+ sensor->isp_priv_info.focus_zone.ty = (ty+1000)*16/2000;\r
+ sensor->isp_priv_info.focus_zone.rx = (rx+1000)*16/2000;\r
+ sensor->isp_priv_info.focus_zone.dy = (dy+1000)*16/2000;\r
+ // printk("lx = %x,ty = %x,rx = %x,dy = %x\n",sensor->isp_priv_info.focus_zone.lx,sensor->isp_priv_info.focus_zone.ty,sensor->isp_priv_info.focus_zone.rx,sensor->isp_priv_info.focus_zone.dy);\r
+ if((lx == 0)&&(ty == 0)&&(rx==0)&&(dy==0)){\r
+ sensor->isp_priv_info.focus_zone.lx = 0;\r
+ sensor->isp_priv_info.focus_zone.ty = 0;\r
+ sensor->isp_priv_info.focus_zone.rx = 0;\r
+ sensor->isp_priv_info.focus_zone.dy = 0;\r
+ }\r
+ if(sensor->isp_priv_info.focus_zone.lx > 0xf){\r
+ sensor->isp_priv_info.focus_zone.lx = 0xf;\r
+ } \r
+ if(sensor->isp_priv_info.focus_zone.ty > 0xf){\r
+ sensor->isp_priv_info.focus_zone.ty = 0xf;\r
+ }\r
+ if(sensor->isp_priv_info.focus_zone.rx > 0xf){\r
+ sensor->isp_priv_info.focus_zone.rx = 0xf;\r
+ } \r
+ if(sensor->isp_priv_info.focus_zone.dy > 0xf){\r
+ sensor->isp_priv_info.focus_zone.dy = 0xf;\r
+ } \r
+ }\r
+ if(ext_ctrl->controls[i].id == V4L2_CID_ZOOM_ABSOLUTE){\r
+ printk("%s: digtal zoom \n",__func__);\r
+ }\r
+\r
+ if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) {\r
+ error_cnt++;\r
+ error_idx = i;\r
+ }\r
+ }\r
+\r
+ if (error_cnt > 1)\r
+ error_idx = ext_ctrl->count;\r
+\r
+ if (error_idx != -1) {\r
+ ext_ctrl->error_idx = error_idx;\r
+ return -EINVAL;\r
+ } else {\r
+ return 0;\r
+ }\r
+}\r
+\r
+//640*480 default\r
+static int sensor_set_isp_output_res(struct i2c_client *client,enum ISP_OUTPUT_RES outputSize){\r
+ u8 check_val = 0;\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ switch(outputSize)\r
+ {\r
+ case OUTPUT_QCIF:\r
+ {\r
+ SENSOR_TR(" SET qcif!\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x05);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 176*144\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x00);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x00);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+ break;\r
+ case OUTPUT_HQVGA:\r
+ {\r
+ SENSOR_TR(" SET hqvga !\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x05);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 240*160\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x00);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ break;\r
+ }\r
+ case OUTPUT_QVGA:\r
+ {\r
+ SENSOR_TR(" SET qvga RES!\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x05);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 320*240\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x02);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x00);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+ break;\r
+ case OUTPUT_CIF:\r
+ {\r
+ SENSOR_TR(" SET cif RES!\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x05);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 352*288\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x04);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x00);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+\r
+ break;\r
+ case OUTPUT_VGA:\r
+ {\r
+ SENSOR_TR(" SET VGA RES!\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x05);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 640x480\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x03);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x00);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+ break;\r
+ case OUTPUT_SVGA:\r
+ {\r
+ SENSOR_TR(" SET SVGA RES!\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x05);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ //isp output 800*600\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x06);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x00);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+ break;\r
+ case OUTPUT_720P:\r
+ {\r
+ SENSOR_TR(" SET 720P RES!\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x0c);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 1280*720\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x0c);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x00);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ }\r
+ break;\r
+ case OUTPUT_XGA:\r
+ {\r
+ SENSOR_TR(" SET XGA RES!\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x0E);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 1024*768\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x07);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+ break;\r
+ case OUTPUT_SXGA:\r
+ break;\r
+ case OUTPUT_UXGA:\r
+ {\r
+ SENSOR_TR(" SET UXGA RES!\n");\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x0E);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 1600*1200\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x09);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+ break;\r
+ case OUTPUT_1080P:\r
+ break;\r
+ case OUTPUT_QXGA:\r
+ {\r
+ SENSOR_TR(" SET QXGA RES!\n");\r
+ //sensor output 2592*1944\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x0E);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 2592*1944\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x0D);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+ break;\r
+ case OUTPUT_QSXGA:\r
+ {\r
+ SENSOR_TR(" SET QSXGA RES!\n");\r
+ //sensor output 2592*1944\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x08, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x10, 0x0E);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ //isp output 2592*1944\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x11, 0x0E);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x07, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ }\r
+ break;\r
+ default:\r
+ SENSOR_TR("%s %s isp not support this resolution!\n",SENSOR_NAME_STRING(),__FUNCTION__);\r
+ \r
+ }\r
+\r
+ //AC freq :50Hz\r
+ sendI2cCmd(client, 0x0E, 0x00);\r
+ sendI2cCmd(client, 0x16, 0x01);\r
+ isp_reg_value_check(client,0x0E,0xBB);\r
+ \r
+ return 0;\r
+\r
+}\r
+static int sensor_init(struct v4l2_subdev *sd, u32 val)\r
+{\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+ struct soc_camera_link *icl = to_soc_camera_link(icd);\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ const struct v4l2_queryctrl *qctrl;\r
+ //define the outputsize , qcif - cif is down-scaling from vga , or jaggies is very serious\r
+ sensor->isp_priv_info.outputSize = /*OUTPUT_QCIF|OUTPUT_HQVGA|OUTPUT_QVGA |OUTPUT_CIF |*/OUTPUT_VGA | OUTPUT_SVGA|OUTPUT_720P|OUTPUT_XGA|OUTPUT_QXGA|OUTPUT_UXGA|OUTPUT_QSXGA;\r
+ sensor->isp_priv_info.curRes = -1;\r
+ #if 1\r
+ //reset , reset pin low ,then high\r
+ if (icl->reset)\r
+ icl->reset(icd->pdev);\r
+ #endif\r
+ isp_init_cmds(client);\r
+ #if 1\r
+ isp_reg_value_check(client,0x01,PRODUCT_VERSION_VALUE_REG1);\r
+ printk("init default size :VGA\n");\r
+ sensor->isp_priv_info.curRes = OUTPUT_VGA;\r
+ sensor_set_isp_output_res(client,OUTPUT_VGA);\r
+ #endif\r
+ /* sensor sensor information for initialization */\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.whiteBalance = qctrl->default_value;\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.brightness = qctrl->default_value;\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.effect = qctrl->default_value;\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE);\r
+ if (qctrl){\r
+ sensor->isp_priv_info.exposure = qctrl->default_value;\r
+ //set expose auto \r
+ sensor_set_exposure(icd,qctrl,qctrl->default_value);\r
+ }\r
+\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.saturation = qctrl->default_value;\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.contrast = qctrl->default_value;\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.mirror = qctrl->default_value;\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.flip = qctrl->default_value;\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE);\r
+ if (qctrl){\r
+ sensor->isp_priv_info.scene = qctrl->default_value;\r
+ sensor_set_scene(icd,qctrl,qctrl->default_value);\r
+ }\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.digitalzoom = qctrl->default_value;\r
+ /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */\r
+ //qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_AUTO);\r
+ //if (qctrl)\r
+ sensor->isp_priv_info.auto_focus = SENSOR_AF_CONTINUOUS_OFF;\r
+ qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FACEDETECT);\r
+ if (qctrl)\r
+ sensor->isp_priv_info.face = qctrl->default_value;\r
+ return 0;\r
+}\r
+static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)\r
+{\r
+ return 0;\r
+}\r
+static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on)\r
+{\r
+#if 0\r
+ struct soc_camera_link *icl = to_soc_camera_link(icd);\r
+ int ret = 0;\r
+\r
+ SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on);\r
+ switch (cmd)\r
+ {\r
+ case Sensor_PowerDown:\r
+ {\r
+ if (icl->powerdown) {\r
+ ret = icl->powerdown(icd->pdev, on);\r
+ if (ret == RK29_CAM_IO_SUCCESS) {\r
+ if (on == 0) {\r
+ mdelay(2);\r
+ if (icl->reset)\r
+ icl->reset(icd->pdev);\r
+ }\r
+ } else if (ret == RK29_CAM_EIO_REQUESTFAIL) {\r
+ ret = -ENODEV;\r
+ goto sensor_power_end;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case Sensor_Flash:\r
+ {\r
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));\r
+ struct sensor *sensor = to_sensor(client);\r
+\r
+ if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) {\r
+ sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on);\r
+ if(on){\r
+ //flash off after 2 secs\r
+ hrtimer_cancel(&(flash_off_timer.timer));\r
+ hrtimer_start(&(flash_off_timer.timer),ktime_set(0, 800*1000*1000),HRTIMER_MODE_REL);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd);\r
+ break;\r
+ }\r
+ }\r
+sensor_power_end:\r
+ return ret;\r
+#endif\r
+return 0;\r
+}\r
+#if 0\r
+static enum hrtimer_restart flash_off_func(struct hrtimer *timer){\r
+ struct flash_timer *fps_timer = container_of(timer, struct flash_timer, timer);\r
+ sensor_ioctrl(fps_timer->icd,Sensor_Flash,0);\r
+ SENSOR_DG("%s %s !!!!!!",SENSOR_NAME_STRING(),__FUNCTION__);\r
+ return 0;\r
+ \r
+}\r
+#endif\r
+static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)\r
+{\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+ struct isp_dev *sensor = to_sensor(client);\r
+\r
+ mf->width = icd->user_width;\r
+ mf->height = icd->user_height;\r
+ mf->code = sensor->isp_priv_info.fmt.code;\r
+ mf->colorspace = sensor->isp_priv_info.fmt.colorspace;\r
+ mf->field = V4L2_FIELD_NONE;\r
+ return 0;\r
+}\r
+static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)\r
+{\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ const struct sensor_datafmt *fmt;\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ //const struct v4l2_queryctrl *qctrl;\r
+ //struct soc_camera_device *icd = client->dev.platform_data;\r
+ int ret=0;\r
+ int set_w,set_h;\r
+ int supported_size = sensor->isp_priv_info.outputSize;\r
+ int res_set = 0;\r
+ fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts,\r
+ ARRAY_SIZE(sensor_colour_fmts));\r
+ if (!fmt) {\r
+ ret = -EINVAL;\r
+ goto sensor_s_fmt_end;\r
+ }\r
+ set_w = mf->width;\r
+ set_h = mf->height;\r
+ if (((set_w <= 176) && (set_h <= 144)) && (supported_size & OUTPUT_QCIF))\r
+ {\r
+ set_w = 176;\r
+ set_h = 144;\r
+ res_set = OUTPUT_QCIF;\r
+ }\r
+ else if (((set_w <= 320) && (set_h <= 240)) && (supported_size & OUTPUT_QVGA))\r
+ {\r
+ set_w = 320;\r
+ set_h = 240;\r
+ res_set = OUTPUT_QVGA;\r
+\r
+ }\r
+ else if (((set_w <= 352) && (set_h<= 288)) && (supported_size & OUTPUT_CIF))\r
+ {\r
+ set_w = 352;\r
+ set_h = 288;\r
+ res_set = OUTPUT_CIF;\r
+ \r
+ }\r
+ else if (((set_w <= 640) && (set_h <= 480)) && (supported_size & OUTPUT_VGA))\r
+ {\r
+ set_w = 640;\r
+ set_h = 480;\r
+ res_set = OUTPUT_VGA;\r
+ \r
+ }\r
+ else if (((set_w <= 800) && (set_h <= 600)) && (supported_size & OUTPUT_SVGA))\r
+ {\r
+ set_w = 800;\r
+ set_h = 600;\r
+ res_set = OUTPUT_SVGA;\r
+ \r
+ }\r
+ else if (((set_w <= 1024) && (set_h <= 768)) && (supported_size & OUTPUT_XGA))\r
+ {\r
+ set_w = 1024;\r
+ set_h = 768;\r
+ res_set = OUTPUT_XGA;\r
+ \r
+ }\r
+ else if (((set_w <= 1280) && (set_h <= 720)) && (supported_size & OUTPUT_720P))\r
+ {\r
+ set_w = 1280;\r
+ set_h = 720;\r
+ res_set = OUTPUT_720P;\r
+ }\r
+ else if (((set_w <= 1280) && (set_h <= 1024)) && (supported_size & OUTPUT_XGA))\r
+ {\r
+ set_w = 1280;\r
+ set_h = 1024;\r
+ res_set = OUTPUT_XGA;\r
+ }\r
+ else if (((set_w <= 1600) && (set_h <= 1200)) && (supported_size & OUTPUT_UXGA))\r
+ {\r
+ set_w = 1600;\r
+ set_h = 1200;\r
+ res_set = OUTPUT_UXGA;\r
+ }\r
+ else if (((set_w <= 1920) && (set_h <= 1080)) && (supported_size & OUTPUT_1080P))\r
+ {\r
+ set_w = 1920;\r
+ set_h = 1080;\r
+ res_set = OUTPUT_1080P;\r
+ }\r
+ else if (((set_w <= 2048) && (set_h <= 1536)) && (supported_size & OUTPUT_QXGA))\r
+ {\r
+ set_w = 2048;\r
+ set_h = 1536;\r
+ res_set = OUTPUT_QXGA;\r
+ }\r
+ else if (((set_w <= 2592) && (set_h <= 1944)) && (supported_size & OUTPUT_QSXGA))\r
+ {\r
+ set_w = 2592;\r
+ set_h = 1944;\r
+ res_set = OUTPUT_QSXGA;\r
+ }\r
+ else\r
+ {\r
+ set_w = SENSOR_INIT_WIDTH;\r
+ set_h = SENSOR_INIT_HEIGHT;\r
+ res_set = OUTPUT_VGA;\r
+ }\r
+ if(res_set != sensor->isp_priv_info.curRes)\r
+ sensor_set_isp_output_res(client,res_set);\r
+ sensor->isp_priv_info.curRes = res_set;\r
+ mf->width = set_w;\r
+ mf->height = set_h;\r
+\r
+sensor_s_fmt_end:\r
+ return ret;\r
+}\r
+static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)\r
+{\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ const struct sensor_datafmt *fmt;\r
+ int ret = 0,set_w,set_h;\r
+ int supported_size = sensor->isp_priv_info.outputSize;\r
+ \r
+ fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts,\r
+ ARRAY_SIZE(sensor_colour_fmts));\r
+ if (fmt == NULL) {\r
+ fmt = &sensor->isp_priv_info.fmt;\r
+ mf->code = fmt->code;\r
+ } \r
+ if (mf->height > SENSOR_MAX_HEIGHT)\r
+ mf->height = SENSOR_MAX_HEIGHT;\r
+ else if (mf->height < SENSOR_MIN_HEIGHT)\r
+ mf->height = SENSOR_MIN_HEIGHT;\r
+\r
+ if (mf->width > SENSOR_MAX_WIDTH)\r
+ mf->width = SENSOR_MAX_WIDTH;\r
+ else if (mf->width < SENSOR_MIN_WIDTH)\r
+ mf->width = SENSOR_MIN_WIDTH;\r
+\r
+ set_w = mf->width;\r
+ set_h = mf->height;\r
+\r
+ if (((set_w <= 176) && (set_h <= 144)) && (supported_size & OUTPUT_QCIF))\r
+ {\r
+ set_w = 176;\r
+ set_h = 144;\r
+ }\r
+ else if (((set_w <= 320) && (set_h <= 240)) && (supported_size & OUTPUT_QVGA))\r
+ {\r
+ set_w = 320;\r
+ set_h = 240;\r
+ }\r
+ else if (((set_w <= 352) && (set_h<= 288)) && (supported_size & OUTPUT_CIF))\r
+ {\r
+ set_w = 352;\r
+ set_h = 288;\r
+ }\r
+ else if (((set_w <= 640) && (set_h <= 480)) && (supported_size & OUTPUT_VGA))\r
+ {\r
+ set_w = 640;\r
+ set_h = 480;\r
+ }\r
+ else if (((set_w <= 800) && (set_h <= 600)) && (supported_size & OUTPUT_SVGA))\r
+ {\r
+ set_w = 800;\r
+ set_h = 600;\r
+ }\r
+ else if (((set_w <= 1024) && (set_h <= 768)) && (supported_size & OUTPUT_XGA))\r
+ {\r
+ set_w = 1024;\r
+ set_h = 768;\r
+ }\r
+ else if (((set_w <= 1280) && (set_h <= 720)) && (supported_size & OUTPUT_720P))\r
+ {\r
+ set_w = 1280;\r
+ set_h = 720;\r
+ }\r
+ else if (((set_w <= 1280) && (set_h <= 1024)) && (supported_size & OUTPUT_XGA))\r
+ {\r
+ set_w = 1280;\r
+ set_h = 1024;\r
+ }\r
+ else if (((set_w <= 1600) && (set_h <= 1200)) && (supported_size & OUTPUT_UXGA))\r
+ {\r
+ set_w = 1600;\r
+ set_h = 1200;\r
+ }\r
+ else if (((set_w <= 1920) && (set_h <= 1080)) && (supported_size & OUTPUT_1080P))\r
+ {\r
+ set_w = 1920;\r
+ set_h = 1080;\r
+ }\r
+ else if (((set_w <= 2048) && (set_h <= 1536)) && (supported_size & OUTPUT_QXGA))\r
+ {\r
+ set_w = 2048;\r
+ set_h = 1536;\r
+ }\r
+ else if (((set_w <= 2592) && (set_h <= 1944)) && (supported_size & OUTPUT_QSXGA))\r
+ {\r
+ set_w = 2592;\r
+ set_h = 1944;\r
+ }\r
+ else\r
+ {\r
+ set_w = SENSOR_INIT_WIDTH;\r
+ set_h = SENSOR_INIT_HEIGHT;\r
+ }\r
+\r
+\r
+ mf->width = set_w;\r
+ mf->height = set_h;\r
+ mf->colorspace = fmt->colorspace;\r
+ \r
+ return ret;\r
+\r
+}\r
+\r
+static int sensor_enum_fmt(struct v4l2_subdev *sd, unsigned int index,\r
+ enum v4l2_mbus_pixelcode *code)\r
+{\r
+ if (index >= ARRAY_SIZE(sensor_colour_fmts))\r
+ return -EINVAL;\r
+\r
+ *code = sensor_colour_fmts[index].code;\r
+ return 0;\r
+\r
+}\r
+static int sensor_s_stream(struct v4l2_subdev *sd, int enable){\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+ if(enable == 0){\r
+ // sensor_set_face_detect(client,0);\r
+ // sensor_af_workqueue_set(icd,0,0,true);\r
+ }else{\r
+ //sensor_set_face_detect(client,1);\r
+ }\r
+ return 0;\r
+}\r
+static int sensor_g_face_area(struct v4l2_subdev *sd, void* face_data){\r
+ struct i2c_client *client = v4l2_get_subdevdata(sd);\r
+ u8 lx_rx = 0,tx_dy = 0;\r
+ isp_i2c_read(client,0x2c,&lx_rx,0);\r
+ isp_i2c_read(client,0x2d,&tx_dy,0);\r
+ // printk("lx_rx = %x, ty_dy = %x\n",lx_rx,tx_dy);\r
+ *(u16 *)face_data = ((u16)lx_rx << 8 ) | tx_dy;\r
+\r
+}\r
+static struct v4l2_subdev_core_ops isp_subdev_core_ops = {\r
+ .init = sensor_init,\r
+ .g_ctrl = sensor_g_control,\r
+ .s_ctrl = sensor_s_control,\r
+ .g_ext_ctrls = sensor_g_ext_controls,\r
+ .s_ext_ctrls = sensor_s_ext_controls,\r
+// .g_chip_ident = sensor_g_chip_ident,\r
+ .ioctl = sensor_ioctl,\r
+};\r
+static struct v4l2_subdev_video_ops isp_subdev_video_ops = {\r
+ .s_mbus_fmt = sensor_s_fmt,\r
+ .g_mbus_fmt = sensor_g_fmt,\r
+ .try_mbus_fmt = sensor_try_fmt,\r
+ .enum_mbus_fmt = sensor_enum_fmt,\r
+ .s_stream = sensor_s_stream,\r
+ //.g_face_area = sensor_g_face_area,\r
+};\r
+\r
+static struct v4l2_subdev_ops sensor_subdev_ops = {\r
+ .core = &isp_subdev_core_ops,\r
+ .video = &isp_subdev_video_ops,\r
+};\r
+static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg)\r
+{\r
+ return 0;\r
+}\r
+static int sensor_resume(struct soc_camera_device *icd)\r
+{\r
+ return 0;\r
+\r
+}\r
+static int sensor_set_bus_param(struct soc_camera_device *icd,\r
+ unsigned long flags)\r
+{\r
+\r
+ return 0;\r
+}\r
+\r
+static unsigned long sensor_query_bus_param(struct soc_camera_device *icd)\r
+{\r
+ struct soc_camera_link *icl = to_soc_camera_link(icd);\r
+ unsigned long flags = SENSOR_BUS_PARAM;\r
+\r
+ return soc_camera_apply_sensor_flags(icl, flags);\r
+}\r
+static struct soc_camera_ops sensor_ops =\r
+{\r
+ .suspend = sensor_suspend,\r
+ .resume = sensor_resume,\r
+ .set_bus_param = sensor_set_bus_param,\r
+ .query_bus_param = sensor_query_bus_param,\r
+ .controls = sensor_controls,\r
+ .menus = sensor_menus,\r
+ .num_controls = ARRAY_SIZE(sensor_controls),\r
+ .num_menus = ARRAY_SIZE(sensor_menus),\r
+};\r
+ \r
+\r
+/* sensor register read */\r
+static int isp_i2c_read(struct i2c_client *client, u8 reg, u8 *val,u16 ext_addr)\r
+{\r
+ int err = 0,cnt;\r
+ u8 buf[1];\r
+ struct i2c_msg msg[2];\r
+\r
+ buf[0] = reg;\r
+\r
+ msg[0].addr = (ext_addr == 0)? client->addr:ext_addr;\r
+ msg[0].flags = client->flags;\r
+ msg[0].buf = buf;\r
+ msg[0].len = sizeof(buf);\r
+ msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */\r
+ msg[0].read_type = 0; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */\r
+\r
+ cnt = 50;\r
+ err = -EAGAIN;\r
+ while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */\r
+ err = i2c_transfer(client->adapter, &msg[0], 1);\r
+\r
+ if (err >= 0) {\r
+ break;\r
+ } else {\r
+ //SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val);\r
+ udelay(10);\r
+ }\r
+ }\r
+ if(cnt <=0 ){\r
+ SENSOR_TR("write i2c addr erro!\n");\r
+ return err;\r
+ }\r
+\r
+ msg[1].addr = (ext_addr == 0)? client->addr:ext_addr;\r
+ msg[1].flags = client->flags|I2C_M_RD;\r
+ msg[1].buf = buf;\r
+ msg[1].len = 1;\r
+ msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */\r
+ msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */\r
+\r
+ cnt = 50;\r
+ err = -EAGAIN;\r
+ while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */\r
+ err = i2c_transfer(client->adapter, &msg[1], 1);\r
+\r
+ if (err >= 0) {\r
+ *val = buf[0];\r
+ return 0;\r
+ } else {\r
+ SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val);\r
+ udelay(10);\r
+ }\r
+ }\r
+\r
+ return err;\r
+}\r
+\r
+u8 i2cWaitIdle(struct i2c_client *client,u8 timeOut) \r
+{ \r
+ u8 ret; \r
+ u8 dat = 0; \r
+ /* read I2C_IDLE_IDX register until the value I2C_IDLE */ \r
+ while(timeOut) \r
+ { \r
+ ret = isp_i2c_read(client, I2C_STATUS_REG2, &dat,0); \r
+ if ((ret >= 0) && ((dat&0x01) == I2C_IDLE)) \r
+ break; \r
+ udelay(100); \r
+ timeOut--; \r
+ } \r
+ if(!timeOut){ \r
+ //SENSOR_TR("wait i2c idle erro!!\n"); \r
+ return -1;\r
+ } \r
+ return 0; \r
+} \r
+\r
+static int isp_write_regs(struct i2c_client *client, u8 *reg_info, u16 num,u16 ext_addr,int seq)\r
+{\r
+ int err=0,cnt;\r
+ struct i2c_msg msg;\r
+ u16 windex = 0;\r
+ \r
+ switch(seq){\r
+ case 0 :\r
+ {\r
+ msg.len = num; \r
+ msg.addr = (ext_addr == 0)? client->addr:ext_addr; \r
+ msg.flags = client->flags; \r
+ msg.buf = reg_info; \r
+ msg.scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ \r
+ msg.read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ \r
+\r
+ \r
+ cnt= 10; \r
+ err = -EAGAIN;\r
+ \r
+ while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ \r
+ err = i2c_transfer(client->adapter, &msg, 1); \r
+ if (err >= 0) { \r
+ return 0; \r
+ } else { \r
+ SENSOR_TR("\n %s write reg failed, try to write again!\n", SENSOR_NAME_STRING()); \r
+ mdelay(5); \r
+ } \r
+ }\r
+ break;\r
+ }\r
+ case 1 :\r
+ {\r
+ #define TRPERTIME (2)\r
+ int remain = 0;\r
+ msg.len = TRPERTIME; \r
+ msg.addr = (ext_addr == 0)? client->addr:ext_addr; \r
+ msg.flags = client->flags; \r
+ msg.scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ \r
+ msg.read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ \r
+ \r
+ err = -EAGAIN;\r
+ remain = num % TRPERTIME;\r
+ while(windex < num){\r
+ cnt= 10; \r
+ msg.buf = reg_info+windex;\r
+ err = -EAGAIN;\r
+ while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ \r
+ err = i2c_transfer(client->adapter, &msg, 1); \r
+ if (err >= 0) { \r
+ break; \r
+ } else { \r
+ SENSOR_TR("\n %s write reg failed, try to write again ,index = %d!\n", SENSOR_NAME_STRING(),windex); \r
+ udelay(10); \r
+ } \r
+ }\r
+ if(cnt <= 0){\r
+ SENSOR_TR("\n %s write reg failed ,index = %d!\n", SENSOR_NAME_STRING(),windex);\r
+ break;\r
+ }\r
+ windex+= TRPERTIME;\r
+ if((windex >= num) && (remain != 0)){\r
+ windex = num - remain;\r
+ remain = 0;\r
+ }\r
+ }\r
+ if(err >= 0){\r
+ err = 0;\r
+ if(num % TRPERTIME){\r
+ SENSOR_TR("\n %s isp_write_regs sucess ,index = %d, val = %x!!\n",SENSOR_NAME_STRING(),(windex - (TRPERTIME - num % TRPERTIME) -1),*((u8*)(reg_info+(windex - (TRPERTIME - num % TRPERTIME) -1))));\r
+ }\r
+ else{\r
+ SENSOR_TR("\n %s isp_write_regs sucess ,index = %d, val = %x!!\n",SENSOR_NAME_STRING(),windex - 1,*((u8*)(reg_info+windex - 1)));\r
+ }\r
+ }\r
+ \r
+ break;\r
+ }\r
+ default:\r
+ SENSOR_TR("\n %s isp_write_regs erro\n",SENSOR_NAME_STRING());\r
+ }\r
+ \r
+ return err;\r
+\r
+}\r
+\r
+static u8 sendI2cCmd(struct i2c_client *client,u8 cmd, u8 dat) \r
+{ \r
+ u8 buf[2];\r
+ buf[0] = cmd & 0xFF;\r
+ buf[1] = dat;\r
+ if (i2cWaitIdle(client,100) < 0){ \r
+ SENSOR_TR("%s:%d,send i2c command erro!",__func__,__LINE__);\r
+ return -1;\r
+ }\r
+ if (isp_write_regs(client,buf,2,0,0)<0) \r
+ { \r
+ SENSOR_TR("%s:%d,send i2c command erro!",__func__,__LINE__);\r
+ return -1; \r
+ } \r
+ //check the write\r
+ #if WRITE_READ_CHECK\r
+ if(cmd != 0xE){// no need to check if 0x0e\r
+ buf[1] = 0xff;\r
+ isp_i2c_read(client,cmd,&buf[1],0);\r
+ if(buf[1]!=dat){\r
+ SENSOR_TR("%s:%d,send i2c command check erro,reg %x:(%x:%x)\n!",__func__,__LINE__,cmd,buf[1],dat);\r
+ }\r
+ }\r
+ #endif\r
+ return 0; \r
+} \r
+\r
+static int flash_program_mode(struct i2c_client *client,bool enable){\r
+ u8 ss_array[2] = {0x5b,enable};\r
+ u8 mem_choose[2] = {0x80,0x2}; // 0x2 ,flash ;0x0 sdram\r
+ if(enable == true){\r
+ //select flash mem\r
+ if(isp_write_regs(client,(u8*)mem_choose,sizeof(mem_choose),0,0)){\r
+ SENSOR_TR("%s:%d,enter_program_mode %d erro!",__func__,__LINE__,enable);\r
+ return -1;\r
+ }\r
+ //enter pro mode\r
+ if(isp_write_regs(client,(u8*)ss_array,sizeof(ss_array),0,0)){\r
+ SENSOR_TR("%s:%d,enter_program_mode %d erro!",__func__,__LINE__,enable);\r
+ return -1;\r
+ }\r
+ mdelay(10);\r
+ }else{\r
+ //exit promode\r
+ mem_choose[1] = 0x0; \r
+ if(isp_write_regs(client,(u8*)ss_array,sizeof(ss_array),0,0)){\r
+ SENSOR_TR("%s:%d,enter_program_mode %d erro!",__func__,__LINE__,enable);\r
+ return -1;\r
+ }\r
+ //select sdram mem\r
+ mdelay(10);\r
+ if(isp_write_regs(client,(u8*)mem_choose,sizeof(mem_choose),0,0)){\r
+ SENSOR_TR("%s:%d,enter_program_mode %d erro!",__func__,__LINE__,enable);\r
+ return -1;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+static int flash_mem_erase(struct i2c_client *client,u8 sector){\r
+ //default is chip erase.\r
+ u8 ss_array[3] = {0x00,sector,0x02};\r
+\r
+ if(sector == 0xFF){\r
+ if(isp_write_regs(client,(u8*)ss_array,sizeof(ss_array),DEV_ID_MV9335_I2CSLAVE_FLASH_PRO,0)){\r
+ SENSOR_TR("%s:%d,chip_erase erro!",__func__,__LINE__);\r
+ return -1;\r
+ }\r
+ //delay 120ms\r
+ mdelay(120);\r
+ }else{\r
+ ss_array[2] = 0x05;\r
+ if(isp_write_regs(client,(u8*)ss_array,sizeof(ss_array),DEV_ID_MV9335_I2CSLAVE_FLASH_PRO,0)){\r
+ SENSOR_TR("%s:%d,sector_erase erro\n!",__func__,__LINE__);\r
+ return -1;\r
+ }\r
+ mdelay(120);\r
+ }\r
+ \r
+ return 0;\r
+}\r
+static int flash_write_read_addr(struct i2c_client *client,u16 addr,u8 commd){\r
+ //commd :0x50 write, 0x00 read\r
+ u8 lsb = get_lsb(addr);\r
+ u8 msb = get_msb(addr);\r
+ u8 ss_array[3] = {lsb,msb,commd};\r
+ if(isp_write_regs(client,(u8*)ss_array,sizeof(ss_array),DEV_ID_MV9335_I2CSLAVE_FLASH_PRO,0)){\r
+ SENSOR_TR("%s:%d,flash_write_addr erro!",__func__,__LINE__);\r
+ return -1;\r
+ }\r
+ return 0;\r
+}\r
+static int flash_write_data(struct i2c_client *client){\r
+ int ret = 0;\r
+ const struct firmware *fw = NULL;\r
+ ret = request_firmware(&fw, fw_name, &client->dev);\r
+ if(ret){\r
+ SENSOR_TR("%s:%d,request_firmware erro+++++++++++++!\n",__func__,__LINE__);\r
+ ret = -1;\r
+ goto free_fw_buffer;\r
+ }\r
+ SENSOR_TR("%s:%d,request_firmware sucess,val = %x!\n",__func__,__LINE__,*((u8*)fw->data+fw->size-1));\r
+ if(isp_write_regs(client,(u8*)fw->data,fw->size,DEV_ID_MV9335_I2CSLAVE_FLASH_PRO,1)){\r
+ SENSOR_TR("%s:%d,flash_write_data erro,size = %d!\n",__func__,__LINE__,fw->size);\r
+ ret = -1;\r
+ goto free_fw_buffer;\r
+ }\r
+ #if FLASH_WRITE_CHECK // read all datas back to check\r
+ {\r
+ flash_write_read_addr(client,0x00,0x00);\r
+ u8 rd_data = 0;\r
+ u32 i = 0;\r
+ for(;i<fw->size;i++){\r
+ flash_read_data(client,&rd_data,1);\r
+ if(rd_data!= *((u8*)(fw->data+i)))\r
+ {\r
+ printk("0x%x, ori = 0x%x, rb = 0x%x\n",i,*((u8*)(fw->data+i)),rd_data);\r
+ break;\r
+ }\r
+ rd_data = 0;\r
+ udelay(200);\r
+ }\r
+ }\r
+ #endif\r
+\r
+free_fw_buffer:\r
+ if(fw)\r
+ release_firmware(fw);\r
+ return ret;\r
+}\r
+static int flash_read_data(struct i2c_client *client,u8* rd_data,int readcount){\r
+ int err = 0,cnt,i = 0;\r
+ //u8 buf[2];\r
+ u8 buf;\r
+ struct i2c_msg msg;\r
+\r
+ msg.addr = DEV_ID_MV9335_I2CSLAVE_FLASH_PRO;\r
+ msg.flags = client->flags|I2C_M_RD;\r
+ msg.buf = &buf;\r
+ msg.len = 1;\r
+ msg.scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */\r
+ msg.read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */\r
+ for(i = 0;i < readcount;i++){\r
+ cnt = 3;\r
+ err = -EAGAIN;\r
+ while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */\r
+ err = i2c_transfer(client->adapter, &msg, 1);\r
+\r
+ if (err >= 0) {\r
+ rd_data[i] = buf;\r
+ break;\r
+ } else {\r
+ //SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val);\r
+ udelay(10);\r
+ }\r
+ }\r
+ if(cnt <=0 ){\r
+ SENSOR_TR("flash read erro,i = %d ,readcount = %d!\n",i,readcount);\r
+ return err;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+static int isp_load_fw_prepare(struct i2c_client *client){\r
+ //pll start cmd\r
+ sendI2cCmd(client, 0x80, 0x0);\r
+// msleep(5);\r
+ //flash memory devider\r
+ sendI2cCmd(client, 0xD0, 0x30); \r
+// msleep(5);\r
+ //pll 1 Conf.command(24MHZ->192MHZ)\r
+ sendI2cCmd(client, 0x40, 0x01); \r
+ sendI2cCmd(client, 0x41, 0x40); \r
+ sendI2cCmd(client, 0x42, 0x05); \r
+ sendI2cCmd(client, 0x49, 0x03); \r
+ sendI2cCmd(client, 0x80, 0x02); \r
+// sendI2cCmd(client, 0x4A, 0x01); \r
+ return 0;\r
+}\r
+static int isp_init_cmds(struct i2c_client *client){\r
+ //pll start cmd\r
+ sendI2cCmd(client, 0x80, 0x0);\r
+// msleep(5);\r
+ //flash memory devider\r
+ sendI2cCmd(client, 0xD0, 0x30); \r
+// msleep(5);\r
+ //pll 1 Conf.command(24MHZ->192MHZ)\r
+ sendI2cCmd(client, 0x40, 0x01); \r
+ sendI2cCmd(client, 0x41, 0x40); \r
+ sendI2cCmd(client, 0x42, 0x05); \r
+ sendI2cCmd(client, 0x49, 0x03);\r
+ isp_reg_value_check(client,0x36,0x03);\r
+ sendI2cCmd(client, 0x80, 0x03); \r
+// sendI2cCmd(client, 0x4A, 0x01); \r
+ // msleep(100);\r
+ return 0;\r
+}\r
+static int isp_init_check(struct i2c_client *client){\r
+ if(!isp_reg_value_check(client,0x00,PRODUCT_ID_VALUE_REG0)){\r
+ SENSOR_TR("%s:%d,check erro!\n", __func__,__LINE__);\r
+ return -1;\r
+ }\r
+ if(!isp_reg_value_check(client,0x01,PRODUCT_VERSION_VALUE_REG1)){\r
+ SENSOR_TR("%s:%d,check erro!\n", __func__,__LINE__);\r
+ return -1;\r
+ }\r
+\r
+ isp_reg_value_check(client,0x02,FIRMWARE_MAJOR_VERSION_VALUE_REG2);\r
+ isp_reg_value_check(client,0x03,FIRMWARE_MINOR_VERSION_VALUE_REG3);\r
+ isp_reg_value_check(client,0x05,I2C_CHECKE_VALUE_REG5);\r
+ // isp_reg_value_check(client,0x06,CHECKE_VALUE_REG6);\r
+ //now do not check the two reg.\r
+ sendI2cCmd(client, 0x1F, 0x01); \r
+ isp_reg_value_check(client,0x90,CHECKE_VALUE_REG0X90);\r
+ isp_reg_value_check(client,0x91,CHECKE_VALUE_REG0X91);\r
+ SENSOR_TR("%s:%d,check succsess!\n", __func__,__LINE__);\r
+ //while(1);\r
+ return 0;\r
+}\r
+static int flash_down_load_firmware(struct i2c_client *client,u16 addr){\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+ struct soc_camera_link *icl = to_soc_camera_link(icd);\r
+ isp_load_fw_prepare(client);\r
+ // 1.enter pro mode\r
+ if(flash_program_mode(client,true)){\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit;\r
+ }\r
+ // 2. flash erase , chip erase or sector erase\r
+ #if FLASH_ERASE_BY_SECTOR\r
+ //for test\r
+ {\r
+ int sect,sectCnt,i;\r
+\r
+ sect = 0;\r
+ sectCnt = 15;\r
+ for(i = 0;i < sectCnt;i++)\r
+ {\r
+ sect = (i << 4) & 0xF0;\r
+ if(flash_mem_erase(client,sect/*+i*/))\r
+ {\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit_promode; \r
+ }\r
+ }\r
+ }\r
+ #elif FLASH_ERASE_ALL\r
+ if(flash_mem_erase(client,0xFF))\r
+ {\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit_promode;\r
+ }\r
+ #endif\r
+\r
+ // 3. write addr\r
+ if(flash_write_read_addr(client,addr,0x50)){\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit_promode;\r
+ }\r
+\r
+ // 4. write data ,sequence write\r
+ if(flash_write_data(client)){\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit_promode;\r
+ }\r
+ // 5. quit pro mode\r
+ if(flash_program_mode(client,false)){\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit;\r
+ }\r
+ //reset , reset pin low ,then high\r
+ if (icl->reset)\r
+ icl->reset(icd->pdev);\r
+ mdelay(10);\r
+ isp_init_cmds(client);\r
+ isp_init_check(client);\r
+ return 0;\r
+ erro_quit_promode:\r
+ flash_program_mode(client,false);\r
+ erro_quit:\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ return -1;\r
+}\r
+static int flash_read_firmware_data(struct i2c_client *client,u16 addr,u8* rd_data,int readcount){\r
+ // 1.enter pro mode\r
+ if(flash_program_mode(client,true)){\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit;\r
+ }\r
+ // 2. write addr\r
+ if(flash_write_read_addr(client,addr,0x00)){\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit_promode;\r
+ }\r
+ // 3. read data\r
+ if(flash_read_data(client,rd_data,readcount)){\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit_promode;\r
+ }\r
+ // 4. quit pro mode\r
+ if(flash_program_mode(client,false)){\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ goto erro_quit;\r
+ }\r
+ return 0;\r
+ erro_quit_promode:\r
+ flash_program_mode(client,false);\r
+ erro_quit:\r
+ printk("%s:%d erro \n",__func__,__LINE__);\r
+ return -1;\r
+}\r
+//power control\r
+//power_up sequence : reset low,no mclk; power up ; supply mclk ; reset high\r
+//power_off sequence: reset low ,mclk off , power off\r
+//power down sequence :as the power up ,then cut off mclk;\r
+//wake up from power down: supply mclk ;reset asserted twice(low - high -low -high)\r
+//soc camera has done the power control\r
+/* Interface active, can use i2c. If it fails, it can indeed mean, that\r
+ * this wasn't our capture interface, so, we wait for the right one */\r
+static int sensor_video_probe(struct soc_camera_device *icd,\r
+ struct i2c_client *client)\r
+{\r
+\r
+ /* We must have a parent by now. And it cannot be a wrong one.\r
+ * So this entire test is completely redundant. */\r
+ if (!icd->dev.parent ||\r
+ to_soc_camera_host(icd->dev.parent)->nr != icd->iface)\r
+ return -ENODEV;\r
+ //get the pid of sensor\r
+ //pll start cmd\r
+\r
+ //ISP initialization check\r
+#if 1\r
+ flash_down_load_firmware(client,0x00);\r
+ isp_init_cmds(client);\r
+ if(!isp_init_check(client)){\r
+ SENSOR_TR("%s:%d,check erro!\n", __func__,__LINE__);\r
+ return -1;\r
+ }\r
+\r
+#endif\r
+ return 0;\r
+\r
+//sensor_video_probe_err:\r
+ // return ret;\r
+}\r
+static int sensor_probe(struct i2c_client *client,\r
+ const struct i2c_device_id *did)\r
+{\r
+ struct isp_dev *sensor;\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);\r
+ struct soc_camera_link *icl;\r
+ int ret;\r
+\r
+ SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__);\r
+ if (!icd) {\r
+ dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING());\r
+ return -EINVAL;\r
+ }\r
+\r
+ icl = to_soc_camera_link(icd);\r
+ if (!icl) {\r
+ dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING());\r
+ return -EINVAL;\r
+ }\r
+\r
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {\r
+ dev_warn(&adapter->dev,\r
+ "I2C-Adapter doesn't support I2C_FUNC_I2C\n");\r
+ return -EIO;\r
+ }\r
+\r
+ sensor = kzalloc(sizeof(struct isp_dev), GFP_KERNEL);\r
+ if (!sensor)\r
+ return -ENOMEM;\r
+\r
+ v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops);\r
+\r
+ /* Second stage probe - when a capture adapter is there */\r
+ icd->ops = &sensor_ops;\r
+ sensor->isp_priv_info.fmt = sensor_colour_fmts[0];\r
+\r
+\r
+ ret = sensor_video_probe(icd, client);\r
+ if (ret < 0) {\r
+ icd->ops = NULL;\r
+ i2c_set_clientdata(client, NULL);\r
+ kfree(sensor);\r
+ sensor = NULL;\r
+ } else {\r
+ #if CONFIG_SENSOR_Focus\r
+ sensor->sensor_wq = create_workqueue(SENSOR_NAME_STRING(_af_workqueue));\r
+ if (sensor->sensor_wq == NULL)\r
+ SENSOR_TR("%s create fail!", SENSOR_NAME_STRING(_af_workqueue));\r
+ mutex_init(&sensor->wq_lock);\r
+ #endif\r
+ mutex_init(&sensor->isp_priv_info.access_data_lock);\r
+\r
+ }\r
+\r
+ SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret);\r
+ return ret;\r
+}\r
+static int sensor_remove(struct i2c_client *client)\r
+{\r
+ struct isp_dev *sensor = to_sensor(client);\r
+ struct soc_camera_device *icd = client->dev.platform_data;\r
+\r
+ icd->ops = NULL;\r
+ i2c_set_clientdata(client, NULL);\r
+ client->driver = NULL;\r
+ kfree(sensor);\r
+ sensor = NULL;\r
+\r
+ return 0;\r
+}\r
+static const struct i2c_device_id sensor_id[] = {\r
+ {SENSOR_NAME_STRING(), 0 },\r
+ { }\r
+};\r
+MODULE_DEVICE_TABLE(i2c, sensor_id);\r
+\r
+static struct i2c_driver sensor_i2c_driver = {\r
+ .driver = {\r
+ .name = SENSOR_NAME_STRING(),\r
+ },\r
+ .probe = sensor_probe,\r
+ .remove = sensor_remove,\r
+ .id_table = sensor_id,\r
+};\r
+\r
+static int __init sensor_mod_init(void)\r
+{\r
+ SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING());\r
+ return i2c_add_driver(&sensor_i2c_driver);\r
+}\r
+\r
+static void __exit sensor_mod_exit(void)\r
+{\r
+ i2c_del_driver(&sensor_i2c_driver);\r
+}\r
+\r
+device_initcall_sync(sensor_mod_init);\r
+module_exit(sensor_mod_exit);\r
+\r
+MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver));\r
+MODULE_AUTHOR("ddl <kernel@rock-chips>");\r
+MODULE_LICENSE("GPL");\r