static int sensor_ctrl_rg_weight(struct v4l2_subdev *sd, int val) { struct sensor_info *info = to_sensor(sd); u8 *value = (u8 *)&val; int ret = 0; sensor_dbg("val = %d", val); if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_GAIN_RED, value[1]); if (ret < 0) { sensor_err("Failed to add request(RED)"); goto ret; } ret = sensor_add_request(sd, SENSOR_REG_VIS_GAIN_GREEN, value[0]); if (ret < 0) { sensor_err("Failed to add request(GREEN)"); goto ret; } } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_GAIN_RED, (u8)value[1], I2C_8BIT); if (ret < 0) { sensor_err("file to write reg(ret = %d)", ret); goto ret; } ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_GAIN_GREEN, (u8)value[0], I2C_8BIT); if (ret < 0) { sensor_err("file to write reg(ret = %d)", ret); goto ret; } } ret: return ret; }
/* * sensor_straming - start and stop streaming. */ int sensor_streaming(struct v4l2_subdev *sd, enum sensor_status state) { struct sensor_info *info = to_sensor(sd); int ret = 0; if (state == info->status) { sensor_err("sensor is already stream %s", state == STATUS_STREAMING ? "on" : "off"); return ret; } ret = vision_sensor_write_reg(sd, 0x4100, (u8)state, I2C_8BIT); if (ret < 0) { sensor_err("file to write reg(ret = %d)", ret); return ret; } if (state == STATUS_STANDBY) { ret = sensor_drain_request(sd, true); if (ret < 0) { sensor_err("fail to drain request"); return ret; } } info->status = state; return ret; }
static int sensor_add_request(struct v4l2_subdev *sd, u32 addr, u8 val) { struct sensor_info *info = to_sensor(sd); if (info->req_head == NULL) { info->req_head = kzalloc(sizeof(struct sensor_req_list), GFP_ATOMIC); if (info->req_head == NULL) { sensor_err("Failed to allocate new requeset\n"); return -ENOMEM; } info->req_tail = info->req_head; info->req_head->next = NULL; info->req_head->addr = addr; info->req_head->value = val; } else if (info->req_tail->next == NULL) { info->req_tail->next = kzalloc(sizeof(struct sensor_req_list), GFP_ATOMIC); if (info->req_tail->next == NULL) { sensor_err("Failed to allocate new requeset\n"); return -ENOMEM; } info->req_tail = info->req_tail->next; info->req_tail->next = NULL; info->req_tail->addr = addr; info->req_tail->value = val; } else { sensor_err("Failed to add request, abnormal state!"); return -1; } return 0; }
/* * sensor_power - handle sensor power up/down. * * @enable: If it is true, power up. If is not, power down. */ static int sensor_power(struct sensor_info *info, bool enable) { struct v4l2_subdev *sd = &info->sd; struct i2c_client *client = v4l2_get_subdevdata(sd); struct device *cdev = &client->dev; const struct exynos_fimc_is_sensor_platform_data *pdata = cdev->platform_data; int ret = 0; if (enable) { if (is_powerup(sd)) return 0; if (pdata->clk_on) { pdata->clk_on(cdev, FLITE_ID_C); } else { sensor_err("failed to clk_on\n"); return -1; } info->power = true; } else { if (!is_powerup(sd)) return 0; if (pdata->clk_off) { pdata->clk_off(cdev, FLITE_ID_C); } else { sensor_err("failed to clk_off\n"); return -1; } info->power = false; } return ret; }
int vision_sensor_write_reg(struct v4l2_subdev *sd, u32 addr, u8 val, enum sensor_i2c_size size) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_msg msg[1]; u8 *array = (u8*)&addr; u8 wbuf[3]; int ret; if (!client->adapter) { sensor_err("Could not find adapter!\n"); return -ENODEV; } if (size != I2C_8BIT && size != I2C_16BIT && size != I2C_32BIT) { sensor_err("Wrong data size\n"); return -EINVAL; } msg->addr = client->addr; msg->flags = 0; msg->len = 3; msg->buf = wbuf; wbuf[0] = array[1]; wbuf[1] = array[0]; wbuf[2] = val; ret = i2c_transfer(client->adapter, msg, 1); if (ret < 0) { sensor_err("i2c treansfer fail"); return ret; } return 0; }
static int sensor_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct sensor_info *info = to_sensor(sd); int ret = 0; struct platform_device *pdev; int irq = 0; v4l2_dbg(1, sensor_debug, sd, "%s", __func__); ret = sensor_set_clock(sd, FLITE_ID_C); if (ret < 0) { sensor_err("sensor set clock fail"); return ret; } ret = sensor_init_controls(info); if (ret < 0) { sensor_err("sensor init contols fail"); return ret; } fh->vfh.ctrl_handler = &info->handle; sensor_init_formats(sd, fh); pdev = get_mipi_csis_pdev(FLITE_ID_C); irq = platform_get_irq(pdev, 0); v4l2_dbg(1, sensor_debug, sd, "%s : mipi irq num : %d", __func__, irq); enable_irq(irq); return 0; }
static int sensor_ctrl_frame_rate(struct v4l2_subdev *sd, int val) { struct sensor_info *info = to_sensor(sd); u8 *value = (u8 *)&val; int ret = 0; sensor_dbg("val = %d", val); if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_DURATION_MSB, value[1]); if (ret < 0) { sensor_err("Failed to add request(MSB)"); goto ret; } ret = sensor_add_request(sd, SENSOR_REG_VIS_DURATION_LSB, value[0]); if (ret < 0) { sensor_err("Failed to add request(LSB)"); goto ret; } } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_DURATION_MSB, (u8)value[1], I2C_8BIT); if (ret < 0) { sensor_err("file to write reg(ret = %d)", ret); goto ret; } ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_DURATION_LSB, (u8)value[0], I2C_8BIT); if (ret < 0) { sensor_err("file to write reg(ret = %d)", ret); goto ret; } } ret: return ret; }
static int sensor_s_power(struct v4l2_subdev *sd, int on) { struct sensor_info *info = to_sensor(sd); int ret; if (on) { /* * HACK * s_power of flite make mux to change to ipll and then * mclk for vision should be cacaluate again after mux setting changes * vision clock source is channel 2 */ ret = sensor_set_clock(sd, FLITE_ID_C); if (ret < 0) sensor_err("sensor set clock fail"); ret = sensor_power(info, true); if (!ret) ret = sensor_setup_default(sd); } else { ret = sensor_power(info, false); } return ret; }
static int sensor_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); u32 cmd = ctrl->id; s32 value = ctrl->val; int ret = 0; switch (cmd) { case V4L2_CID_SENSOR_SET_AE_TARGET: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_ae_target(sd, value); break; case V4L2_CID_SENSOR_SET_AE_WEIGHT_1x1_2: case V4L2_CID_SENSOR_SET_AE_WEIGHT_1x3_4: case V4L2_CID_SENSOR_SET_AE_WEIGHT_2x1_2: case V4L2_CID_SENSOR_SET_AE_WEIGHT_2x3_4: case V4L2_CID_SENSOR_SET_AE_WEIGHT_3x1_2: case V4L2_CID_SENSOR_SET_AE_WEIGHT_3x3_4: case V4L2_CID_SENSOR_SET_AE_WEIGHT_4x1_2: case V4L2_CID_SENSOR_SET_AE_WEIGHT_4x3_4: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_ae_weight(sd, cmd, value); break; case V4L2_CID_SENSOR_SET_RG_WEIGHT: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_rg_weight(sd, value); break; case V4L2_CID_SENSOR_SET_AE_SPEED: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_ae_speed(sd, value); break; case V4L2_CID_SENSOR_SET_SHUTTER: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_shutter(sd, value); break; case V4L2_CID_SENSOR_SET_GAIN: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_gain(sd, value); break; case V4L2_CID_SENSOR_SET_BIT_CONVERTING: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_bit_converting(sd, value); break; case V4L2_CID_SENSOR_SET_AUTO_EXPOSURE: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_auto_exposure(sd, value); break; case V4L2_CID_SENSOR_SET_FRAME_RATE: sensor_dbg("ctrl.id = %x, val=%x", cmd, value); ret = sensor_ctrl_frame_rate(sd, value); break; default : sensor_err("Unknown CID(%x)", cmd); ret = -1; break; } return ret; }
/* * vision_sensor_read_reg/vision_sensor_write_reg - handle sensor's I2C communications. * * The I2C command packet of sensor is made up 3 kinds of I2C bytes(category, * command, bytes). Reference exynos_sensor.h. * * The packet is needed 2, when read through I2C. * The packet is needed 1, when written through I2C. * * I2C packet common order(including both reading/writing) * 1st : Slave addr * 2nd : READ/WRITE (R - 0x01, W - 0x02) * 3rd : Size * 4th : Data */ int vision_sensor_read_reg(struct v4l2_subdev *sd, u32 addr, u8 *val, enum sensor_i2c_size size) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_msg msg[2]; u8 *array = (u8*)&addr; u8 wbuf[2]; int ret; if (!client->adapter) { sensor_err("Could not find adapter!\n"); return -ENODEV; } if (size != I2C_8BIT && size != I2C_16BIT && size != I2C_32BIT) { sensor_err("Wrong data size\n"); return -EINVAL; } /* 1. I2C operation for writing. */ msg[0].addr = client->addr; msg[0].flags = 0; /* write : 0, read : 1 */ msg[0].len = 2; msg[0].buf = wbuf; /* TODO : consider other size of buffer */ wbuf[0] = array[1]; wbuf[1] = array[0]; /* 2. I2C operation for reading data. */ msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].len = 1; msg[1].buf = val; ret = i2c_transfer(client->adapter, msg, 2); if (ret < 0) { sensor_err("i2c treansfer fail"); return ret; } return 0; }
static int sensor_ctrl_auto_exposure(struct v4l2_subdev *sd, int val) { struct sensor_info *info = to_sensor(sd); u8 *value = (u8 *)&val; int ret = 0; sensor_dbg("val = %d", val); if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_OFF, value[0]); if (ret < 0) sensor_err("Failed to add request"); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_OFF, (u8)value[0], I2C_8BIT); if (ret < 0) sensor_err("file to write reg(ret = %d)", ret); } return ret; }
/* * sensor_init_controls - initialization using v4l2_ctrl. */ static int sensor_init_controls(struct sensor_info *info) { struct v4l2_subdev *sd = &info->sd; int num_of_ctl_hint = ARRAY_SIZE(ctrl_private); /* set the controls using v4l2 control frameworks */ v4l2_ctrl_handler_init(&info->handle, num_of_ctl_hint); /* Vision mode only support simple AE */ info->ae_target = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[0], NULL); info->ae_weight[0] = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[1], NULL); info->ae_weight[1] = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[2], NULL); info->ae_weight[2] = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[3], NULL); info->ae_weight[3] = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[4], NULL); info->ae_weight[4] = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[5], NULL); info->ae_weight[5] = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[6], NULL); info->ae_weight[6] = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[7], NULL); info->ae_weight[7] = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[8], NULL); info->rg_weight = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[9], NULL); info->ae_speed = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[10], NULL); info->shutter = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[11], NULL); info->gain = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[12], NULL); info->bit_converting = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[13], NULL); info->autoexposure = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[14], NULL); info->framerate = v4l2_ctrl_new_custom(&info->handle, &ctrl_private[15], NULL); sd->ctrl_handler = &info->handle; if (info->handle.error) { sensor_err("Failed to init controls, %d\n", info->handle.error); v4l2_ctrl_handler_free(&info->handle); return info->handle.error; } return 0; }
static void sensor_handler(void *data, int arg) { struct v4l2_subdev *sd = data; struct sensor_info *info = to_sensor(sd); sensor_dbg("%s: irq(%d), info->status(%d)", __func__, arg, info->status); switch (arg) { case FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART: sensor_dbg("Flite frame start"); tasklet_schedule(&info->tasklet_flite_str); break; case FLITE_REG_CISTATUS_IRQ_SRC_FRMEND: sensor_dbg("Flite frame end"); schedule_work(&info->work); break; default : sensor_err("unknown irq(%d)", arg); break; } }
static void tasklet_func_flite_end(unsigned long data) { struct sensor_info *info = (struct sensor_info *)data; struct sensor_req_list *req = NULL; int ret = 0; req = sensor_get_request(&info->sd); while (req) { sensor_dbg("addr(%.8x), val(%x)", req->addr, req->value); ret = vision_sensor_write_reg(&info->sd, req->addr, (u8)req->value, I2C_8BIT); kfree(req); req = NULL; if (ret < 0) { sensor_err("file to write reg(ret = %d)", ret); break; } req = sensor_get_request(&info->sd); } }
static void sensor_irq_work(struct work_struct *work) { struct sensor_info *info = container_of(work, struct sensor_info, work); struct sensor_req_list *req = NULL; int ret = 0; req = sensor_get_request(&info->sd); while (req) { sensor_dbg("addr(%.8x), val(%x)", req->addr, req->value); ret = vision_sensor_write_reg(&info->sd, req->addr, (u8)req->value, I2C_8BIT); kfree(req); req = NULL; if (ret < 0) { sensor_err("file to write reg(ret = %d)", ret); break; } req = sensor_get_request(&info->sd); } }
static int sensor_drain_request(struct v4l2_subdev *sd, bool isValid) { struct sensor_info *info = to_sensor(sd); struct sensor_req_list *req = NULL; int ret = 0; req = sensor_get_request(&info->sd); while (req) { if (isValid) ret = vision_sensor_write_reg(&info->sd, req->addr, (u8)req->value, I2C_8BIT); kfree(req); req = NULL; if (ret < 0) { sensor_err("file to write reg(ret = %d)", ret); break; } req = sensor_get_request(&info->sd); } return ret; }
static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct exynos_fimc_is_sensor_platform_data *pdata = client->dev.platform_data; struct sensor_info *info; struct v4l2_subdev *sd; int ret = 0; if (pdata == NULL) { sensor_err("No platform data\n"); return -EINVAL; } if (!gpio_is_valid(pdata->gpio_rst)) { sensor_err("No valid nRST gpio pin.\n"); return -EINVAL; } info = kzalloc(sizeof(struct sensor_info), GFP_KERNEL); if (info == NULL) { sensor_err("Failed to allocate info\n"); return -ENOMEM; } info->pdata = pdata; tasklet_init(&info->tasklet_flite_str, tasklet_func_flite_str, (unsigned long)info); tasklet_init(&info->tasklet_flite_end, tasklet_func_flite_end, (unsigned long)info); INIT_WORK(&info->work, sensor_irq_work); if (info->pdata->irq) { ret = request_irq(info->pdata->irq, sensor_irq_handler, IRQF_TRIGGER_RISING, MOD_NAME, &info->sd); if (ret) { sensor_err("Failed to request irq: %d\n", ret); return ret; } } ret = gpio_request(info->pdata->gpio_rst, "GPIO_CAM_VT_nRST"); if (ret) { sensor_err("Failed to set gpio, %d\n", ret); goto out_gpio; } /* s3c_gpio_setpull(info->pdata->gpio_rst, S3C_GPIO_PULL_NONE); gpio_direction_output(info->pdata->gpio_rst, 0); gpio_direction_output(info->pdata->gpio_rst, 1); */ gpio_free(info->pdata->gpio_rst); sd = &info->sd; v4l2_i2c_subdev_init(sd, client, &sensor_ops); info->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&sd->entity, 1, &info->pad, 0); if (ret < 0) goto out_reg; sensor_init_formats(sd, NULL); strlcpy(sd->name, MOD_NAME, sizeof(sd->name)); sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; sd->internal_ops = &sensor_v4l2_internal_ops; sd->entity.ops = &sensor_media_ops; sd->host_priv = sensor_handler; info->req_head = NULL; info->req_tail = NULL; v4l2_info(sd, "%s : sensor driver probed success\n", __func__); return 0; out_reg: out_gpio: gpio_free(info->pdata->gpio_rst); kfree(info); return ret; }
static int sensor_ctrl_ae_weight(struct v4l2_subdev *sd, int cmd, int val) { struct sensor_info *info = to_sensor(sd); u8 *value = (u8 *)&val; int ret = 0; sensor_dbg("cmd = %x val = %d", cmd, val); switch (cmd) { case V4L2_CID_SENSOR_SET_AE_WEIGHT_1x1_2: if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x1_2, value[0]); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x1_2, (u8)value[0], I2C_8BIT); } break; case V4L2_CID_SENSOR_SET_AE_WEIGHT_1x3_4: if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x3_4, value[0]); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x3_4, (u8)value[0], I2C_8BIT); } break; case V4L2_CID_SENSOR_SET_AE_WEIGHT_2x1_2: if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x1_2, value[0]); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x1_2, (u8)value[0], I2C_8BIT); } break; case V4L2_CID_SENSOR_SET_AE_WEIGHT_2x3_4: if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x3_4, value[0]); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x3_4, (u8)value[0], I2C_8BIT); } break; case V4L2_CID_SENSOR_SET_AE_WEIGHT_3x1_2: if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x1_2, value[0]); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x1_2, (u8)value[0], I2C_8BIT); } break; case V4L2_CID_SENSOR_SET_AE_WEIGHT_3x3_4: if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x3_4, value[0]); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x3_4, (u8)value[0], I2C_8BIT); } break; case V4L2_CID_SENSOR_SET_AE_WEIGHT_4x1_2: if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x1_2, value[0]); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x1_2, (u8)value[0], I2C_8BIT); } break; case V4L2_CID_SENSOR_SET_AE_WEIGHT_4x3_4: if (info->status == STATUS_STREAMING) { ret = sensor_add_request(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x3_4, value[0]); } else { ret = vision_sensor_write_reg(sd, SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x3_4, (u8)value[0], I2C_8BIT); } break; default : sensor_err("Unknown CID"); ret = -EINVAL; break; } if (ret < 0) sensor_err("Failed to set ae weight(CID:%x)", cmd); return ret; }