From 1bdb7cdb3576e1170684aba3757eb24fa8149aca Mon Sep 17 00:00:00 2001 From: Evgeniy Borisov Date: Mon, 9 Dec 2013 10:39:46 +0200 Subject: [PATCH] msm: camera: Add power down sequence separately for camera Add support for custom power down sequence. With this change we able to define custom sensor power sequence including lesser delays instead of power up sequence. Also for backward compatibility we can use the reversed power up sequence if power down sequence is missing. Change-Id: I99e17dbff7e17f51557f8421fc18de84c9142efb Signed-off-by: Evgeniy Borisov Signed-off-by: Satish Kamuju --- .../msm/camera_v2/sensor/eeprom/msm_eeprom.c | 2 +- .../camera_v2/sensor/io/msm_camera_dt_util.c | 112 ++++++++++++------ .../camera_v2/sensor/io/msm_camera_dt_util.h | 3 +- .../msm/camera_v2/sensor/msm_sensor.c | 109 +++++++++++++++-- .../msm/camera_v2/sensor/msm_sensor_driver.c | 83 +++++++++++-- 5 files changed, 250 insertions(+), 59 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c index 1715acc4815..5c0e6d5837c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c +++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c @@ -612,7 +612,7 @@ static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) rc = msm_camera_get_dt_power_setting_data(of_node, power_info->cam_vreg, power_info->num_vreg, - &power_info->power_setting, &power_info->power_setting_size); + power_info); if (rc < 0) goto ERROR1; diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c index c89fa82f94f..71ba6d34c05 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c @@ -347,8 +347,7 @@ ERROR: int msm_camera_get_dt_power_setting_data(struct device_node *of_node, struct camera_vreg_t *cam_vreg, int num_vreg, - struct msm_sensor_power_setting **power_setting, - uint16_t *power_setting_size) + struct msm_camera_power_ctrl_t *power_info) { int rc = 0, i, j; int count = 0; @@ -356,11 +355,18 @@ int msm_camera_get_dt_power_setting_data(struct device_node *of_node, uint32_t *array = NULL; struct msm_sensor_power_setting *ps; - if (!power_setting || !power_setting_size) + struct msm_sensor_power_setting *power_setting; + uint16_t *power_setting_size; + + if (!power_info) return -EINVAL; + power_setting = power_info->power_setting; + power_setting_size = &power_info->power_setting_size; + count = of_property_count_strings(of_node, "qcom,cam-power-seq-type"); *power_setting_size = count; + CDBG("%s qcom,cam-power-seq-type count %d\n", __func__, count); if (count <= 0) @@ -371,7 +377,7 @@ int msm_camera_get_dt_power_setting_data(struct device_node *of_node, pr_err("%s failed %d\n", __func__, __LINE__); return -ENOMEM; } - *power_setting = ps; + power_setting = ps; for (i = 0; i < count; i++) { rc = of_property_read_string_index(of_node, @@ -502,7 +508,6 @@ int msm_camera_get_dt_power_setting_data(struct device_node *of_node, } kfree(array); return rc; - ERROR2: kfree(array); ERROR1: @@ -1038,6 +1043,7 @@ power_up_failed: power_setting = &ctrl->power_setting[index]; CDBG("%s type %d\n", __func__, power_setting->seq_type); switch (power_setting->seq_type) { + case SENSOR_CLK: msm_cam_clk_enable(ctrl->dev, &ctrl->clk_info[0], @@ -1081,12 +1087,34 @@ power_up_failed: return rc; } +static struct msm_sensor_power_setting* +msm_camera_get_power_settings(struct msm_camera_power_ctrl_t *ctrl, + enum msm_sensor_power_seq_type_t seq_type, + uint16_t seq_val) +{ + struct msm_sensor_power_setting *power_setting, *ps = NULL; + int idx; + + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + power_setting = &ctrl->power_setting[idx]; + if (power_setting->seq_type == seq_type && + power_setting->seq_val == seq_val) { + ps = power_setting; + return ps; + } + + } + return ps; +} + int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, enum msm_camera_device_type_t device_type, struct msm_camera_i2c_client *sensor_i2c_client) { int index = 0; - struct msm_sensor_power_setting *power_setting = NULL; + struct msm_sensor_power_setting *pd = NULL; + struct msm_sensor_power_setting *ps; + CDBG("%s:%d\n", __func__, __LINE__); if (!ctrl || !sensor_i2c_client) { @@ -1099,46 +1127,64 @@ int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, sensor_i2c_client->i2c_func_tbl->i2c_util( sensor_i2c_client, MSM_CCI_RELEASE); - for (index = (ctrl->power_setting_size - 1); index >= 0; index--) { + for (index = 0; index < ctrl->power_down_setting_size; index++) { CDBG("%s index %d\n", __func__, index); - power_setting = &ctrl->power_setting[index]; - CDBG("%s type %d\n", __func__, power_setting->seq_type); - switch (power_setting->seq_type) { + pd = &ctrl->power_down_setting[index]; + ps = NULL; + CDBG("%s type %d\n", __func__, pd->seq_type); + switch (pd->seq_type) { case SENSOR_CLK: - msm_cam_clk_enable(ctrl->dev, - &ctrl->clk_info[0], - (struct clk **)&power_setting->data[0], - ctrl->clk_info_size, - 0); - break; + + ps = msm_camera_get_power_settings(ctrl, + pd->seq_type, + pd->seq_val); + if (ps) + msm_cam_clk_enable(ctrl->dev, + &ctrl->clk_info[0], + (struct clk **)&ps->data[0], + ctrl->clk_info_size, + 0); + else + pr_err("%s error in power up/down seq data\n", + __func__); + break; case SENSOR_GPIO: - if (power_setting->seq_val >= SENSOR_GPIO_MAX || + if (pd->seq_val >= SENSOR_GPIO_MAX || !ctrl->gpio_conf->gpio_num_info) { pr_err("%s gpio index %d >= max %d\n", __func__, - power_setting->seq_val, + pd->seq_val, SENSOR_GPIO_MAX); continue; } if (!ctrl->gpio_conf->gpio_num_info->valid - [power_setting->seq_val]) + [pd->seq_val]) continue; gpio_set_value_cansleep( ctrl->gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val], + [pd->seq_val], ctrl->gpio_conf->gpio_num_info->gpio_num - [power_setting->config_val]); + [pd->config_val]); break; case SENSOR_VREG: - if (power_setting->seq_val >= CAM_VREG_MAX) { + if (pd->seq_val >= CAM_VREG_MAX) { pr_err("%s vreg index %d >= max %d\n", __func__, - power_setting->seq_val, + pd->seq_val, SENSOR_GPIO_MAX); continue; } - msm_camera_config_single_vreg(ctrl->dev, - &ctrl->cam_vreg[power_setting->seq_val], - (struct regulator **)&power_setting->data[0], - 0); + + ps = msm_camera_get_power_settings(ctrl, + pd->seq_type, + pd->seq_val); + + if (ps) + msm_camera_config_single_vreg(ctrl->dev, + &ctrl->cam_vreg[pd->seq_val], + (struct regulator **)&ps->data[0], + 0); + else + pr_err("%s error in power up/down seq data\n", + __func__); break; case SENSOR_I2C_MUX: if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) @@ -1146,14 +1192,14 @@ int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, break; default: pr_err("%s error power seq type %d\n", __func__, - power_setting->seq_type); + pd->seq_type); break; } - if (power_setting->delay > 20) { - msleep(power_setting->delay); - } else if (power_setting->delay) { - usleep_range(power_setting->delay * 1000, - (power_setting->delay * 1000) + 1000); + if (pd->delay > 20) { + msleep(pd->delay); + } else if (pd->delay) { + usleep_range(pd->delay * 1000, + (pd->delay * 1000) + 1000); } } msm_camera_request_gpio_table( diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h index 84d53e7d07a..d7f850798f2 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h @@ -29,8 +29,7 @@ int msm_sensor_get_dt_csi_data(struct device_node *of_node, int msm_camera_get_dt_power_setting_data(struct device_node *of_node, struct camera_vreg_t *cam_vreg, int num_vreg, - struct msm_sensor_power_setting **power_setting, - uint16_t *power_setting_size); + struct msm_camera_power_ctrl_t *power_info); int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c index d915351086f..87ad9945b12 100755 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c @@ -35,6 +35,7 @@ static int32_t msm_camera_get_power_settimgs_from_sensor_lib( int32_t rc = 0; uint32_t size; struct msm_sensor_power_setting *ps; + bool need_reverse = 0; if ((NULL == power_info->power_setting) || (0 == power_info->power_setting_size)) { @@ -60,7 +61,42 @@ static int32_t msm_camera_get_power_settimgs_from_sensor_lib( power_info->power_setting_size = size; } + ps = power_setting_array->power_down_setting; + size = power_setting_array->size_down; + if (NULL == ps || 0 == size) { + ps = power_info->power_setting; + size = power_info->power_setting_size; + need_reverse = 1; + } + + power_info->power_down_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + if (!power_info->power_down_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_UP; + } + memcpy(power_info->power_down_setting, + ps, + sizeof(*ps) * size); + power_info->power_down_setting_size = size; + + if (need_reverse) { + int c, end = size - 1; + struct msm_sensor_power_setting power_down_setting_t; + for (c = 0; c < size/2; c++) { + power_down_setting_t = + power_info->power_down_setting[c]; + power_info->power_down_setting[c] = + power_info->power_down_setting[end]; + power_info->power_down_setting[end] = + power_down_setting_t; + end--; + } + } + return 0; +FREE_UP: + kfree(power_info->power_setting); FAILED_1: return rc; } @@ -159,8 +195,7 @@ static int32_t msm_sensor_get_dt_data(struct device_node *of_node, rc = msm_camera_get_dt_power_setting_data(of_node, sensordata->power_info.cam_vreg, sensordata->power_info.num_vreg, - &sensordata->power_info.power_setting, - &sensordata->power_info.power_setting_size); + &sensordata->power_info); if (rc < 0) { @@ -277,6 +312,7 @@ FREE_GPIO_CONF: kfree(s_ctrl->sensordata->power_info.gpio_conf); FREE_PS: kfree(s_ctrl->sensordata->power_info.power_setting); + kfree(s_ctrl->sensordata->power_info.power_down_setting); FREE_VREG: kfree(s_ctrl->sensordata->power_info.cam_vreg); FREE_CSI: @@ -566,7 +602,7 @@ int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) struct msm_camera_sensor_slave_info sensor_slave_info; struct msm_camera_power_ctrl_t *p_ctrl; uint16_t size; - int slave_index = 0; + int s_index = 0; if (copy_from_user(&sensor_slave_info, (void *)cdata->cfg.setting, sizeof(sensor_slave_info))) { @@ -583,9 +619,9 @@ int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) /* Update sensor address type */ s_ctrl->sensor_i2c_client->addr_type = sensor_slave_info.addr_type; - - /* Update power up / down sequence */ p_ctrl = &s_ctrl->sensordata->power_info; + + /* Update power up sequence */ size = sensor_slave_info.power_setting_array.size; if (p_ctrl->power_setting_size < size) { struct msm_sensor_power_setting *tmp; @@ -619,15 +655,62 @@ int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) sensor_slave_info.sensor_id_info.sensor_id_reg_addr); CDBG("%s sensor id %x\n", __func__, sensor_slave_info.sensor_id_info.sensor_id); - for (slave_index = 0; slave_index < - p_ctrl->power_setting_size; slave_index++) { - CDBG("%s i %d power setting %d %d %ld %d\n", __func__, - slave_index, - p_ctrl->power_setting[slave_index].seq_type, - p_ctrl->power_setting[slave_index].seq_val, - p_ctrl->power_setting[slave_index].config_val, - p_ctrl->power_setting[slave_index].delay); + for (s_index = 0; s_index < + p_ctrl->power_setting_size; s_index++) { + CDBG("%s i %d power up setting %d %d %ld %d\n", + __func__, + s_index, + p_ctrl->power_setting[s_index].seq_type, + p_ctrl->power_setting[s_index].seq_val, + p_ctrl->power_setting[s_index].config_val, + p_ctrl->power_setting[s_index].delay); } + + /* Update power down sequence */ + if (!sensor_slave_info.power_setting_array.power_down_setting || + 0 == size) { + pr_err("%s: Missing dedicated power down sequence\n", + __func__); + break; + } + size = sensor_slave_info.power_setting_array.size_down; + + if (p_ctrl->power_down_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_down_setting); + p_ctrl->power_down_setting = tmp; + } + p_ctrl->power_down_setting_size = size; + + + rc = copy_from_user(p_ctrl->power_down_setting, (void *) + sensor_slave_info.power_setting_array. + power_down_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(sensor_slave_info.power_setting_array. + power_down_setting); + rc = -EFAULT; + break; + } + for (s_index = 0; s_index < + p_ctrl->power_down_setting_size; s_index++) { + CDBG("%s i %d power DOWN setting %d %d %ld %d\n", + __func__, + s_index, + p_ctrl->power_down_setting[s_index].seq_type, + p_ctrl->power_down_setting[s_index].seq_val, + p_ctrl->power_down_setting[s_index].config_val, + p_ctrl->power_down_setting[s_index].delay); + } + break; } case CFG_WRITE_I2C_ARRAY: { diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index f04c370f1b1..c6fbf200a12 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -144,13 +144,16 @@ static int32_t msm_sensor_driver_create_v4l_subdev int32_t msm_sensor_driver_probe(void *setting) { int32_t rc = 0; - uint16_t i = 0, size = 0; + uint16_t i = 0, size = 0, size_down = 0; struct msm_sensor_ctrl_t *s_ctrl = NULL; struct msm_camera_cci_client *cci_client = NULL; struct msm_camera_sensor_slave_info *slave_info = NULL; struct msm_sensor_power_setting *power_setting = NULL; + struct msm_sensor_power_setting *power_down_setting = NULL; struct msm_camera_slave_info *camera_info = NULL; struct msm_camera_power_ctrl_t *power_info = NULL; + int c, end; + struct msm_sensor_power_setting power_down_setting_t; /* Validate input parameters */ if (!setting) { @@ -178,7 +181,8 @@ int32_t msm_sensor_driver_probe(void *setting) CDBG("sensor_id_reg_addr %x", slave_info->sensor_id_info.sensor_id_reg_addr); CDBG("sensor_id %x", slave_info->sensor_id_info.sensor_id); - CDBG("size %x", slave_info->power_setting_array.size); + CDBG("size %d", slave_info->power_setting_array.size); + CDBG("size down %d", slave_info->power_setting_array.size_down); /* Validate camera id */ if (slave_info->camera_id >= MAX_CAMERAS) { @@ -211,7 +215,7 @@ int32_t msm_sensor_driver_probe(void *setting) } size = slave_info->power_setting_array.size; - /* Allocate memory for power setting */ + /* Allocate memory for power up setting */ power_setting = kzalloc(sizeof(*power_setting) * size, GFP_KERNEL); if (!power_setting) { pr_err("failed: no memory power_setting %p", power_setting); @@ -229,15 +233,68 @@ int32_t msm_sensor_driver_probe(void *setting) /* Print power setting */ for (i = 0; i < size; i++) { - CDBG("seq_type %d seq_val %d config_val %ld delay %d", + CDBG("UP seq_type %d seq_val %d config_val %ld delay %d", power_setting[i].seq_type, power_setting[i].seq_val, power_setting[i].config_val, power_setting[i].delay); } + /*DOWN*/ + size_down = slave_info->power_setting_array.size_down; + if (!size_down) + size_down = size; + /* Allocate memory for power down setting */ + power_down_setting = + kzalloc(sizeof(*power_setting) * size_down, GFP_KERNEL); + if (!power_down_setting) { + pr_err("failed: no memory power_setting %p", + power_down_setting); + rc = -ENOMEM; + goto FREE_POWER_SETTING; + } + + if (slave_info->power_setting_array.power_down_setting) { + if (copy_from_user(power_down_setting, + (void *)slave_info->power_setting_array. + power_down_setting, + sizeof(*power_down_setting) * size_down)) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_POWER_DOWN_SETTING; + } + } else { + pr_err("failed: no power_down_setting"); + if (copy_from_user(power_down_setting, + (void *)slave_info->power_setting_array. + power_setting, + sizeof(*power_down_setting) * size_down)) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_POWER_DOWN_SETTING; + } + + /*reverce*/ + end = size_down - 1; + for (c = 0; c < size_down/2; c++) { + power_down_setting_t = power_down_setting[c]; + power_down_setting[c] = power_down_setting[end]; + power_down_setting[end] = power_down_setting_t; + end--; + } + + } + + /* Print power setting */ + for (i = 0; i < size_down; i++) { + CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d", + power_down_setting[i].seq_type, + power_down_setting[i].seq_val, + power_down_setting[i].config_val, + power_down_setting[i].delay); + } camera_info = kzalloc(sizeof(struct msm_camera_slave_info), GFP_KERNEL); if (!camera_info) { pr_err("failed: no memory slave_info %p", camera_info); - goto FREE_POWER_SETTING; + goto FREE_POWER_DOWN_SETTING; } @@ -245,6 +302,8 @@ int32_t msm_sensor_driver_probe(void *setting) power_info = &s_ctrl->sensordata->power_info; power_info->power_setting = power_setting; power_info->power_setting_size = size; + power_info->power_down_setting = power_down_setting; + power_info->power_down_setting_size = size_down; s_ctrl->sensordata->slave_info = camera_info; @@ -259,7 +318,7 @@ int32_t msm_sensor_driver_probe(void *setting) pr_err("failed: sensor_i2c_client %p", s_ctrl->sensor_i2c_client); rc = -EINVAL; - goto FREE_POWER_SETTING; + goto FREE_CAMERA_INFO; } /* Fill sensor address type */ s_ctrl->sensor_i2c_client->addr_type = slave_info->addr_type; @@ -270,7 +329,7 @@ int32_t msm_sensor_driver_probe(void *setting) cci_client = s_ctrl->sensor_i2c_client->cci_client; if (!cci_client) { pr_err("failed: cci_client %p", cci_client); - goto FREE_POWER_SETTING; + goto FREE_CAMERA_INFO; } cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; cci_client->sid = slave_info->slave_addr >> 1; @@ -286,7 +345,7 @@ int32_t msm_sensor_driver_probe(void *setting) if (rc < 0) { pr_err("failed: msm_camera_get_dt_power_setting_data rc %d", rc); - goto FREE_POWER_SETTING; + goto FREE_CAMERA_INFO; } /* Parse and fill vreg params for powerdown settings*/ @@ -298,7 +357,7 @@ int32_t msm_sensor_driver_probe(void *setting) if (rc < 0) { pr_err("failed: msm_camera_fill_vreg_params for PDOWN rc %d", rc); - goto FREE_POWER_SETTING; + goto FREE_CAMERA_INFO; } /* Update sensor, actuator and eeprom name in @@ -309,7 +368,7 @@ int32_t msm_sensor_driver_probe(void *setting) rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); if (rc < 0) { pr_err("%s power up failed", slave_info->sensor_name); - goto FREE_POWER_SETTING; + goto FREE_CAMERA_INFO; } pr_err("%s probe succeeded", slave_info->sensor_name); @@ -344,6 +403,10 @@ int32_t msm_sensor_driver_probe(void *setting) CAMERA_POWER_DOWN: s_ctrl->func_tbl->sensor_power_down(s_ctrl); +FREE_CAMERA_INFO: + kfree(camera_info); +FREE_POWER_DOWN_SETTING: + kfree(power_down_setting); FREE_POWER_SETTING: kfree(power_setting); FREE_SLAVE_INFO: