| /* Copyright (c) 2013, The Linux Foundation. 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. |
| * |
| */ |
| |
| #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ |
| |
| #include <mach/gpiomux.h> |
| #include <linux/module.h> |
| #include "msm_led_flash.h" |
| #include "msm_camera_io_util.h" |
| #include "../msm_sensor.h" |
| #include "msm_led_flash.h" |
| #include <linux/debugfs.h> |
| |
| #define FLASH_NAME "camera-led-flash" |
| |
| /*#define CONFIG_MSMB_CAMERA_DEBUG*/ |
| #undef CDBG |
| #ifdef CONFIG_MSMB_CAMERA_DEBUG |
| #define CDBG(fmt, args...) pr_err(fmt, ##args) |
| #else |
| #define CDBG(fmt, args...) do { } while (0) |
| #endif |
| |
| int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, |
| void *arg) |
| { |
| uint32_t *subdev_id = (uint32_t *)arg; |
| if (!subdev_id) { |
| pr_err("failed\n"); |
| return -EINVAL; |
| } |
| *subdev_id = fctrl->subdev_id; |
| |
| CDBG("subdev_id %d\n", *subdev_id); |
| return 0; |
| } |
| |
| int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl, |
| void *data) |
| { |
| int rc = 0; |
| struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data; |
| CDBG("called led_state %d\n", cfg->cfgtype); |
| |
| if (!fctrl->func_tbl) { |
| pr_err("failed\n"); |
| return -EINVAL; |
| } |
| switch (cfg->cfgtype) { |
| |
| case MSM_CAMERA_LED_INIT: |
| if (fctrl->func_tbl->flash_led_init) |
| rc = fctrl->func_tbl->flash_led_init(fctrl); |
| break; |
| |
| case MSM_CAMERA_LED_RELEASE: |
| if (fctrl->func_tbl->flash_led_release) |
| rc = fctrl->func_tbl-> |
| flash_led_release(fctrl); |
| break; |
| |
| case MSM_CAMERA_LED_OFF: |
| if (fctrl->func_tbl->flash_led_off) |
| rc = fctrl->func_tbl->flash_led_off(fctrl); |
| break; |
| |
| case MSM_CAMERA_LED_LOW: |
| if (fctrl->func_tbl->flash_led_low) |
| rc = fctrl->func_tbl->flash_led_low(fctrl); |
| break; |
| |
| case MSM_CAMERA_LED_HIGH: |
| if (fctrl->func_tbl->flash_led_high) |
| rc = fctrl->func_tbl->flash_led_high(fctrl); |
| break; |
| default: |
| rc = -EFAULT; |
| break; |
| } |
| CDBG("flash_set_led_state: return %d\n", rc); |
| return rc; |
| } |
| |
| int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl) |
| { |
| int rc = 0; |
| struct msm_camera_sensor_board_info *flashdata = NULL; |
| CDBG("%s:%d called\n", __func__, __LINE__); |
| |
| flashdata = fctrl->flashdata; |
| if (flashdata->gpio_conf->cam_gpiomux_conf_tbl != NULL) { |
| pr_err("%s:%d mux install\n", __func__, __LINE__); |
| msm_gpiomux_install( |
| (struct msm_gpiomux_config *) |
| flashdata->gpio_conf->cam_gpiomux_conf_tbl, |
| flashdata->gpio_conf->cam_gpiomux_conf_tbl_size); |
| } |
| |
| rc = msm_camera_request_gpio_table( |
| flashdata->gpio_conf->cam_gpio_req_tbl, |
| flashdata->gpio_conf->cam_gpio_req_tbl_size, 1); |
| if (rc < 0) { |
| pr_err("%s: request gpio failed\n", __func__); |
| return rc; |
| } |
| msleep(20); |
| gpio_set_value_cansleep( |
| flashdata->gpio_conf->gpio_num_info->gpio_num[0], |
| GPIO_OUT_HIGH); |
| |
| if (fctrl->flash_i2c_client && fctrl->reg_setting) { |
| rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( |
| fctrl->flash_i2c_client, |
| fctrl->reg_setting->init_setting); |
| if (rc < 0) |
| pr_err("%s:%d failed\n", __func__, __LINE__); |
| } |
| |
| return rc; |
| } |
| |
| int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl) |
| { |
| int rc = 0; |
| struct msm_camera_sensor_board_info *flashdata = NULL; |
| |
| flashdata = fctrl->flashdata; |
| CDBG("%s:%d called\n", __func__, __LINE__); |
| if (!fctrl) { |
| pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); |
| return -EINVAL; |
| } |
| gpio_set_value_cansleep( |
| flashdata->gpio_conf->gpio_num_info->gpio_num[0], |
| GPIO_OUT_LOW); |
| gpio_set_value_cansleep( |
| flashdata->gpio_conf->gpio_num_info->gpio_num[1], |
| GPIO_OUT_LOW); |
| rc = msm_camera_request_gpio_table( |
| flashdata->gpio_conf->cam_gpio_req_tbl, |
| flashdata->gpio_conf->cam_gpio_req_tbl_size, 0); |
| if (rc < 0) { |
| pr_err("%s: request gpio failed\n", __func__); |
| return rc; |
| } |
| return 0; |
| } |
| |
| int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl) |
| { |
| int rc = 0; |
| struct msm_camera_sensor_board_info *flashdata = NULL; |
| |
| flashdata = fctrl->flashdata; |
| CDBG("%s:%d called\n", __func__, __LINE__); |
| if (!fctrl) { |
| pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); |
| return -EINVAL; |
| } |
| if (fctrl->flash_i2c_client && fctrl->reg_setting) { |
| rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( |
| fctrl->flash_i2c_client, |
| fctrl->reg_setting->off_setting); |
| if (rc < 0) |
| pr_err("%s:%d failed\n", __func__, __LINE__); |
| } |
| gpio_set_value_cansleep( |
| flashdata->gpio_conf->gpio_num_info->gpio_num[1], |
| GPIO_OUT_LOW); |
| |
| return rc; |
| } |
| |
| int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl) |
| { |
| int rc = 0; |
| struct msm_camera_sensor_board_info *flashdata = NULL; |
| CDBG("%s:%d called\n", __func__, __LINE__); |
| |
| flashdata = fctrl->flashdata; |
| gpio_set_value_cansleep( |
| flashdata->gpio_conf->gpio_num_info->gpio_num[0], |
| GPIO_OUT_HIGH); |
| |
| gpio_set_value_cansleep( |
| flashdata->gpio_conf->gpio_num_info->gpio_num[1], |
| GPIO_OUT_HIGH); |
| |
| |
| if (fctrl->flash_i2c_client && fctrl->reg_setting) { |
| rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( |
| fctrl->flash_i2c_client, |
| fctrl->reg_setting->low_setting); |
| if (rc < 0) |
| pr_err("%s:%d failed\n", __func__, __LINE__); |
| } |
| |
| return rc; |
| } |
| |
| int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl) |
| { |
| int rc = 0; |
| struct msm_camera_sensor_board_info *flashdata = NULL; |
| CDBG("%s:%d called\n", __func__, __LINE__); |
| |
| flashdata = fctrl->flashdata; |
| gpio_set_value_cansleep( |
| flashdata->gpio_conf->gpio_num_info->gpio_num[0], |
| GPIO_OUT_HIGH); |
| |
| gpio_set_value_cansleep( |
| flashdata->gpio_conf->gpio_num_info->gpio_num[1], |
| GPIO_OUT_HIGH); |
| |
| if (fctrl->flash_i2c_client && fctrl->reg_setting) { |
| rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( |
| fctrl->flash_i2c_client, |
| fctrl->reg_setting->high_setting); |
| if (rc < 0) |
| pr_err("%s:%d failed\n", __func__, __LINE__); |
| } |
| |
| return rc; |
| } |
| |
| static int32_t msm_flash_init_gpio_pin_tbl(struct device_node *of_node, |
| struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, |
| uint16_t gpio_array_size) |
| { |
| int32_t rc = 0; |
| int32_t val = 0; |
| |
| gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info), |
| GFP_KERNEL); |
| if (!gconf->gpio_num_info) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| rc = -ENOMEM; |
| return rc; |
| } |
| |
| rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val); |
| if (rc < 0) { |
| pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n", |
| __func__, __LINE__, rc); |
| goto ERROR; |
| } else if (val >= gpio_array_size) { |
| pr_err("%s:%d qcom,gpio-flash-en invalid %d\n", |
| __func__, __LINE__, val); |
| goto ERROR; |
| } |
| /*index 0 is for qcom,gpio-flash-en */ |
| gconf->gpio_num_info->gpio_num[0] = |
| gpio_array[val]; |
| CDBG("%s qcom,gpio-flash-en %d\n", __func__, |
| gconf->gpio_num_info->gpio_num[0]); |
| |
| rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val); |
| if (rc < 0) { |
| pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n", |
| __func__, __LINE__, rc); |
| goto ERROR; |
| } else if (val >= gpio_array_size) { |
| pr_err("%s:%d qcom,gpio-flash-now invalid %d\n", |
| __func__, __LINE__, val); |
| goto ERROR; |
| } |
| /*index 1 is for qcom,gpio-flash-now */ |
| gconf->gpio_num_info->gpio_num[1] = |
| gpio_array[val]; |
| CDBG("%s qcom,gpio-flash-now %d\n", __func__, |
| gconf->gpio_num_info->gpio_num[1]); |
| |
| return rc; |
| |
| ERROR: |
| kfree(gconf->gpio_num_info); |
| gconf->gpio_num_info = NULL; |
| return rc; |
| } |
| |
| static int32_t msm_led_get_dt_data(struct device_node *of_node, |
| struct msm_led_flash_ctrl_t *fctrl) |
| { |
| int32_t rc = 0, i = 0; |
| struct msm_camera_gpio_conf *gconf = NULL; |
| struct device_node *flash_src_node = NULL; |
| struct msm_camera_sensor_board_info *flashdata = NULL; |
| uint32_t count = 0; |
| uint16_t *gpio_array = NULL; |
| uint16_t gpio_array_size = 0; |
| uint32_t id_info[3]; |
| |
| CDBG("called\n"); |
| |
| if (!of_node) { |
| pr_err("of_node NULL\n"); |
| return -EINVAL; |
| } |
| |
| fctrl->flashdata = kzalloc(sizeof( |
| struct msm_camera_sensor_board_info), |
| GFP_KERNEL); |
| if (!fctrl->flashdata) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| return -ENOMEM; |
| } |
| |
| flashdata = fctrl->flashdata; |
| |
| flashdata->sensor_init_params = kzalloc(sizeof( |
| struct msm_sensor_init_params), GFP_KERNEL); |
| if (!flashdata->sensor_init_params) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| return -ENOMEM; |
| } |
| |
| rc = of_property_read_u32(of_node, "cell-index", &fctrl->subdev_id); |
| if (rc < 0) { |
| pr_err("failed\n"); |
| return -EINVAL; |
| } |
| |
| CDBG("subdev id %d\n", fctrl->subdev_id); |
| |
| rc = of_property_read_string(of_node, "qcom,flash-name", |
| &flashdata->sensor_name); |
| CDBG("%s qcom,flash-name %s, rc %d\n", __func__, |
| flashdata->sensor_name, rc); |
| if (rc < 0) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| goto ERROR1; |
| } |
| |
| if (of_get_property(of_node, "qcom,flash-source", &count)) { |
| count /= sizeof(uint32_t); |
| CDBG("count %d\n", count); |
| if (count > MAX_LED_TRIGGERS) { |
| pr_err("failed\n"); |
| return -EINVAL; |
| } |
| for (i = 0; i < count; i++) { |
| flash_src_node = of_parse_phandle(of_node, |
| "qcom,flash-source", i); |
| if (!flash_src_node) { |
| pr_err("flash_src_node NULL\n"); |
| continue; |
| } |
| |
| rc = of_property_read_string(flash_src_node, |
| "linux,default-trigger", |
| &fctrl->flash_trigger_name[i]); |
| if (rc < 0) { |
| pr_err("failed\n"); |
| of_node_put(flash_src_node); |
| continue; |
| } |
| |
| CDBG("default trigger %s\n", |
| fctrl->flash_trigger_name[i]); |
| |
| rc = of_property_read_u32(flash_src_node, |
| "qcom,max-current", |
| &fctrl->flash_op_current[i]); |
| if (rc < 0) { |
| pr_err("failed rc %d\n", rc); |
| of_node_put(flash_src_node); |
| continue; |
| } |
| |
| of_node_put(flash_src_node); |
| |
| CDBG("max_current[%d] %d\n", |
| i, fctrl->flash_op_current[i]); |
| |
| led_trigger_register_simple( |
| fctrl->flash_trigger_name[i], |
| &fctrl->flash_trigger[i]); |
| } |
| |
| } else { /*Handle LED Flash Ctrl by GPIO*/ |
| flashdata->gpio_conf = |
| kzalloc(sizeof(struct msm_camera_gpio_conf), |
| GFP_KERNEL); |
| if (!flashdata->gpio_conf) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| rc = -ENOMEM; |
| return rc; |
| } |
| gconf = flashdata->gpio_conf; |
| |
| gpio_array_size = of_gpio_count(of_node); |
| CDBG("%s gpio count %d\n", __func__, gpio_array_size); |
| |
| if (gpio_array_size) { |
| gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, |
| GFP_KERNEL); |
| if (!gpio_array) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| rc = -ENOMEM; |
| goto ERROR4; |
| } |
| for (i = 0; i < gpio_array_size; i++) { |
| gpio_array[i] = of_get_gpio(of_node, i); |
| CDBG("%s gpio_array[%d] = %d\n", __func__, i, |
| gpio_array[i]); |
| } |
| |
| rc = msm_sensor_get_dt_gpio_req_tbl(of_node, gconf, |
| gpio_array, gpio_array_size); |
| if (rc < 0) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| goto ERROR4; |
| } |
| |
| rc = msm_sensor_get_dt_gpio_set_tbl(of_node, gconf, |
| gpio_array, gpio_array_size); |
| if (rc < 0) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| goto ERROR5; |
| } |
| |
| rc = msm_flash_init_gpio_pin_tbl(of_node, gconf, |
| gpio_array, gpio_array_size); |
| if (rc < 0) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| goto ERROR6; |
| } |
| } |
| |
| flashdata->slave_info = |
| kzalloc(sizeof(struct msm_camera_slave_info), |
| GFP_KERNEL); |
| if (!flashdata->slave_info) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| rc = -ENOMEM; |
| goto ERROR8; |
| } |
| |
| rc = of_property_read_u32_array(of_node, "qcom,slave-id", |
| id_info, 3); |
| if (rc < 0) { |
| pr_err("%s failed %d\n", __func__, __LINE__); |
| goto ERROR9; |
| } |
| fctrl->flashdata->slave_info->sensor_slave_addr = id_info[0]; |
| fctrl->flashdata->slave_info->sensor_id_reg_addr = id_info[1]; |
| fctrl->flashdata->slave_info->sensor_id = id_info[2]; |
| |
| kfree(gpio_array); |
| return rc; |
| ERROR9: |
| kfree(fctrl->flashdata->slave_info); |
| ERROR8: |
| kfree(fctrl->flashdata->gpio_conf->gpio_num_info); |
| ERROR6: |
| kfree(gconf->cam_gpio_set_tbl); |
| ERROR5: |
| kfree(gconf->cam_gpio_req_tbl); |
| ERROR4: |
| kfree(gconf); |
| ERROR1: |
| kfree(fctrl->flashdata); |
| kfree(gpio_array); |
| } |
| return rc; |
| } |
| |
| static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { |
| .i2c_read = msm_camera_qup_i2c_read, |
| .i2c_read_seq = msm_camera_qup_i2c_read_seq, |
| .i2c_write = msm_camera_qup_i2c_write, |
| .i2c_write_table = msm_camera_qup_i2c_write_table, |
| .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, |
| .i2c_write_table_w_microdelay = |
| msm_camera_qup_i2c_write_table_w_microdelay, |
| }; |
| |
| #ifdef CONFIG_DEBUG_FS |
| static int set_led_status(void *data, u64 val) |
| { |
| struct msm_led_flash_ctrl_t *fctrl = |
| (struct msm_led_flash_ctrl_t *)data; |
| int rc = -1; |
| pr_debug("set_led_status: Enter val: %llu", val); |
| if (!fctrl) { |
| pr_err("set_led_status: fctrl is NULL"); |
| return rc; |
| } |
| if (!fctrl->func_tbl) { |
| pr_err("set_led_status: fctrl->func_tbl is NULL"); |
| return rc; |
| } |
| if (val == 0) { |
| pr_debug("set_led_status: val is disable"); |
| rc = msm_flash_led_off(fctrl); |
| } else { |
| pr_debug("set_led_status: val is enable"); |
| rc = msm_flash_led_low(fctrl); |
| } |
| |
| return rc; |
| } |
| |
| DEFINE_SIMPLE_ATTRIBUTE(ledflashdbg_fops, |
| NULL, set_led_status, "%llu\n"); |
| #endif |
| |
| int msm_flash_i2c_probe(struct i2c_client *client, |
| const struct i2c_device_id *id) |
| { |
| int rc = 0; |
| struct msm_led_flash_ctrl_t *fctrl = NULL; |
| #ifdef CONFIG_DEBUG_FS |
| struct dentry *dentry; |
| #endif |
| if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { |
| pr_err("i2c_check_functionality failed\n"); |
| goto probe_failure; |
| } |
| |
| fctrl = (struct msm_led_flash_ctrl_t *)(id->driver_data); |
| if (fctrl->flash_i2c_client) |
| fctrl->flash_i2c_client->client = client; |
| /* Set device type as I2C */ |
| fctrl->flash_device_type = MSM_CAMERA_I2C_DEVICE; |
| |
| /* Assign name for sub device */ |
| snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name), |
| "%s", id->name); |
| |
| rc = msm_led_get_dt_data(client->dev.of_node, fctrl); |
| if (rc < 0) { |
| pr_err("%s failed line %d\n", __func__, __LINE__); |
| return rc; |
| } |
| if (fctrl->flash_i2c_client != NULL) { |
| fctrl->flash_i2c_client->client = client; |
| if (fctrl->flashdata->slave_info->sensor_slave_addr) |
| fctrl->flash_i2c_client->client->addr = |
| fctrl->flashdata->slave_info-> |
| sensor_slave_addr; |
| } else { |
| pr_err("%s %s sensor_i2c_client NULL\n", |
| __func__, client->name); |
| rc = -EFAULT; |
| return rc; |
| } |
| |
| if (!fctrl->flash_i2c_client->i2c_func_tbl) |
| fctrl->flash_i2c_client->i2c_func_tbl = |
| &msm_sensor_qup_func_tbl; |
| |
| rc = msm_led_i2c_flash_create_v4lsubdev(fctrl); |
| #ifdef CONFIG_DEBUG_FS |
| dentry = debugfs_create_file("ledflash", S_IRUGO, NULL, (void *)fctrl, |
| &ledflashdbg_fops); |
| if (!dentry) |
| pr_err("Failed to create the debugfs ledflash file"); |
| #endif |
| CDBG("%s:%d probe success\n", __func__, __LINE__); |
| return 0; |
| |
| probe_failure: |
| CDBG("%s:%d probe failed\n", __func__, __LINE__); |
| return rc; |
| } |