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

Commit 8f047d48 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: flash: enable gpio-based flash"

parents 4ec8bf20 968b1092
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";
+51 −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"
@@ -21,6 +22,10 @@
static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl,
	bool regulator_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 rc = 0;

	if (!(flash_ctrl->switch_trigger)) {
@@ -48,6 +53,11 @@ static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl,
			return rc;
		}
		flash_ctrl->is_regulator_enabled = false;
	} else if ((gpio_conf != NULL) &&
		(gpio_conf->cam_gpio_common_tbl_size > 0)) {
		CAM_INFO(CAM_FLASH,
			"gpio based flash not need regulator");
		return rc;
	} else {
		CAM_ERR(CAM_FLASH, "Wrong Flash State : %d",
			flash_ctrl->flash_state);
@@ -380,6 +390,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 +445,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 +505,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: