/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * */ #include #include #include #include #include #include #include #include "ov9665.h" /* OV9665 Registers and their values */ /* Sensor Core Registers */ #define REG_OV9665_MODEL_ID_H 0x0A #define REG_OV9665_MODEL_ID_L 0x0B #define OV9665_MODEL_ID 0x9663 /* SOC Registers Page 1 */ #define REG_OV9665_SENSOR_RESET 0x301A #define REG_OV9665_STANDBY_CONTROL 0x3202 #define REG_OV9665_MCU_BOOT 0x3386 struct ov9665_work { struct work_struct work; }; static struct ov9665_work *ov9665_sensorw; static struct i2c_client *ov9665_client; struct ov9665_ctrl { const struct msm_camera_sensor_info *sensordata; }; static struct ov9665_ctrl *ov9665_ctrl; static int op_mode; static DECLARE_WAIT_QUEUE_HEAD(ov9665_wait_queue); DECLARE_MUTEX(ov9665_sem); static int sensor_probe_node = 0; #define MAX_I2C_RETRIES 20 static int i2c_transfer_retry(struct i2c_adapter *adap, struct i2c_msg *msgs, int len) { int i2c_retry = 0; int ns; /* number sent */ while (i2c_retry++ < MAX_I2C_RETRIES) { ns = i2c_transfer(adap, msgs, len); if (ns == len) break; pr_err("%s: try %d/%d: i2c_transfer sent: %d, len %d\n", __func__, i2c_retry, MAX_I2C_RETRIES, ns, len); msleep(10); } return ns == len ? 0 : -EIO; } static int ov9665_i2c_txdata(unsigned short saddr, unsigned char *txdata, int length) { struct i2c_msg msg[] = { { .addr = saddr, .flags = 0, .len = length, .buf = txdata, }, }; if (i2c_transfer_retry(ov9665_client->adapter, msg, 1) < 0) { pr_info("ov9665_i2c_txdata failed\n"); return -EIO; } return 0; } static int ov9665_i2c_write(unsigned short saddr, unsigned char waddr, unsigned char wdata, enum ov9665_width width) { int rc = -EIO; unsigned char buf[4]; memset(buf, 0, sizeof(buf)); switch (width) { case WORD_LEN:{ buf[0] = (waddr & 0xFF00) >> 8; buf[1] = (waddr & 0x00FF); buf[2] = (wdata & 0xFF00) >> 8; buf[3] = (wdata & 0x00FF); rc = ov9665_i2c_txdata(saddr, buf, 4); } break; case BYTE_LEN:{ buf[0] = waddr; buf[1] = wdata; rc = ov9665_i2c_txdata(saddr, buf, 2); } break; default: break; } if (rc < 0) pr_info("i2c_write failed, addr = 0x%x, val = 0x%x!\n", waddr, wdata); return rc; } static int ov9665_i2c_write_table(struct ov9665_i2c_reg_conf const *reg_conf_tbl, int num_of_items_in_table) { int i; int rc = -EIO; for (i = 0; i < num_of_items_in_table; i++) { rc = ov9665_i2c_write(ov9665_client->addr, reg_conf_tbl->waddr, reg_conf_tbl->wdata, reg_conf_tbl->width); if (rc < 0) break; if (reg_conf_tbl->mdelay_time != 0) mdelay(reg_conf_tbl->mdelay_time); reg_conf_tbl++; } return rc; } static int ov9665_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, int length) { struct i2c_msg msgs[] = { { .addr = saddr, .flags = 0, .len = 1, .buf = rxdata, }, { .addr = saddr, .flags = I2C_M_RD, .len = length, .buf = rxdata, }, }; if (i2c_transfer_retry(ov9665_client->adapter, msgs, 2) < 0) { pr_info("ov9665_i2c_rxdata failed!\n"); return -EIO; } return 0; } static int ov9665_i2c_read(unsigned short saddr, unsigned short raddr, unsigned char *rdata) { int rc = 0; unsigned char buf[1]; if (!rdata) return -EIO; memset(buf, 0, sizeof(buf)); buf[0] = raddr; rc = ov9665_i2c_rxdata(saddr, buf,1); if (rc < 0) return rc; *rdata = buf[0]; if (rc < 0) pr_info("ov9665_i2c_read failed!\n"); return rc; } static int ov9665_i2c_write_mask( unsigned char addr,unsigned char Data, unsigned char Mask) { int rc = 0; unsigned char temp; rc = ov9665_i2c_read(ov9665_client->addr, addr, &temp); if(rc < 0){ pr_err("ov9665 error : read i2c error\n"); return rc; } temp = (temp&(~Mask))|Data; rc = ov9665_i2c_write(ov9665_client->addr, addr, temp, BYTE_LEN); if(rc < 0){ pr_err("ov9665 error : write i2c error\n"); return rc; } return rc; } static int ov9665_pwd(const struct msm_camera_sensor_info *info){ int rc=0; rc = gpio_request(info->sensor_pwd, "ov9665"); if (!rc) gpio_direction_output(info->sensor_pwd, 0); else pr_err("GPIO(%d) request faile",info->sensor_pwd); gpio_free(info->sensor_pwd); return rc; } static int ov9665_reset(const struct msm_camera_sensor_info *dev) { int rc = 0; rc = gpio_request(dev->sensor_reset, "ov9665"); if (!rc) rc = gpio_direction_output(dev->sensor_reset, 1); else pr_err("GPIO(%d) request faile",dev->sensor_reset); gpio_free(dev->sensor_reset); return rc; } static int ov9665_reg_init(void) { int rc = 0; rc = ov9665_i2c_write_table(&ov9665_regs.register_init[0], ov9665_regs.register_init_size); return rc; } static int ov9665_init_done(const struct msm_camera_sensor_info *info) { int rc = 0; rc = gpio_request(info->sensor_pwd, "ov9665"); if (!rc) gpio_direction_output(info->sensor_pwd, 1); else pr_err("GPIO(%d) request faile",info->sensor_pwd); gpio_free(info->sensor_pwd); return rc; } static int ov9665_set_sensor_mode(int mode) { unsigned char shading, gain; switch (mode) { case SENSOR_PREVIEW_MODE: op_mode = SENSOR_PREVIEW_MODE; pr_info("ov9665:sensor set mode: preview\n"); ov9665_i2c_write(ov9665_client->addr, 0x63, 0x00, BYTE_LEN); /*Windowing*/ ov9665_i2c_write(ov9665_client->addr, 0x12, 0x40, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x4d, 0x09, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x17, 0x0c, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x18, 0x5d, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x19, 0x02, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x1a, 0x3f, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x03, 0x83, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x32, 0xad, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x2b, 0x00, BYTE_LEN); /*scaling*/ ov9665_i2c_write(ov9665_client->addr, 0x64, 0xa4, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xab, 0xe7, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xb9, 0x50, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xba, 0x3c, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbb, 0x50, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbc, 0x3c, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x85, 0xe7, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x0d, 0x92, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x0d, 0x90, BYTE_LEN); /*enable 3A*/ ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe7, BYTE_LEN); /*VGA 30fps*/ ov9665_i2c_write(ov9665_client->addr, 0x11, 0x80, BYTE_LEN); //ov9665_i2c_write(ov9665_client->addr, 0x09, 0x01, BYTE_LEN); mdelay(400);/*skip 2 break frame */ break; case SENSOR_SNAPSHOT_MODE: pr_info("ov9665:sensor set mode: snapshot\n"); op_mode = SENSOR_SNAPSHOT_MODE; /*disable 3A*/ ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe0, BYTE_LEN); /*SXGA 7.5fps*/ ov9665_i2c_write(ov9665_client->addr, 0x11, 0x81, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x63, 0x01, BYTE_LEN); /*Windowing*/ ov9665_i2c_write(ov9665_client->addr, 0x12, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x4d, 0x11, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x17, 0x0c, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x18, 0x5d, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x19, 0x01, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x1a, 0x82, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x03, 0x83, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x32, 0x24, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x2b, 0x00, BYTE_LEN); /*scaling*/ ov9665_i2c_write(ov9665_client->addr, 0x64, 0x24, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xab, 0xe7, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xb9, 0xa0, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xba, 0x80, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbb, 0xa0, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbc, 0x80, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x85, 0xe7, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x0d, 0x82, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x0d, 0x80, BYTE_LEN); mdelay(400); /*wait for AE stable*/ break; case SENSOR_GET_EXP: ov9665_i2c_read(ov9665_client->addr, 0x83, &shading); ov9665_i2c_read(ov9665_client->addr, 0x00, &gain); if (gain >= 0x36) //5.5xgain ov9665_i2c_write (ov9665_client->addr, 0x83, 0x06, BYTE_LEN); else if (gain < 0x34) //5x gain ov9665_i2c_write (ov9665_client->addr, 0x83, 0x07, BYTE_LEN); break; default: return -EINVAL; } return 0; } static int ov9665_set_effect(int effect) { if (op_mode == SENSOR_SNAPSHOT_MODE) return 0; switch (effect) { case CAMERA_EFFECT_OFF: #if 1/*color matrix*/ ov9665_i2c_write(ov9665_client->addr, 0xbd, 0x04, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbe, 0x1f, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbf, 0x03, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc0, 0x0d, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc1, 0x24, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc2, 0x30, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc3, 0x34, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc4, 0x34, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc5, 0x01, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc6, 0x9c, BYTE_LEN); #endif #if 0/*control by SDE*/ ov9665_i2c_write(ov9665_client->addr, 0xc7, 0x80, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc8, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xcd, 0x80, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xce, 0x80, BYTE_LEN); #endif break; case CAMERA_EFFECT_MONO: #if 1/*color matrix*/ ov9665_i2c_write(ov9665_client->addr, 0xbd, 0x09, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbe, 0x12, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbf, 0x03, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc0, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc1, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc2, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc3, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc4, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc5, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc6, 0x00, BYTE_LEN); #endif #if 0/*control by SDE*/ ov9665_i2c_write_mask(0xc7, 0x10, 0x10); ov9665_i2c_write_mask(0xc8, 0x18, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xCD, 0x80, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xCE, 0x80, BYTE_LEN); #endif break; case CAMERA_EFFECT_NEGATIVE: #if 0/*control by SDE*/ ov9665_i2c_write_mask(0xc7, 0x10, 0x10); ov9665_i2c_write_mask(0xc8, 0x40, 0x58); /*ov9665_i2c_write(ov9665_client->addr, 0xC7, 0x90, BYTE_LEN);*/ #endif break; case CAMERA_EFFECT_SEPIA: #if 1/*user color matrix*/ ov9665_i2c_write(ov9665_client->addr, 0xbd, 0x09, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbe, 0x09, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xbf, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc0, 0x06, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc1, 0x08, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc2, 0x07, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc3, 0x0a, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc4, 0x04, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc5, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc6, 0x98, BYTE_LEN); #endif #if 0/*control by SDE*/ ov9665_i2c_write(ov9665_client->addr, 0xc7, 0x90, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xc8, 0x18, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xCD, 0x40, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xCE, 0xa0, BYTE_LEN); #endif break; default: return -EINVAL; } return 0; } static int ov9665_set_antibanding(enum antibanding_mode antibanding_value) { if (op_mode == SENSOR_SNAPSHOT_MODE) return 0; switch (antibanding_value) { case CAMERA_ANTI_BANDING_50HZ: ov9665_i2c_write_mask(0x0c, 0x00, 0x02); ov9665_i2c_write_mask(0x0c, 0x04, 0x04); break; case CAMERA_ANTI_BANDING_60HZ: ov9665_i2c_write_mask(0x0c, 0x00, 0x02); ov9665_i2c_write_mask(0x0c, 0x00, 0x04); break; case CAMERA_ANTI_BANDING_AUTO: ov9665_i2c_write_mask(0x0c, 0x02, 0x02); break; } return 0; } static int ov9665_set_brightness(enum brightness_t brightness_value) { if (op_mode == SENSOR_SNAPSHOT_MODE) return 0; ov9665_i2c_write_mask(0xc8, 0x04, 0x04); switch (brightness_value) { case CAMERA_BRIGHTNESS_N4: ov9665_i2c_write_mask(0xc7, 0x18, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x40, BYTE_LEN); break; case CAMERA_BRIGHTNESS_N3: ov9665_i2c_write_mask(0xc7, 0x18, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x30, BYTE_LEN); break; case CAMERA_BRIGHTNESS_N2: ov9665_i2c_write_mask(0xc7, 0x18, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x20, BYTE_LEN); break; case CAMERA_BRIGHTNESS_N1: ov9665_i2c_write_mask(0xc7, 0x18, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x10, BYTE_LEN); break; case CAMERA_BRIGHTNESS_D: ov9665_i2c_write_mask(0xc7, 0x10, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x00, BYTE_LEN); break; case CAMERA_BRIGHTNESS_P1: ov9665_i2c_write_mask(0xc7, 0x10, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x10, BYTE_LEN); break; case CAMERA_BRIGHTNESS_P2: ov9665_i2c_write_mask(0xc7, 0x10, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x20, BYTE_LEN); break; case CAMERA_BRIGHTNESS_P3: ov9665_i2c_write_mask(0xc7, 0x10, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x30, BYTE_LEN); break; case CAMERA_BRIGHTNESS_P4: ov9665_i2c_write_mask(0xc7, 0x10, 0x18); ov9665_i2c_write(ov9665_client->addr, 0xd1, 0x40, BYTE_LEN); break; default: break; } return 0; } static int ov9665_set_wb(enum wb_mode wb_value) { if (op_mode == SENSOR_SNAPSHOT_MODE) return 0; switch (wb_value) { case CAMERA_AWB_AUTO: ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe7, BYTE_LEN); break; case CAMERA_AWB_CLOUDY: ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe5, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x01, 0x40, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x02, 0x68, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x16, 0x46, BYTE_LEN); break; case CAMERA_AWB_INDOOR_HOME: ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe5, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x01, 0x62, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x02, 0x3c, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x16, 0x41, BYTE_LEN); break; case CAMERA_AWB_INDOOR_OFFICE: ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe5, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x01, 0x50, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x02, 0x40, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x16, 0x40, BYTE_LEN); break; case CAMERA_AWB_SUNNY: ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe5, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x01, 0x35, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x02, 0x52, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x16, 0x40, BYTE_LEN); break; default: break; } return 0; } static int ov9665_set_sharpness(enum sharpness_mode sharpness_value) { if (op_mode == SENSOR_SNAPSHOT_MODE) return 0; ov9665_i2c_write_mask(0xab, 0x04, 0x04); switch (sharpness_value) { case CAMERA_SHARPNESS_X0: ov9665_i2c_write(ov9665_client->addr, 0xad, 0x20, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xd9, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xda, 0x00, BYTE_LEN); break; case CAMERA_SHARPNESS_X1: ov9665_i2c_write(ov9665_client->addr, 0xad, 0x22, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xd9, 0x01, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xda, 0x00, BYTE_LEN); break; case CAMERA_SHARPNESS_X2: ov9665_i2c_write(ov9665_client->addr, 0xad, 0x24, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xd9, 0x13, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xda, 0x00, BYTE_LEN); break; case CAMERA_SHARPNESS_X3: ov9665_i2c_write(ov9665_client->addr, 0xad, 0x28, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xd9, 0x26, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xda, 0x22, BYTE_LEN); break; case CAMERA_SHARPNESS_X4: ov9665_i2c_write(ov9665_client->addr, 0xad, 0x2c, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xd9, 0x6a, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xda, 0x66, BYTE_LEN); break; default: break; } return 0; } static int ov9665_set_saturation(enum saturation_mode saturation_value) { if (op_mode == SENSOR_SNAPSHOT_MODE) return 0; switch (saturation_value) { case CAMERA_SATURATION_X0: ov9665_i2c_write_mask(0xc7, 0x10, 0x10); ov9665_i2c_write_mask(0xc8, 0x02, 0x02); ov9665_i2c_write(ov9665_client->addr, 0xcb, 0x00, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xcc, 0x00, BYTE_LEN); break; case CAMERA_SATURATION_X05: ov9665_i2c_write_mask(0xc7, 0x10, 0x10); ov9665_i2c_write_mask(0xc8, 0x02, 0x02); ov9665_i2c_write(ov9665_client->addr, 0xcb, 0x20, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xcc, 0x20, BYTE_LEN); break; case CAMERA_SATURATION_X1: ov9665_i2c_write_mask(0xc7, 0x10, 0x10); ov9665_i2c_write_mask(0xc8, 0x02, 0x02); ov9665_i2c_write(ov9665_client->addr, 0xcb, 0x40, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xcc, 0x40, BYTE_LEN); break; case CAMERA_SATURATION_X15: ov9665_i2c_write_mask(0xc7, 0x10, 0x10); ov9665_i2c_write_mask(0xc8, 0x02, 0x02); ov9665_i2c_write(ov9665_client->addr, 0xcb, 0x60, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xcc, 0x60, BYTE_LEN); break; case CAMERA_SATURATION_X2: ov9665_i2c_write_mask(0xc7, 0x10, 0x10); ov9665_i2c_write_mask(0xc8, 0x02, 0x02); ov9665_i2c_write(ov9665_client->addr, 0xcb, 0x80, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0xcc, 0x80, BYTE_LEN); break; default: break; } return 0; } static int ov9665_set_contrast(enum contrast_mode contrast_value) { if (op_mode == SENSOR_SNAPSHOT_MODE) return 0; ov9665_i2c_write_mask(0xc7, 0x34, 0x34); ov9665_i2c_write_mask(0xc8, 0x04, 0x04); ov9665_i2c_write_mask(0x64, 0x02, 0x02); switch (contrast_value) { case CAMERA_CONTRAST_N2: ov9665_i2c_write(ov9665_client->addr, 0xd0, 0x08, BYTE_LEN); break; case CAMERA_CONTRAST_N1: ov9665_i2c_write(ov9665_client->addr, 0xd0, 0x10, BYTE_LEN); break; case CAMERA_CONTRAST_D: ov9665_i2c_write(ov9665_client->addr, 0xd0, 0x20, BYTE_LEN); break; case CAMERA_CONTRAST_P1: ov9665_i2c_write(ov9665_client->addr, 0xd0, 0x30, BYTE_LEN); break; case CAMERA_CONTRAST_P2: ov9665_i2c_write(ov9665_client->addr, 0xd0, 0x40, BYTE_LEN); break; default: break; } return 0; } static int ov9665_set_front_camera_mode(enum frontcam_t frontcam_value) { if (op_mode == SENSOR_SNAPSHOT_MODE) return 0; switch (frontcam_value) { case CAMERA_MIRROR: /*mirror and flip*/ ov9665_i2c_write(ov9665_client->addr, 0x04, 0xa8, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x33, 0xc8, BYTE_LEN); break; case CAMERA_REVERSE: /*reverse mode*/ ov9665_i2c_write(ov9665_client->addr, 0x04, 0x28, BYTE_LEN); ov9665_i2c_write(ov9665_client->addr, 0x33, 0xc0, BYTE_LEN); break; default: break; } return 0; } static int ov9665_sensor_init(const struct msm_camera_sensor_info *data) { uint8_t model_id_h = 0,model_id_l = 0; uint16_t model_id; int rc = 0; pr_info("ov9665_sensor_init_probe \n"); /* Read the Model ID of the sensor */ rc = ov9665_i2c_read(ov9665_client->addr, REG_OV9665_MODEL_ID_H, &model_id_h); if (rc < 0) goto init_probe_fail; rc = ov9665_i2c_read(ov9665_client->addr, REG_OV9665_MODEL_ID_L, &model_id_l); if (rc < 0) goto init_probe_fail; model_id = (((model_id_h << 8) & 0xFF00) +(model_id_l)); pr_info("ov9665: model_id = 0x%x\n", model_id); /* Check if it matches it with the value in Datasheet */ if (model_id != OV9665_MODEL_ID) { rc = -EINVAL; goto init_probe_fail; } return rc; init_probe_fail: return rc; } int ov9665_sensor_open_init(struct msm_camera_sensor_info *data) { int rc = 0; ov9665_ctrl = kzalloc(sizeof(struct ov9665_ctrl), GFP_KERNEL); if (!ov9665_ctrl) { pr_info("ov9665_init failed!\n"); rc = -ENOMEM; goto init_done; } if (data == NULL) { pr_err("%s sensor data is NULL\n", __func__); return -EINVAL; } ov9665_ctrl->sensordata = data; /*switch PCLK and MCLK to 2nd cam*/ pr_info("ov9665: ov9665_sensor_probe switch clk\n"); if(data->camera_clk_switch != NULL) data->camera_clk_switch(); /* Config power down */ rc = gpio_request(data->sensor_pwd, "ov9665"); if (!rc) gpio_direction_output(data->sensor_pwd, 0); else pr_info("GPIO(%d) request faile",data->sensor_pwd); gpio_free(data->sensor_pwd); mdelay(3); /* Input MCLK = 24MHz */ msm_camio_clk_rate_set(24000000); mdelay(5); msm_camio_camif_pad_reg_reset(); rc = ov9665_i2c_write_table(&ov9665_regs.plltbl[0], ov9665_regs.plltbl_size); /*read ID*/ rc = ov9665_sensor_init(data); if (rc < 0) { pr_info("ov9665_sensor_init failed!\n"); goto init_fail; } /*set initial register*/ rc = ov9665_reg_init(); if (rc < 0) { pr_info("ov9665_sensor_reg_init failed!\n"); goto init_fail; } init_done: return rc; init_fail: if (ov9665_ctrl) { kfree(ov9665_ctrl); ov9665_ctrl = NULL; } return rc; } static int ov9665_init_client(struct i2c_client *client) { /* Initialize the MSM_CAMI2C Chip */ init_waitqueue_head(&ov9665_wait_queue); return 0; } int ov9665_sensor_config(void __user *argp) { struct sensor_cfg_data cfg_data; long rc = 0; if (copy_from_user(&cfg_data, (void *)argp, sizeof(struct sensor_cfg_data))) return -EFAULT; switch (cfg_data.cfgtype) { case CFG_SET_MODE: rc = ov9665_set_sensor_mode(cfg_data.mode); break; case CFG_SET_EFFECT: rc = ov9665_set_effect(cfg_data.cfg.effect); if(rc < 0) return rc; break; case CFG_SET_ANTIBANDING: rc = ov9665_set_antibanding (cfg_data.cfg.antibanding_value); break; case CFG_SET_BRIGHTNESS: rc = ov9665_set_brightness (cfg_data.cfg.brightness_value); break; case CFG_SET_WB: rc = ov9665_set_wb(cfg_data.cfg.wb_value); break; case CFG_SET_SHARPNESS: rc = ov9665_set_sharpness (cfg_data.cfg.sharpness_value); break; case CFG_SET_SATURATION: rc = ov9665_set_saturation (cfg_data.cfg.saturation_value); break; case CFG_SET_CONTRAST: rc = ov9665_set_contrast(cfg_data.cfg.contrast_value); break; case CFG_SET_FRONT_CAMERA_MODE: rc = ov9665_set_front_camera_mode(cfg_data.cfg.frontcam_value); break; default: rc = -EINVAL; break; } return rc; } int ov9665_sensor_release(void) { int rc = 0; down(&ov9665_sem); rc = gpio_request(ov9665_ctrl->sensordata->sensor_pwd, "ov9665"); if (!rc) gpio_direction_output(ov9665_ctrl->sensordata->sensor_pwd, 1); else pr_info("GPIO(%d) request faile", ov9665_ctrl->sensordata->sensor_pwd); gpio_free(ov9665_ctrl->sensordata->sensor_pwd); if (ov9665_ctrl) { kfree(ov9665_ctrl); ov9665_ctrl = NULL; } up(&ov9665_sem); return rc; } static const char *Ov9665Vendor = "OmniVision"; static const char *Ov9665NAME = "ov9665"; static const char *Ov9665Size = "1M"; static uint32_t htcwc_value; static ssize_t sensor_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t ret = 0; sprintf(buf, "%s %s %s\n", Ov9665Vendor, Ov9665NAME, Ov9665Size); ret = strlen(buf) + 1; return ret; } static ssize_t htcwc_get(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t length; length = sprintf(buf, "%d\n", htcwc_value); return length; } static ssize_t htcwc_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { uint32_t tmp = 0; tmp = buf[0] - 0x30; /* only get the first char */ #if 0 if (strcmp(current->comm,"com.android.camera")!=0){ pr_info("No permission : not camera ap\n"); return -EINVAL; } #endif htcwc_value = tmp; //pr_info("current_comm = %s\n", current->comm); pr_info("htcwc_value = %d\n", htcwc_value); return count; } static ssize_t sensor_read_node(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t length; length = sprintf(buf, "%d\n", sensor_probe_node); return length; } static DEVICE_ATTR(sensor, 0444, sensor_vendor_show, NULL); static DEVICE_ATTR(htcwc, 0777, htcwc_get, htcwc_set); static DEVICE_ATTR(node, 0444, sensor_read_node, NULL); static struct kobject *android_ov9665; static int ov9665_sysfs_init(void) { int ret ; pr_info("ov9665:kobject creat and add\n"); android_ov9665 = kobject_create_and_add("android_camera2", NULL); if (android_ov9665 == NULL) { pr_info("ov9665_sysfs_init: subsystem_register " \ "failed\n"); ret = -ENOMEM; return ret ; } pr_info("ov9665:sysfs_create_file\n"); ret = sysfs_create_file(android_ov9665, &dev_attr_sensor.attr); if (ret) { pr_info("ov9665_sysfs_init: sysfs_create_file " \ "failed\n"); kobject_del(android_ov9665); } ret = sysfs_create_file(android_ov9665, &dev_attr_htcwc.attr); if (ret) { pr_info("ov9665_sysfs_init: sysfs_create_file htcwc failed\n"); kobject_del(android_ov9665); } ret = sysfs_create_file(android_ov9665, &dev_attr_node.attr); if (ret) { pr_info("ov9665_sysfs_init: dev_attr_node failed\n"); kobject_del(android_ov9665); } return 0 ; } static int ov9665_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc = 0; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { rc = -ENOTSUPP; goto probe_failure; } ov9665_sensorw = kzalloc(sizeof(struct ov9665_work), GFP_KERNEL); if (!ov9665_sensorw) { rc = -ENOMEM; goto probe_failure; } i2c_set_clientdata(client, ov9665_sensorw); ov9665_init_client(client); ov9665_client = client; pr_info("ov9665_probe succeeded!\n"); return 0; probe_failure: kfree(ov9665_sensorw); ov9665_sensorw = NULL; pr_info("ov9665_probe failed!\n"); return rc; } static const struct i2c_device_id ov9665_i2c_id[] = { {"ov9665", 0}, {}, }; static struct i2c_driver ov9665_i2c_driver = { .id_table = ov9665_i2c_id, .probe = ov9665_i2c_probe, .remove = __exit_p(ov9665_i2c_remove), .driver = { .name = "ov9665", }, }; static int ov9665_sensor_probe(struct msm_camera_sensor_info *info, struct msm_sensor_ctrl *s) { int rc = i2c_add_driver(&ov9665_i2c_driver); if (rc < 0 || ov9665_client == NULL) { rc = -ENOTSUPP; goto probe_done; } pr_info("ov9665 s->node %d\n", s->node); sensor_probe_node = s->node; /*switch clk source*/ pr_info("ov9665: ov9665_sensor_probe switch clk\n"); if(info->camera_clk_switch != NULL) info->camera_clk_switch(); /* Config power down */ if(ov9665_pwd(info)<0) goto probe_fail; mdelay(3); /*Config reset */ if(ov9665_reset(info)<0) goto probe_fail; mdelay(5); /*MCLK enable*/ pr_info("ov9665: MCLK enable clk\n"); msm_camio_clk_rate_set(24000000); mdelay(100); /* PLL Setup Start */ rc = ov9665_i2c_write_table(&ov9665_regs.plltbl[0], ov9665_regs.plltbl_size); rc = ov9665_sensor_init(info); if (rc < 0) goto probe_fail; /*set initial register*/ rc = ov9665_reg_init(); if (rc < 0) goto probe_fail; s->s_init = ov9665_sensor_open_init; s->s_release = ov9665_sensor_release; s->s_config = ov9665_sensor_config; /*init done*/ mdelay(800); ov9665_init_done(info); ov9665_sysfs_init(); probe_done: pr_info("%s %s:%d\n", __FILE__, __func__, __LINE__); return rc; probe_fail: pr_err("OV9665 probe faile\n"); return rc; } static int __ov9665_probe(struct platform_device *pdev) { return msm_camera_drv_start(pdev, ov9665_sensor_probe); } static struct platform_driver msm_camera_driver = { .probe = __ov9665_probe, .driver = { .name = "msm_camera_ov9665", .owner = THIS_MODULE, }, }; static int __init ov9665_init(void) { return platform_driver_register(&msm_camera_driver); } module_init(ov9665_init);