Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d21af77 authored by Lei Wang's avatar Lei Wang Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: flash: enable ov6211 eye-tracking camera


LED torch mode

Add interface for gpio flash support in device tree,
and add logic codes to require gpios info .And  pull up
the related gpios when open flash and pull down them when
close flash.

CRs-Fixed: 2589042.

Change-Id: I387df78fedebdca94ab6e8fe87e63e966c1cb50d
Signed-off-by: default avatarLei Wang <wangwanglei@codeaurora.org>
parent d484105d
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -39,7 +39,16 @@
		flash-source = <&pm660l_flash2>;
		torch-source = <&pm660l_torch2>;
		switch-source = <&pm660l_switch1>;
		status = "disabled";
		gpios = <&tlmm 0 0>,
			<&tlmm 1 0>,
			<&tlmm 23 0>;
		gpio-req-tbl-num = <0 1 2>;
		gpio-req-tbl-flags = <0 0 0>;
		gpio-req-tbl-label = "TCKING_LED_3V3_EN",
					"TCKING_LED_1V2_EN",
					"TCKing_LED_EN";
		gpio-req-tbl-delay = <20 20 20>;
		status = "ok";
	};

	actuator_regulator: gpio-regulator@0 {
@@ -350,6 +359,7 @@
		sensor-position-roll = <270>;
		sensor-position-pitch = <0>;
		sensor-position-yaw = <180>;
		led-flash-src = <&led_flash_front>;
		cam_vio-supply = <&pm660_l14>;
		cam_vana-supply = <&pm660l_l3>;
		cam_vdig-supply = <&pm660_l12>;
+10 −10
Original line number Diff line number Diff line
@@ -39,6 +39,12 @@
		flash-source = <&pmi8998_flash2>;
		torch-source = <&pmi8998_torch2>;
		switch-source = <&pmi8998_switch1>;
		gpios = <&tlmm 90 0>,
			<&tlmm 40 0>;
		gpio-req-tbl-num = <0 1>;
		gpio-req-tbl-flags = <0 0>;
		gpio-req-tbl-label = "FLASH_EN",
			"FLASH_NOW";
		status = "ok";
	};

@@ -408,22 +414,16 @@
		gpios = <&tlmm 13 0>,
			<&tlmm 26 0>,
			<&tlmm 132 0>,
			<&tlmm 133 0>,
			<&tlmm 90 0>,
			<&tlmm 40 0>;
			<&tlmm 133 0>;
		gpio-reset = <1>;
		gpio-vana = <2>;
		gpio-vdig = <3>;
		gpio-vio = <4>;
		gpio-standby = <5>;
		gpio-req-tbl-num = <0 1 2 3 4 5>;
		gpio-req-tbl-flags = <1 0 0 0 0 0>;
		gpio-req-tbl-num = <0 1 2 3>;
		gpio-req-tbl-flags = <1 0 0 0>;
		gpio-req-tbl-label = "CAMIF_MCLK0",
					"CAM_RESET2",
					"CAM_VANA2",
					"CAM_VDIG2",
					"CAM_VIO2",
					"CAM_STANDBY2";
					"CAM_VDIG2";
		sensor-mode = <0>;
		cci-master = <0>;
		status = "ok";
+42 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 */

#include <linux/module.h>
#include <linux/gpio.h>

#include "cam_sensor_cmn_header.h"
#include "cam_flash_core.h"
@@ -380,6 +381,45 @@ int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush)
	return rc;
}

static void cam_flash_set_gpios(struct cam_flash_ctrl *flash_ctrl, bool enable)
{

	struct cam_flash_private_soc *soc_private =
		(struct cam_flash_private_soc *) flash_ctrl->soc_info
		.soc_private;
	struct cam_soc_gpio_data *gpio_conf = soc_private->gpio_data;
	int i;

	if (gpio_conf != NULL && gpio_conf->cam_gpio_common_tbl_size > 0) {
		struct gpio *gpio_tbl = gpio_conf->cam_gpio_req_tbl;
		int size = (int) gpio_conf->cam_gpio_req_tbl_size;

		if (enable) {
			for (i = 0; i < size; i++) {
				CAM_DBG(CAM_FLASH, "enabling gpio %d",
					gpio_tbl[i].gpio);
				gpio_set_value_cansleep(gpio_tbl[i].gpio, 1);
				if (soc_private->gpio_delay_tbl_size > 0) {
					CAM_DBG(CAM_FLASH, "sleeping for %d ms",
						soc_private->gpio_delay_tbl[i]);
					msleep(soc_private->gpio_delay_tbl[i]);
				}
			}
		} else {
			for (i = size-1; i >= 0; i--) {
				CAM_DBG(CAM_FLASH, "disabling gpio %d",
					gpio_tbl[i].gpio);
				gpio_set_value_cansleep(gpio_tbl[i].gpio, 0);
				if (soc_private->gpio_delay_tbl_size > 0) {
					CAM_DBG(CAM_FLASH, "sleeping for %d ms",
						soc_private->gpio_delay_tbl[i]);
					msleep(soc_private->gpio_delay_tbl[i]);
				}
			}
		}
	}
}

static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl,
	struct cam_flash_frame_setting *flash_data, enum camera_flash_opcode op)
{
@@ -396,6 +436,7 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl,
		flash_ctrl->soc_info.soc_private;

	if (op == CAMERA_SENSOR_FLASH_OP_FIRELOW) {
		cam_flash_set_gpios(flash_ctrl, true);
		for (i = 0; i < flash_ctrl->torch_num_sources; i++) {
			if (flash_ctrl->torch_trigger[i]) {
				max_current = soc_private->torch_max_current[i];
@@ -455,6 +496,7 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl)
		cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger,
			(enum led_brightness)LED_SWITCH_OFF);

	cam_flash_set_gpios(flash_ctrl, false);
	flash_ctrl->flash_state = CAM_FLASH_STATE_START;
	return 0;
}
+6 −0
Original line number Diff line number Diff line
@@ -136,6 +136,9 @@ struct cam_flash_frame_setting {
 * @torch_trigger_name  : Torch trigger name array
 * @torch_op_current    : Torch operational current
 * @torch_max_current   : Max supported current for LED in torch mode
 * @gpio_data           : GPIO info
 * @gpio_delay_tbl      : Sleep times after enabling/disabling GPIOs
 * @gpio_delay_tbl_size : Number of elements in cam_gpio_delay_tbl
 */

struct cam_flash_private_soc {
@@ -147,6 +150,9 @@ struct cam_flash_private_soc {
	const char   *torch_trigger_name[CAM_FLASH_MAX_LED_TRIGGERS];
	uint32_t     torch_op_current[CAM_FLASH_MAX_LED_TRIGGERS];
	uint32_t     torch_max_current[CAM_FLASH_MAX_LED_TRIGGERS];
	struct cam_soc_gpio_data *gpio_data;
	uint32_t     *gpio_delay_tbl;
	uint8_t      gpio_delay_tbl_size;
};

struct cam_flash_func_tbl {
+267 −1
Original line number Diff line number Diff line
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2019, 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
@@ -15,6 +15,262 @@
#include "cam_flash_soc.h"
#include "cam_res_mgr_api.h"

static int cam_flash_get_dt_gpio_req_tbl(struct device_node *of_node,
	struct cam_soc_gpio_data *gconf,
	uint16_t *gpio_array,
	uint16_t gpio_array_size)
{
	int32_t rc = 0, i = 0;
	uint32_t count = 0;
	uint32_t *val_array = NULL;

	if (!of_get_property(of_node, "gpio-req-tbl-num", &count))
		return 0;

	count /= sizeof(uint32_t);
	if (!count) {
		CAM_DBG(CAM_FLASH, "gpio-req-tbl-num 0");
		return 0;
	}

	val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
	if (!val_array)
		return -ENOMEM;

	gconf->cam_gpio_req_tbl = kcalloc(count, sizeof(struct gpio),
		GFP_KERNEL);
	if (!gconf->cam_gpio_req_tbl) {
		rc = -ENOMEM;
		goto free_val_array;
	}
	gconf->cam_gpio_req_tbl_size = count;

	rc = of_property_read_u32_array(of_node, "gpio-req-tbl-num",
		val_array, count);
	if (rc) {
		CAM_ERR(CAM_FLASH,
			"failed in reading gpio-req-tbl-num, rc = %d",
			rc);
		goto free_gpio_req_tbl;
	}

	for (i = 0; i < count; i++) {
		if (val_array[i] >= gpio_array_size) {
			CAM_ERR(CAM_FLASH, "gpio req tbl index %d invalid",
				val_array[i]);
			goto free_gpio_req_tbl;
		}
		gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]];
		CAM_DBG(CAM_FLASH, "cam_gpio_req_tbl[%d].gpio = %d", i,
			gconf->cam_gpio_req_tbl[i].gpio);
	}

	rc = of_property_read_u32_array(of_node, "gpio-req-tbl-flags",
		val_array, count);
	if (rc) {
		CAM_ERR(CAM_FLASH, "Failed in gpio-req-tbl-flags, rc %d", rc);
		goto free_gpio_req_tbl;
	}

	for (i = 0; i < count; i++) {
		gconf->cam_gpio_req_tbl[i].flags = val_array[i];
		CAM_DBG(CAM_FLASH, "cam_gpio_req_tbl[%d].flags = %ld", i,
			gconf->cam_gpio_req_tbl[i].flags);
	}

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node,
			"gpio-req-tbl-label", i,
			&gconf->cam_gpio_req_tbl[i].label);
		if (rc) {
			CAM_ERR(CAM_FLASH, "Failed rc %d", rc);
			goto free_gpio_req_tbl;
		}
		CAM_DBG(CAM_FLASH, "cam_gpio_req_tbl[%d].label = %s", i,
			gconf->cam_gpio_req_tbl[i].label);
	}

	kfree(val_array);

	return rc;

free_gpio_req_tbl:
	kfree(gconf->cam_gpio_req_tbl);
free_val_array:
	kfree(val_array);
	gconf->cam_gpio_req_tbl_size = 0;

	return rc;
}

static int cam_flash_get_dt_gpio_delay_tbl(
	struct device_node *of_node, struct cam_flash_private_soc *soc_private)
{
	int32_t rc = 0, i = 0;
	uint32_t *val_array = NULL;
	uint32_t count = 0;

	soc_private->gpio_delay_tbl_size = 0;

	if (!of_get_property(of_node, "gpio-req-tbl-delay", &count))
		return 0;

	count /= sizeof(uint32_t);
	if (!count) {
		CAM_ERR(CAM_FLASH, "gpio-req-tbl-delay 0");
		return 0;
	}

	if (count != soc_private->gpio_data->cam_gpio_req_tbl_size) {
		CAM_ERR(CAM_FLASH,
			"Invalid number of gpio-req-tbl-delay entries: %d",
			count);
		return 0;
	}

	val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
	if (!val_array)
		return -ENOMEM;

	soc_private->gpio_delay_tbl_size = count;

	rc = of_property_read_u32_array(of_node, "gpio-req-tbl-delay",
		val_array, count);
	if (rc) {
		CAM_ERR(CAM_FLASH, "Failed in gpio-req-tbl-delay, rc %d", rc);
		goto free_val_array;
	}

	soc_private->gpio_delay_tbl = val_array;

	for (i = 0; i < count; i++) {
		CAM_DBG(CAM_FLASH, "gpio_delay_tbl[%d] = %ld", i,
			soc_private->gpio_delay_tbl[i]);
	}

	return 0;

free_val_array:
	kfree(val_array);
	soc_private->gpio_delay_tbl_size = 0;
	return rc;
}

static int cam_flash_get_gpio_info(
	struct device_node *of_node,
	struct cam_flash_private_soc *soc_private)
{
	int32_t rc = 0, i = 0;
	uint16_t *gpio_array = NULL;
	int16_t gpio_array_size = 0;
	struct cam_soc_gpio_data *gconf = NULL;

	gpio_array_size = of_gpio_count(of_node);

	CAM_DBG(CAM_FLASH, "gpio count %d", gpio_array_size);
	if (gpio_array_size <= 0)
		return 0;

	gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), GFP_KERNEL);
	if (!gpio_array)
		goto free_gpio_conf;

	for (i = 0; i < gpio_array_size; i++) {
		gpio_array[i] = of_get_gpio(of_node, i);
		CAM_DBG(CAM_FLASH, "gpio_array[%d] = %d", i, gpio_array[i]);
	}

	gconf = kzalloc(sizeof(*gconf), GFP_KERNEL);
	if (!gconf)
		return -ENOMEM;

	rc = cam_flash_get_dt_gpio_req_tbl(of_node, gconf, gpio_array,
		gpio_array_size);
	if (rc) {
		CAM_ERR(CAM_FLASH, "failed in msm_camera_get_dt_gpio_req_tbl");
		goto free_gpio_array;
	}

	gconf->cam_gpio_common_tbl = kcalloc(gpio_array_size,
		sizeof(struct gpio), GFP_KERNEL);
	if (!gconf->cam_gpio_common_tbl) {
		rc = -ENOMEM;
		goto free_gpio_array;
	}

	for (i = 0; i < gpio_array_size; i++)
		gconf->cam_gpio_common_tbl[i].gpio = gpio_array[i];

	gconf->cam_gpio_common_tbl_size = gpio_array_size;
	soc_private->gpio_data = gconf;
	kfree(gpio_array);

	cam_flash_get_dt_gpio_delay_tbl(of_node, soc_private);

	return rc;

free_gpio_array:
	kfree(gpio_array);
free_gpio_conf:
	kfree(gconf);
	soc_private->gpio_data = NULL;

	return rc;
}

static int cam_flash_request_gpio_table(
	struct cam_flash_private_soc *soc_private, bool gpio_en)
{
	int rc = 0, i = 0;
	uint8_t size = 0;
	struct cam_soc_gpio_data *gpio_conf =
		soc_private->gpio_data;
	struct gpio *gpio_tbl = NULL;

	if (!gpio_conf) {
		CAM_DBG(CAM_FLASH, "No GPIO entry");
		return 0;
	}
	if (gpio_conf->cam_gpio_common_tbl_size <= 0) {
		CAM_ERR(CAM_FLASH, "GPIO table size is invalid");
		return -EINVAL;
	}
	size = gpio_conf->cam_gpio_req_tbl_size;
	gpio_tbl = gpio_conf->cam_gpio_req_tbl;

	if (!gpio_tbl || !size) {
		CAM_ERR(CAM_FLASH, "Invalid gpio_tbl %pK / size %d",
			gpio_tbl, size);
		return -EINVAL;
	}
	for (i = 0; i < size; i++) {
		CAM_DBG(CAM_FLASH,
			"cam_flash_request_gpio_table: i=%d, gpio=%d dir=%ld",
			i,
			gpio_tbl[i].gpio,
			gpio_tbl[i].flags);
	}
	if (gpio_en) {
		for (i = 0; i < size; i++) {
			rc = gpio_request_one(gpio_tbl[i].gpio,
				gpio_tbl[i].flags, gpio_tbl[i].label);
			if (rc) {
				/*
				 * After GPIO request fails, contine to
				 * apply new gpios, outout a error message
				 * for driver bringup debug
				 */
				CAM_ERR(CAM_FLASH, "gpio %d:%s request fails",
					gpio_tbl[i].gpio, gpio_tbl[i].label);
			}
		}
	} else {
		gpio_free_array(gpio_tbl, size);
	}

	return rc;
}

static int32_t cam_get_source_node_info(
	struct device_node *of_node,
	struct cam_flash_ctrl *fctrl,
@@ -179,6 +435,15 @@ static int32_t cam_get_source_node_info(
		}
	}

	(void) cam_flash_get_gpio_info(of_node, soc_private);
	if (soc_private->gpio_data != NULL) {
		rc = cam_flash_request_gpio_table(soc_private, true);
		if (rc < 0)
			CAM_ERR(CAM_FLASH,
			"Failed in request gpio table, rc=%d",
			rc);
	}

	return rc;
}

@@ -216,6 +481,7 @@ int cam_flash_get_dt_data(struct cam_flash_ctrl *fctrl,
	return rc;

free_soc_private:
	cam_flash_request_gpio_table(soc_info->soc_private, false);
	kfree(soc_info->soc_private);
	soc_info->soc_private = NULL;
release_soc_res: