Эх сурвалжийг харах

msm: camera: sensor: debugfs utility for i2c/cci

This change adds support to read/write any sensor
devices that are on i2c, whether using cci or qup.
The debugfs file is mounted on i2c subdir under
camera root directory in debugfs.

Given that these devices are not always turned on,
and that this power on/off sequence is controlled
by userspace, this change displays all available
i2c devices, and their power states.

The user then can read/write to those devices which
are turned on, according to the following:

Usage:
  - echo (anything or empty string) > i2c-rw
  - cat i2c-rw then displays usage, and states of devices
  - echo (proper r/w format) > i2c-rw
  - cat i2c-rw displays output/error
Note that cat output is not persistent, it gets cleared
after displaying once.

CRs-Fixed: 3385104
Change-Id: I22023e0a8d9a680b5c8578cae2aa253c4c90226f
Signed-off-by: Li Sha Lim <[email protected]>
Li Sha Lim 3 жил өмнө
parent
commit
8e7b72d937

+ 2 - 1
Kbuild

@@ -258,7 +258,8 @@ camera-$(CONFIG_SPECTRA_SENSOR) += \
 	drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.o \
 	drivers/cam_sensor_module/cam_flash/cam_flash_dev.o \
 	drivers/cam_sensor_module/cam_flash/cam_flash_core.o \
-	drivers/cam_sensor_module/cam_flash/cam_flash_soc.o
+	drivers/cam_sensor_module/cam_flash/cam_flash_soc.o \
+	drivers/cam_sensor_module/cam_sensor_module_debug.o
 
 camera-$(CONFIG_SPECTRA_CUSTOM) += \
 	drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.o \

+ 4 - 0
drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c

@@ -238,6 +238,8 @@ static int cam_actuator_i2c_component_bind(struct device *dev,
 		goto unreg_subdev;
 	}
 
+	cam_sensor_module_add_i2c_device((void *) a_ctrl, CAM_SENSOR_ACTUATOR);
+
 	INIT_LIST_HEAD(&(a_ctrl->i2c_data.init_settings.list_head));
 
 	for (i = 0; i < MAX_PER_FRAME_ARRAY; i++)
@@ -395,6 +397,8 @@ static int cam_actuator_platform_component_bind(struct device *dev,
 		goto free_soc;
 	}
 
+	cam_sensor_module_add_i2c_device((void *) a_ctrl, CAM_SENSOR_ACTUATOR);
+
 	INIT_LIST_HEAD(&(a_ctrl->i2c_data.init_settings.list_head));
 
 	for (i = 0; i < MAX_PER_FRAME_ARRAY; i++)

+ 5 - 1
drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include "cam_eeprom_dev.h"
@@ -249,6 +249,8 @@ static int cam_eeprom_i2c_component_bind(struct device *dev,
 	if (rc)
 		goto free_soc;
 
+	cam_sensor_module_add_i2c_device((void *) e_ctrl, CAM_SENSOR_EEPROM);
+
 	if (soc_private->i2c_info.slave_addr != 0)
 		e_ctrl->io_master_info.client->addr =
 			soc_private->i2c_info.slave_addr;
@@ -524,6 +526,8 @@ static int cam_eeprom_component_bind(struct device *dev,
 	if (rc)
 		goto free_soc;
 
+	cam_sensor_module_add_i2c_device((void *) e_ctrl, CAM_SENSOR_EEPROM);
+
 	e_ctrl->bridge_intf.device_hdl = -1;
 	e_ctrl->bridge_intf.ops.get_dev_info = NULL;
 	e_ctrl->bridge_intf.ops.link_setup = NULL;

+ 4 - 0
drivers/cam_sensor_module/cam_flash/cam_flash_dev.c

@@ -508,6 +508,8 @@ static int cam_flash_component_bind(struct device *dev,
 			goto free_resource;
 	}
 
+	cam_sensor_module_add_i2c_device((void *) fctrl, CAM_SENSOR_FLASH);
+
 	fctrl->bridge_intf.device_hdl = -1;
 	fctrl->bridge_intf.link_hdl = -1;
 	fctrl->bridge_intf.ops.get_dev_info = cam_flash_publish_dev_info;
@@ -675,6 +677,8 @@ static int cam_flash_i2c_component_bind(struct device *dev,
 		goto unreg_subdev;
 	}
 
+	cam_sensor_module_add_i2c_device((void *) fctrl, CAM_SENSOR_FLASH);
+
 	INIT_LIST_HEAD(&(fctrl->i2c_data.init_settings.list_head));
 	INIT_LIST_HEAD(&(fctrl->i2c_data.config_settings.list_head));
 	for (i = 0; i < MAX_PER_FRAME_ARRAY; i++)

+ 4 - 0
drivers/cam_sensor_module/cam_ois/cam_ois_dev.c

@@ -233,6 +233,8 @@ static int cam_ois_i2c_component_bind(struct device *dev,
 	if (rc)
 		goto soc_free;
 
+	cam_sensor_module_add_i2c_device((void *) o_ctrl, CAM_SENSOR_OIS);
+
 	o_ctrl->cam_ois_state = CAM_OIS_INIT;
 
 	return rc;
@@ -401,6 +403,8 @@ static int cam_ois_component_bind(struct device *dev,
 	}
 	o_ctrl->bridge_intf.device_hdl = -1;
 
+	cam_sensor_module_add_i2c_device((void *) o_ctrl, CAM_SENSOR_OIS);
+
 	platform_set_drvdata(pdev, o_ctrl);
 	o_ctrl->cam_ois_state = CAM_OIS_INIT;
 

+ 8 - 0
drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c

@@ -289,6 +289,8 @@ static int cam_sensor_i2c_component_bind(struct device *dev,
 		INIT_LIST_HEAD(&(s_ctrl->i2c_data.bubble_update[i].list_head));
 	}
 
+	cam_sensor_module_add_i2c_device((void *) s_ctrl, CAM_SENSOR_DEVICE);
+
 	s_ctrl->bridge_intf.device_hdl = -1;
 	s_ctrl->bridge_intf.link_hdl = -1;
 	s_ctrl->bridge_intf.ops.get_dev_info = cam_sensor_publish_dev_info;
@@ -477,6 +479,8 @@ static int cam_sensor_component_bind(struct device *dev,
 		INIT_LIST_HEAD(&(s_ctrl->i2c_data.bubble_update[i].list_head));
 	}
 
+	cam_sensor_module_add_i2c_device((void *) s_ctrl, CAM_SENSOR_DEVICE);
+
 	s_ctrl->bridge_intf.device_hdl = -1;
 	s_ctrl->bridge_intf.link_hdl = -1;
 	s_ctrl->bridge_intf.ops.get_dev_info = cam_sensor_publish_dev_info;
@@ -670,6 +674,8 @@ int cam_sensor_driver_init(void)
 		goto i3c_register_err;
 	}
 
+	cam_sensor_module_debug_register();
+
 	return 0;
 
 i3c_register_err:
@@ -694,6 +700,8 @@ void cam_sensor_driver_exit(void)
 	}
 
 	i3c_driver_unregister(&cam_sensor_i3c_driver);
+
+	cam_sensor_module_debug_deregister();
 }
 
 MODULE_DESCRIPTION("cam_sensor_driver");

+ 320 - 0
drivers/cam_sensor_module/cam_sensor_module_debug.c

@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/debugfs.h>
+#include <media/cam_sensor.h>
+#include "cam_debug_util.h"
+#include "cam_sensor_cmn_header.h"
+#include "cam_sensor_io.h"
+#include "cam_sensor_i2c.h"
+#include "cam_actuator_dev.h"
+#include "cam_eeprom_dev.h"
+#include "cam_flash_dev.h"
+#include "cam_ois_dev.h"
+#include "cam_sensor_dev.h"
+
+#define RW_BUFFER_SIZE          3000
+#define LINE_BUFFER_SIZE        150
+#define NUM_OF_READ_PARAMS      5
+#define NUM_OF_WRITE_PARAMS     7
+#define USAGE_STRING   "Read format: r/R, reg_addr(hex), addr_type, "\
+			       "data_type, device_type, instance_id (ID pair)\n"\
+			       "Write format: w/W, reg_addr(hex), addr_type, "\
+			       "reg_value(hex), delay, addr_type, data_type, device_type, "\
+				   "instance_id (ID pair)\n"
+
+struct cam_sensor_i2c_devices {
+	struct cam_actuator_ctrl_t *actuator[MAX_CAMERAS];
+	struct cam_eeprom_ctrl_t   *eeprom[MAX_CAMERAS];
+	struct cam_flash_ctrl      *flash[MAX_CAMERAS];
+	struct cam_ois_ctrl_t      *ois[MAX_CAMERAS];
+	struct cam_sensor_ctrl_t   *sensor[MAX_CAMERAS];
+	int num_actuator;
+	int num_eeprom;
+	int num_flash;
+	int num_ois;
+	int num_sensor;
+};
+
+static struct dentry *debugfs_root;
+static char in_buffer[RW_BUFFER_SIZE], out_buffer[RW_BUFFER_SIZE];
+static struct cam_sensor_i2c_devices devices = {0};
+
+struct camera_io_master *cam_sensor_module_get_io_master(
+	int device_type, int instance_number, bool *is_on)
+{
+	struct camera_io_master *io_master = NULL;
+	*is_on = false;
+
+	switch (device_type) {
+	case CAM_SENSOR_ACTUATOR:
+		io_master = instance_number >= devices.num_actuator ? NULL :
+			&devices.actuator[instance_number]->io_master_info;
+		if (io_master)
+			*is_on = devices.actuator[instance_number]->cam_act_state ==
+				CAM_ACTUATOR_CONFIG ? true : false;
+		break;
+	case CAM_SENSOR_EEPROM:
+		io_master = instance_number >= devices.num_eeprom ? NULL :
+			&devices.eeprom[instance_number]->io_master_info;
+		if (io_master)
+			*is_on = devices.eeprom[instance_number]->cam_eeprom_state ==
+				CAM_EEPROM_CONFIG ? true : false;
+		break;
+	case CAM_SENSOR_FLASH:
+		io_master = instance_number >= devices.num_flash ? NULL :
+			&devices.flash[instance_number]->io_master_info;
+		if (io_master)
+			*is_on = devices.flash[instance_number]->flash_state >=
+				CAM_FLASH_STATE_CONFIG ? true : false;
+		break;
+	case CAM_SENSOR_OIS:
+		io_master = instance_number >= devices.num_ois ? NULL :
+			&devices.ois[instance_number]->io_master_info;
+		if (io_master)
+			*is_on = devices.ois[instance_number]->cam_ois_state >=
+				CAM_OIS_CONFIG ? true : false;
+		break;
+	case CAM_SENSOR_DEVICE:
+		io_master = instance_number >= devices.num_sensor ? NULL :
+			&devices.sensor[instance_number]->io_master_info;
+		if (io_master)
+			*is_on = devices.sensor[instance_number]->sensor_state >=
+				CAM_SENSOR_ACQUIRE ? true : false;
+		break;
+	default:
+		CAM_WARN(CAM_SENSOR, "Unrecognized sensor device type: %d", device_type);
+		break;
+	}
+
+	return io_master;
+}
+
+static int cam_sensor_module_parse_line(const char *p_line,
+	struct cam_sensor_i2c_reg_setting *reg_list,
+	struct camera_io_master **io_master, bool *is_read,
+	bool *power_state)
+{
+	int device_type, instance_number, rc;
+	struct cam_sensor_i2c_reg_array *reg_array = reg_list->reg_setting;
+
+	if (!strlen(p_line))
+		return -EINVAL;
+
+	CAM_DBG(CAM_SENSOR, "Sensor debugfs string: %s", p_line);
+
+	if (p_line[0] == 'r' || p_line[0] == 'R') {
+		*is_read = true;
+
+		rc = sscanf(p_line+2, "%x,%d,%d,%d,%d",
+			&reg_array->reg_addr, &reg_list->addr_type, &reg_list->data_type,
+			&device_type, &instance_number);
+		if (rc == NUM_OF_READ_PARAMS) {
+			*io_master = cam_sensor_module_get_io_master(
+				device_type, instance_number, power_state);
+			return 0;
+		}
+	} else if (p_line[0] == 'w'  || p_line[0] == 'W') {
+		*is_read = false;
+
+		rc = sscanf(p_line+2, "%x,%x,%d,%d,%d,%d,%d",
+			&reg_array->reg_addr,  &reg_array->reg_data, &reg_array->delay,
+			&reg_list->addr_type, &reg_list->data_type,
+			&device_type, &instance_number);
+		if (rc == NUM_OF_WRITE_PARAMS) {
+			*io_master = cam_sensor_module_get_io_master(
+				device_type, instance_number, power_state);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static void cam_sensor_get_device_status(int offset)
+{
+	int i;
+	char line_buffer[LINE_BUFFER_SIZE], *start = out_buffer + offset;
+
+	for (i = 0; i < devices.num_actuator; i++) {
+		snprintf(line_buffer, LINE_BUFFER_SIZE,
+			"Device: %s, \t %u, state: %d, ID(device_type, instance_number): %d, %d\n",
+		devices.actuator[i]->device_name, devices.actuator[i]->soc_info.index,
+		devices.actuator[i]->cam_act_state, CAM_SENSOR_ACTUATOR, i);
+		strlcat(start, line_buffer, RW_BUFFER_SIZE - offset);
+	}
+	memset(line_buffer, '\0', LINE_BUFFER_SIZE);
+	for (i = 0; i < devices.num_eeprom; i++) {
+		snprintf(line_buffer, LINE_BUFFER_SIZE,
+			"Device: %s, \t\t %u, state: %d, ID(device_type, instance_number): %d, %d\n",
+		devices.eeprom[i]->device_name, devices.eeprom[i]->soc_info.index,
+		devices.eeprom[i]->cam_eeprom_state, CAM_SENSOR_EEPROM, i);
+		strlcat(start, line_buffer, RW_BUFFER_SIZE - offset);
+	}
+	memset(line_buffer, '\0', LINE_BUFFER_SIZE);
+	for (i = 0; i < devices.num_flash; i++) {
+		snprintf(line_buffer, LINE_BUFFER_SIZE,
+			"Device: %s, \t\t %u, state: %d, ID(device_type, instance_number): %d, %d\n",
+		devices.flash[i]->device_name, devices.flash[i]->soc_info.index,
+		devices.flash[i]->flash_state, CAM_SENSOR_FLASH, i);
+		strlcat(start, line_buffer, RW_BUFFER_SIZE - offset);
+	}
+	memset(line_buffer, '\0', LINE_BUFFER_SIZE);
+	for (i = 0; i < devices.num_ois; i++) {
+		snprintf(line_buffer, LINE_BUFFER_SIZE,
+			"Device: %s, \t\t %u, state: %d, ID(device_type, instance_number): %d, %d\n",
+		devices.ois[i]->device_name, devices.ois[i]->soc_info.index,
+		devices.ois[i]->cam_ois_state, CAM_SENSOR_OIS, i);
+		strlcat(start, line_buffer, RW_BUFFER_SIZE - offset);
+	}
+	memset(line_buffer, '\0', LINE_BUFFER_SIZE);
+	for (i = 0; i  < devices.num_sensor; i++) {
+		snprintf(line_buffer, LINE_BUFFER_SIZE,
+			"Device: %s, \t\t %u, state: %d, ID(device_type, instance_number): %d, %d\n",
+		devices.sensor[i]->sensor_name, devices.sensor[i]->soc_info.index,
+		devices.sensor[i]->sensor_state, CAM_SENSOR_DEVICE, i);
+		strlcat(start, line_buffer, RW_BUFFER_SIZE - offset);
+	}
+	memset(line_buffer, '\0', LINE_BUFFER_SIZE);
+}
+
+static ssize_t i2c_read(struct file *t_file, char __user *t_char,
+	size_t t_size_t, loff_t *t_loff_t)
+{
+	ssize_t count;
+
+	count = simple_read_from_buffer(t_char, t_size_t,
+		t_loff_t, out_buffer, RW_BUFFER_SIZE);
+	memset(out_buffer, '\0', RW_BUFFER_SIZE);
+
+	return count;
+}
+
+static ssize_t i2c_write(struct file *t_file, const char __user *t_char,
+	size_t t_size_t, loff_t *t_loff_t)
+{
+	ssize_t bytes_written = 0, rc = 0;
+	struct cam_sensor_i2c_reg_setting read_write;
+	struct cam_sensor_i2c_reg_array   reg_array;
+	struct camera_io_master *io_master = NULL;
+	char line_buffer[LINE_BUFFER_SIZE];
+	bool is_read, power_state;
+
+	memset(out_buffer, '\0', RW_BUFFER_SIZE);
+	memset(line_buffer, '\0', LINE_BUFFER_SIZE);
+	read_write.reg_setting = &reg_array;
+
+	bytes_written = simple_write_to_buffer(in_buffer, RW_BUFFER_SIZE - 1,
+		t_loff_t, t_char, t_size_t);
+
+	/* Turn it into a C string */
+	in_buffer[bytes_written + 1] = '\0';
+
+	rc = cam_sensor_module_parse_line(in_buffer, &read_write,
+		&io_master, &is_read, &power_state);
+
+	if (!rc) {
+		if (!power_state) {
+			snprintf(line_buffer, LINE_BUFFER_SIZE, "Dev not on");
+			goto end;
+		}
+		if (!is_read) {
+			read_write.size = 1;
+			rc = camera_io_dev_write(io_master, &read_write);
+			if (rc) {
+				snprintf(line_buffer, LINE_BUFFER_SIZE,
+					"Error: 0x%X, 0x%X, rc: %d\n",
+					read_write.reg_setting->reg_addr,
+					read_write.reg_setting->reg_data, rc);
+				strlcat(out_buffer, line_buffer, RW_BUFFER_SIZE);
+			}
+		} else {
+			rc = camera_io_dev_read(io_master,
+				read_write.reg_setting->reg_addr,
+				&read_write.reg_setting->reg_data, read_write.addr_type,
+				read_write.data_type, false);
+			if (!rc)
+				snprintf(line_buffer, LINE_BUFFER_SIZE, "Read data: 0x%X\n",
+					read_write.reg_setting->reg_data);
+			else
+				snprintf(line_buffer, LINE_BUFFER_SIZE, "Error, rc: %d\n", rc);
+			strlcat(out_buffer, line_buffer, RW_BUFFER_SIZE);
+		}
+	} else {
+		strscpy(out_buffer, USAGE_STRING, RW_BUFFER_SIZE);
+		cam_sensor_get_device_status(strlen(USAGE_STRING));
+	}
+
+end:
+	return bytes_written;
+}
+
+const struct file_operations i2c_operations = {
+	.open = simple_open,
+	.read = i2c_read,
+	.write = i2c_write,
+};
+
+void cam_sensor_module_add_i2c_device(void *ctrl_struct, int device_type)
+{
+	if (!cam_debugfs_available())
+		return;
+
+	CAM_INFO(CAM_SENSOR, "Adding device type: %d", device_type);
+
+	switch (device_type) {
+	case CAM_SENSOR_ACTUATOR:
+		devices.actuator[devices.num_actuator++] =
+			(struct cam_actuator_ctrl_t *) ctrl_struct;
+		break;
+	case CAM_SENSOR_EEPROM:
+		devices.eeprom[devices.num_eeprom++] =
+			(struct cam_eeprom_ctrl_t *) ctrl_struct;
+		break;
+	case CAM_SENSOR_FLASH:
+		devices.flash[devices.num_flash++] =
+			(struct cam_flash_ctrl *) ctrl_struct;
+		break;
+	case CAM_SENSOR_OIS:
+		devices.ois[devices.num_ois++] =
+			(struct cam_ois_ctrl_t *) ctrl_struct;
+		break;
+	case CAM_SENSOR_DEVICE:
+		devices.sensor[devices.num_sensor++] =
+			(struct cam_sensor_ctrl_t *) ctrl_struct;
+		break;
+	default:
+		CAM_WARN(CAM_SENSOR, "Unrecognized sensor device type: %d", device_type);
+		break;
+	}
+}
+
+int cam_sensor_module_debug_register(void)
+{
+	int rc = 0;
+	struct dentry *dbgfileptr = NULL;
+
+	if (!cam_debugfs_available())
+		return 0;
+
+	rc = cam_debugfs_create_subdir("i2c", &dbgfileptr);
+	if (rc) {
+		CAM_ERR(CAM_MEM, "DebugFS could not create directory!");
+		rc = -ENOENT;
+		goto end;
+	}
+
+	debugfs_root =  dbgfileptr;
+	debugfs_create_file("i2c-rw", 0644, debugfs_root,
+		NULL, &i2c_operations);
+
+end:
+	return rc;
+}
+
+void cam_sensor_module_debug_deregister(void)
+{
+	debugfs_root = NULL;
+}

+ 32 - 1
drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_SENSOR_CMN_HEADER_
@@ -208,6 +208,15 @@ struct cam_sensor_i2c_reg_array {
 	uint32_t data_mask;
 };
 
+enum cam_sensor_module_debugfs_device_type {
+	CAM_SENSOR_ACTUATOR,
+	CAM_SENSOR_EEPROM,
+	CAM_SENSOR_FLASH,
+	CAM_SENSOR_OIS,
+	CAM_SENSOR_DEVICE,
+	CAM_SENSOR_MAX,
+};
+
 struct cam_sensor_i2c_reg_setting {
 	struct cam_sensor_i2c_reg_array *reg_setting;
 	uint32_t size;
@@ -354,4 +363,26 @@ struct msm_camera_gpio_conf {
 	struct msm_camera_gpio_num_info *gpio_num_info;
 };
 
+/**
+ * cam_sensor_module_add_i2c_device()
+ * @brief: Each sensor device passes its ctrl struct to a global
+ *         structure of i2c devices in cam_sensor_module_debug.c
+ * @ctrl_struct: Passed as void pointer, and recast to actual struct
+ *               based on device_type
+ * @device_type: Device type based on cam_sensor_module_debugfs_device_type
+ */
+void cam_sensor_module_add_i2c_device(void *ctrl_struct, int device_type);
+
+/**
+ * cam_sensor_module_debug_register()
+ * @brief Creates debugfs entry
+ */
+int cam_sensor_module_debug_register(void);
+
+/**
+ * cam_sensor_module_debug_deregister(void)
+ * @brief Take down debugfs entry
+ */
+void cam_sensor_module_debug_deregister(void);
+
 #endif /* _CAM_SENSOR_CMN_HEADER_ */