msm: camera: sensor: Add i3c bus support

Add i3c bus support for qup i3c based
I3C target.

CRs-Fixed: 3169593
Change-Id: I0209f799d800daf9afe7a846310a3d4f4f2ee420
Signed-off-by: Jigarkumar Zala <quic_jzala@quicinc.com>
Signed-off-by: Jigar Agrawal <quic_jigar@quicinc.com>
This commit is contained in:
Jigar Agrawal
2022-05-05 14:07:15 -07:00
committed by Camera Software Integration
parent 17e95f5f2f
commit 609d228234
18 changed files with 953 additions and 129 deletions

1
Kbuild
View File

@@ -231,6 +231,7 @@ camera-$(CONFIG_SPECTRA_SENSOR) += \
drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.o \
drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.o \
drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.o \
drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i3c.o \
drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.o \
drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.o \
drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.o \

View File

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
@@ -86,6 +87,7 @@ struct actuator_intf_params {
* @cci_i2c_master: I2C structure
* @io_master_info: Information about the communication master
* @actuator_mutex: Actuator mutex
* @is_i3c_device : A Flag to indicate whether this actuator is I3C device
* @act_apply_state: Actuator settings aRegulator config
* @id: Cell Index
* @res_apply_state: Actuator settings apply state
@@ -106,6 +108,7 @@ struct cam_actuator_ctrl_t {
struct camera_io_master io_master_info;
struct cam_hw_soc_info soc_info;
struct mutex actuator_mutex;
bool is_i3c_device;
uint32_t id;
enum cam_actuator_apply_state_t setting_apply_state;
enum cam_actuator_state cam_act_state;

View File

@@ -1,6 +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.
*/
#include <linux/of.h>
@@ -34,6 +35,14 @@ int32_t cam_actuator_parse_dt(struct cam_actuator_ctrl_t *a_ctrl,
of_node = soc_info->dev->of_node;
rc = of_property_read_bool(of_node, "i3c-target");
if (rc) {
a_ctrl->is_i3c_device = true;
a_ctrl->io_master_info.master_type = I3C_MASTER;
}
CAM_DBG(CAM_SENSOR, "I3C Target: %s", CAM_BOOL_TO_YESNO(a_ctrl->is_i3c_device));
if (a_ctrl->io_master_info.master_type == CCI_MASTER) {
rc = of_property_read_u32(of_node, "cci-master",
&(a_ctrl->cci_i2c_master));

View File

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_EEPROM_DEV_H_
#define _CAM_EEPROM_DEV_H_
@@ -164,6 +165,7 @@ struct eebin_info {
* @gpio_num_info : gpio info
* @cci_i2c_master : I2C structure
* @v4l2_dev_str : V4L2 device structure
* @is_i3c_device : A flag to indicate whether this eeprom is I3C device
* @bridge_intf : bridge interface params
* @cam_eeprom_state : eeprom_device_state
* @userspace_probe : flag indicates userspace or kernel probe
@@ -184,6 +186,7 @@ struct cam_eeprom_ctrl_t {
enum cci_i2c_master_t cci_i2c_master;
enum cci_device_num cci_num;
struct cam_subdev v4l2_dev_str;
bool is_i3c_device;
struct cam_eeprom_intf_params bridge_intf;
enum msm_camera_device_type_t eeprom_device_type;
enum cam_eeprom_state cam_eeprom_state;

View File

@@ -1,6 +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.
*/
#include <linux/of.h>
@@ -304,6 +305,14 @@ int cam_eeprom_parse_dt(struct cam_eeprom_ctrl_t *e_ctrl)
of_node = soc_info->dev->of_node;
rc = of_property_read_bool(of_node, "i3c-target");
if (rc) {
e_ctrl->is_i3c_device = true;
e_ctrl->io_master_info.master_type = I3C_MASTER;
}
CAM_DBG(CAM_SENSOR, "I3C Target: %s", CAM_BOOL_TO_YESNO(e_ctrl->is_i3c_device));
if (of_property_read_bool(of_node, "multimodule-support")) {
CAM_DBG(CAM_UTIL, "Multi Module is Supported");
e_ctrl->is_multimodule_mode = true;

View File

@@ -1,6 +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.
*/
#ifndef _CAM_OIS_DEV_H_
#define _CAM_OIS_DEV_H_
@@ -93,6 +94,7 @@ struct cam_ois_intf_params {
* @io_master_info : Information about the communication master
* @cci_i2c_master : I2C structure
* @v4l2_dev_str : V4L2 device structure
* @is_i3c_device : A Flag to indicate whether this OIS is I3C Device or not.
* @bridge_intf : bridge interface params
* @i2c_fwinit_data : ois i2c firmware init settings
* @i2c_init_data : ois i2c init settings
@@ -116,6 +118,7 @@ struct cam_ois_ctrl_t {
enum cci_i2c_master_t cci_i2c_master;
enum cci_device_num cci_num;
struct cam_subdev v4l2_dev_str;
bool is_i3c_device;
struct cam_ois_intf_params bridge_intf;
struct i2c_settings_array i2c_fwinit_data;
struct i2c_settings_array i2c_init_data;

View File

@@ -1,6 +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.
*/
#include <linux/of.h>
@@ -41,6 +42,14 @@ static int cam_ois_get_dt_data(struct cam_ois_ctrl_t *o_ctrl)
return rc;
}
rc = of_property_read_bool(of_node, "i3c-target");
if (rc) {
o_ctrl->is_i3c_device = true;
o_ctrl->io_master_info.master_type = I3C_MASTER;
}
CAM_DBG(CAM_SENSOR, "I3C Target: %s", CAM_BOOL_TO_YESNO(o_ctrl->is_i3c_device));
/* Initialize regulators to default parameters */
for (i = 0; i < soc_info->num_rgltr; i++) {
soc_info->rgltr[i] = devm_regulator_get(soc_info->dev,
@@ -126,7 +135,6 @@ int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl)
o_ctrl->io_master_info.cci_client->cci_device = o_ctrl->cci_num;
CAM_DBG(CAM_OIS, "cci-device %d", o_ctrl->cci_num, rc);
}
rc = cam_ois_get_dt_data(o_ctrl);

View File

@@ -13,6 +13,7 @@
#include "cam_common_util.h"
#include "cam_packet_util.h"
extern struct completion *cam_sensor_get_i3c_completion(uint32_t index);
static int cam_sensor_update_req_mgr(
struct cam_sensor_ctrl_t *s_ctrl,
@@ -790,7 +791,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
struct cam_sensor_power_ctrl_t *power_info =
&s_ctrl->sensordata->power_info;
struct timespec64 ts;
struct completion *i3c_probe_completion;
uint64_t ms, sec, min, hrs;
long time_left;
if (!s_ctrl || !arg) {
CAM_ERR(CAM_SENSOR, "s_ctrl is NULL");
@@ -879,6 +882,21 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
goto free_power_settings;
}
}
if (s_ctrl->io_master_info.master_type == I3C_MASTER) {
i3c_probe_completion =
cam_sensor_get_i3c_completion(s_ctrl->soc_info.index);
time_left = cam_common_wait_for_completion_timeout(
i3c_probe_completion,
msecs_to_jiffies(CAM_SENSOR_I3C_PROBE_TIMEOUT_MS));
if (!time_left) {
CAM_ERR(CAM_SENSOR, "Wait for I3C probe timedout for %s",
s_ctrl->sensor_name);
return -ETIMEDOUT;
}
}
/* Match sensor ID */
rc = cam_sensor_match_id(s_ctrl);
if (rc < 0) {

View File

@@ -9,6 +9,17 @@
#include "cam_sensor_soc.h"
#include "cam_sensor_core.h"
#include "camera_main.h"
#include "cam_compat.h"
static struct cam_sensor_i3c_sensor_data {
struct cam_sensor_ctrl_t *s_ctrl;
struct completion probe_complete;
} g_i3c_sensor_data[MAX_CAMERAS];
struct completion *cam_sensor_get_i3c_completion(uint32_t index)
{
return &g_i3c_sensor_data[index].probe_complete;
}
static int cam_sensor_subdev_close_internal(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
@@ -136,21 +147,14 @@ static int cam_sensor_init_subdev_params(struct cam_sensor_ctrl_t *s_ctrl)
{
int rc = 0;
s_ctrl->v4l2_dev_str.internal_ops =
&cam_sensor_internal_ops;
s_ctrl->v4l2_dev_str.ops =
&cam_sensor_subdev_ops;
strlcpy(s_ctrl->device_name, CAMX_SENSOR_DEV_NAME,
sizeof(s_ctrl->device_name));
s_ctrl->v4l2_dev_str.name =
s_ctrl->device_name;
s_ctrl->v4l2_dev_str.sd_flags =
(V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
s_ctrl->v4l2_dev_str.ent_function =
CAM_SENSOR_DEVICE_TYPE;
s_ctrl->v4l2_dev_str.internal_ops = &cam_sensor_internal_ops;
s_ctrl->v4l2_dev_str.ops = &cam_sensor_subdev_ops;
strscpy(s_ctrl->device_name, CAMX_SENSOR_DEV_NAME, CAM_CTX_DEV_NAME_MAX_LENGTH);
s_ctrl->v4l2_dev_str.name = s_ctrl->device_name;
s_ctrl->v4l2_dev_str.sd_flags = (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
s_ctrl->v4l2_dev_str.ent_function = CAM_SENSOR_DEVICE_TYPE;
s_ctrl->v4l2_dev_str.token = s_ctrl;
s_ctrl->v4l2_dev_str.close_seq_prior =
CAM_SD_CLOSE_MEDIUM_LOW_PRIORITY;
s_ctrl->v4l2_dev_str.close_seq_prior = CAM_SD_CLOSE_MEDIUM_LOW_PRIORITY;
rc = cam_register_subdev(&(s_ctrl->v4l2_dev_str));
if (rc)
@@ -159,6 +163,45 @@ static int cam_sensor_init_subdev_params(struct cam_sensor_ctrl_t *s_ctrl)
return rc;
}
static int cam_sensor_i3c_driver_probe(struct i3c_device *client)
{
int32_t rc = 0;
struct cam_sensor_ctrl_t *s_ctrl = NULL;
uint32_t index;
struct device *dev;
dev = i3cdev_to_dev(client);
CAM_DBG(CAM_SENSOR, "Probe for I3C Slave %s", dev_name(dev));
rc = of_property_read_u32(dev->of_node, "cell-index", &index);
if (rc) {
CAM_ERR(CAM_UTIL, "device %s failed to read cell-index", dev_name(dev));
return rc;
}
if (index >= MAX_CAMERAS) {
CAM_ERR(CAM_SENSOR, "Invalid Cell-Index: %u for %s", index, dev_name(dev));
return -EINVAL;
}
s_ctrl = g_i3c_sensor_data[index].s_ctrl;
if (!s_ctrl) {
CAM_ERR(CAM_SENSOR, "S_ctrl is null. I3C Probe before platfom driver probe for %s",
dev_name(dev));
return -EINVAL;
}
i3cdev_set_drvdata(client, s_ctrl);
s_ctrl->io_master_info.i3c_client = client;
complete_all(&g_i3c_sensor_data[index].probe_complete);
CAM_DBG(CAM_SENSOR, "I3C Probe Finished for %s", dev_name(dev));
return rc;
}
static int cam_sensor_i2c_component_bind(struct device *dev,
struct device *master_dev, void *data)
{
@@ -358,6 +401,8 @@ static int cam_sensor_component_bind(struct device *dev,
goto free_s_ctrl;
}
CAM_DBG(CAM_SENSOR, "Master Type: %u", s_ctrl->io_master_info.master_type);
/* Fill platform device id*/
pdev->id = soc_info->index;
@@ -406,7 +451,10 @@ static int cam_sensor_component_bind(struct device *dev,
s_ctrl->sensordata->power_info.dev = &pdev->dev;
platform_set_drvdata(pdev, s_ctrl);
s_ctrl->sensor_state = CAM_SENSOR_INIT;
CAM_DBG(CAM_SENSOR, "Component bound successfully");
CAM_DBG(CAM_SENSOR, "Component bound successfully for %s", pdev->name);
g_i3c_sensor_data[soc_info->index].s_ctrl = s_ctrl;
init_completion(&g_i3c_sensor_data[soc_info->index].probe_complete);
return rc;
@@ -464,13 +512,14 @@ static const struct of_device_id cam_sensor_driver_dt_match[] = {
{.compatible = "qcom,cam-sensor"},
{}
};
MODULE_DEVICE_TABLE(of, cam_sensor_driver_dt_match);
static int32_t cam_sensor_driver_platform_probe(
struct platform_device *pdev)
{
int rc = 0;
CAM_DBG(CAM_SENSOR, "Adding Sensor component");
CAM_DBG(CAM_SENSOR, "Adding Sensor component for %s", pdev->name);
rc = component_add(&pdev->dev, &cam_sensor_component_ops);
if (rc)
CAM_ERR(CAM_SENSOR, "failed to add component rc: %d", rc);
@@ -478,8 +527,6 @@ static int32_t cam_sensor_driver_platform_probe(
return rc;
}
MODULE_DEVICE_TABLE(of, cam_sensor_driver_dt_match);
struct platform_driver cam_sensor_platform_driver = {
.probe = cam_sensor_driver_platform_probe,
.driver = {
@@ -495,7 +542,6 @@ static const struct of_device_id cam_sensor_i2c_driver_dt_match[] = {
{.compatible = "qcom,cam-i2c-sensor"},
{}
};
MODULE_DEVICE_TABLE(of, cam_sensor_i2c_driver_dt_match);
static const struct i2c_device_id i2c_id[] = {
@@ -515,20 +561,110 @@ struct i2c_driver cam_sensor_i2c_driver = {
},
};
static struct i3c_device_id sensor_i3c_id[MAX_I3C_DEVICE_ID_ENTRIES + 1];
static struct i3c_driver cam_sensor_i3c_driver = {
.id_table = sensor_i3c_id,
.probe = cam_sensor_i3c_driver_probe,
.remove = cam_sensor_i3c_driver_remove,
.driver = {
.owner = THIS_MODULE,
.name = SENSOR_DRIVER_I3C,
.of_match_table = cam_sensor_driver_dt_match,
.suppress_bind_attrs = true,
},
};
static int cam_sensor_fill_i3c_device_id(void)
{
struct device_node *dev;
int num_entries;
int i = 0;
uint8_t ent_num = 0;
uint32_t mid;
uint32_t pid;
int rc;
dev = of_find_node_by_path(I3C_SENSOR_DEV_ID_DT_PATH);
if (!dev) {
CAM_WARN(CAM_SENSOR, "Couldnt Find the i3c-id-table dev node");
return 0;
}
num_entries = of_property_count_u32_elems(dev, "i3c-sensor-id-table");
if (num_entries <= 0) {
CAM_WARN(CAM_SENSOR, "Failed while reading the property. num_entries:%d",
num_entries);
return 0;
}
while (i < num_entries) {
if (ent_num >= MAX_I3C_DEVICE_ID_ENTRIES) {
CAM_WARN(CAM_SENSOR, "Num_entries are more than MAX_I3C_DEVICE_ID_ENTRIES");
return -ENOMEM;
}
rc = of_property_read_u32_index(dev, "i3c-sensor-id-table", i, &mid);
if (rc) {
CAM_ERR(CAM_SENSOR, "Failed in reading the MID. rc: %d", rc);
return rc;
}
i++;
rc = of_property_read_u32_index(dev, "i3c-sensor-id-table", i, &pid);
if (rc) {
CAM_ERR(CAM_SENSOR, "Failed in reading the PID. rc: %d", rc);
return rc;
}
i++;
CAM_DBG(CAM_SENSOR, "PID: 0x%x, MID: 0x%x", pid, mid);
sensor_i3c_id[ent_num].manuf_id = mid;
sensor_i3c_id[ent_num].match_flags = I3C_MATCH_MANUF_AND_PART;
sensor_i3c_id[ent_num].part_id = pid;
sensor_i3c_id[ent_num].data = 0;
ent_num++;
}
return 0;
}
int cam_sensor_driver_init(void)
{
int32_t rc = 0;
int rc;
rc = platform_driver_register(&cam_sensor_platform_driver);
if (rc < 0) {
CAM_ERR(CAM_SENSOR, "platform_driver_register Failed: rc = %d",
rc);
CAM_ERR(CAM_SENSOR, "platform_driver_register Failed: rc = %d", rc);
return rc;
}
rc = i2c_add_driver(&cam_sensor_i2c_driver);
if (rc)
if (rc) {
CAM_ERR(CAM_SENSOR, "i2c_add_driver failed rc = %d", rc);
goto i2c_register_err;
}
memset(sensor_i3c_id, 0, sizeof(struct i3c_device_id) * (MAX_I3C_DEVICE_ID_ENTRIES + 1));
rc = cam_sensor_fill_i3c_device_id();
if (rc)
goto i3c_register_err;
rc = i3c_driver_register_with_owner(&cam_sensor_i3c_driver, THIS_MODULE);
if (rc) {
CAM_ERR(CAM_SENSOR, "i3c_driver registration failed, rc: %d", rc);
goto i3c_register_err;
}
return 0;
i3c_register_err:
i2c_del_driver(&cam_sensor_i2c_driver);
i2c_register_err:
platform_driver_unregister(&cam_sensor_platform_driver);
return rc;
}
@@ -537,6 +673,7 @@ void cam_sensor_driver_exit(void)
{
platform_driver_unregister(&cam_sensor_platform_driver);
i2c_del_driver(&cam_sensor_i2c_driver);
i3c_driver_unregister(&cam_sensor_i3c_driver);
}
MODULE_DESCRIPTION("cam_sensor_driver");

View File

@@ -28,16 +28,9 @@
#define NUM_MASTERS 2
#define NUM_QUEUES 2
#undef CDBG
#ifdef CAM_SENSOR_DEBUG
#define CDBG(fmt, args...) pr_err(fmt, ##args)
#else
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#endif
#define SENSOR_DRIVER_I2C "cam-i2c-sensor"
#define CAMX_SENSOR_DEV_NAME "cam-sensor-driver"
#define SENSOR_DRIVER_I3C "i3c_camera_sensor"
enum cam_sensor_state_t {
CAM_SENSOR_INIT,
@@ -73,6 +66,7 @@ struct sensor_intf_params {
* @sensor_state: Sensor states
* @is_probe_succeed: Probe succeeded or not
* @id: Cell Index
* @is_i3c_device: A Flag to indicate whether this sensor is an I3C Device.
* @of_node: Of node ptr
* @v4l2_dev_str: V4L2 device structure
* @sensor_probe_addr_type: Sensor probe address type
@@ -90,8 +84,7 @@ struct sensor_intf_params {
* @aon_camera_id: AON Camera ID associated with this sensor
*/
struct cam_sensor_ctrl_t {
char device_name[
CAM_CTX_DEV_NAME_MAX_LENGTH];
char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH];
struct platform_device *pdev;
struct cam_hw_soc_info soc_info;
struct mutex cam_sensor_mutex;
@@ -102,6 +95,7 @@ struct cam_sensor_ctrl_t {
enum cam_sensor_state_t sensor_state;
uint8_t is_probe_succeed;
uint32_t id;
bool is_i3c_device;
struct device_node *of_node;
struct cam_subdev v4l2_dev_str;
uint8_t sensor_probe_addr_type;

View File

@@ -110,14 +110,19 @@ static int32_t cam_sensor_init_bus_params(struct cam_sensor_ctrl_t *s_ctrl)
if (s_ctrl->io_master_info.master_type == CCI_MASTER) {
s_ctrl->io_master_info.cci_client = kzalloc(sizeof(
struct cam_sensor_cci_client), GFP_KERNEL);
if (!(s_ctrl->io_master_info.cci_client))
if (!(s_ctrl->io_master_info.cci_client)) {
CAM_ERR(CAM_SENSOR, "Memory allocation failed");
return -ENOMEM;
}
} else if (s_ctrl->io_master_info.master_type == I2C_MASTER) {
if (!(s_ctrl->io_master_info.client))
return -EINVAL;
} else if (s_ctrl->io_master_info.master_type == I3C_MASTER) {
CAM_DBG(CAM_SENSOR, "I3C Master Type");
} else {
CAM_ERR(CAM_SENSOR,
"Invalid master / Master type Not supported");
"Invalid master / Master type Not supported : %d",
s_ctrl->io_master_info.master_type);
return -EINVAL;
}
@@ -161,6 +166,13 @@ static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl)
goto FREE_SENSOR_DATA;
}
rc = of_property_read_bool(of_node, "i3c-target");
if (rc) {
CAM_INFO(CAM_SENSOR, "I3C Target");
s_ctrl->is_i3c_device = true;
s_ctrl->io_master_info.master_type = I3C_MASTER;
}
/* Store the index of BoB regulator if it is available */
for (i = 0; i < soc_info->num_rgltr; i++) {
if (!strcmp(soc_info->rgltr_name[i],

View File

@@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_SENSOR_I3C_H_
#define _CAM_SENSOR_I3C_H_
#include <linux/delay.h>
#include <media/v4l2-subdev.h>
#include <media/cam_sensor.h>
#include "cam_sensor_io.h"
/**
* cam_qup_i3c_read : This API handles QUP I3C read operations
* @client : QUP IeC client structure
* @data : I3C data
* @addr_type : I3C address type
* @data_type : I3C data type
*/
int cam_qup_i3c_read(struct i3c_device *client,
uint32_t addr, uint32_t *data,
enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type);
/**
* cam_qup_i3c_read_seq : This API handles QUP I3C Sequential read operations
* @client : QUP I3C client structure
* @data : I3C data
* @addr_type : I3C address type
* @num_bytes : Number of bytes to read
*/
int cam_qup_i3c_read_seq(struct i3c_device *client,
uint32_t addr, uint8_t *data,
enum camera_sensor_i2c_type addr_type,
uint32_t num_byte);
/**
* cam_qup_i3c_poll : This API handles QUP based I3C poll operation
* @client : QUP I3C client structure
* @addr : I3C address
* @data : I3C data
* @data_mask : I3C data mask
* @data_type : I3C data type
* @addr_type : I3C addr type
* @delay_ms : Delay in milli seconds
*/
int cam_qup_i3c_poll(struct i3c_device *client,
uint32_t addr, uint16_t data, uint16_t data_mask,
enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type,
uint32_t delay_ms);
/**
* cam_qup_i3c_write_table : This API Handles QUP based I3C write random operations
* @client : QUP I3C client structure
* @write_setting : I3C register settings
*/
int cam_qup_i3c_write_table(
struct camera_io_master *client,
struct cam_sensor_i2c_reg_setting *write_setting);
/**
* cam_qup_i3c_write_continuous_write: This API Handles QUP based I3C write continuous(Burst/Seq)
* @client: QUP I3C client structure
* @write_setting: I3C register setting
* @cam_sensor_i3c_write_flag: burst or seq write
*/
int cam_qup_i3c_write_continuous_table(
struct camera_io_master *client,
struct cam_sensor_i2c_reg_setting *write_setting,
uint8_t cam_sensor_i3c_write_flag);
#endif /*_CAM_SENSOR_I3C_H_*/

View File

@@ -6,6 +6,7 @@
#include "cam_sensor_io.h"
#include "cam_sensor_i2c.h"
#include "cam_sensor_i3c.h"
int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
uint32_t addr, uint16_t data, uint32_t data_mask,
@@ -20,48 +21,49 @@ int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
return -EINVAL;
}
if (io_master_info->master_type == CCI_MASTER) {
switch (io_master_info->master_type) {
case CCI_MASTER:
return cam_cci_i2c_poll(io_master_info->cci_client,
addr, data, mask, data_type, addr_type, delay_ms);
} else if (io_master_info->master_type == I2C_MASTER) {
case I2C_MASTER:
return cam_qup_i2c_poll(io_master_info->client,
addr, data, data_mask, addr_type, data_type,
delay_ms);
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
return -EINVAL;
addr, data, data_mask, addr_type, data_type, delay_ms);
case I3C_MASTER:
return cam_qup_i3c_poll(io_master_info->i3c_client,
addr, data, data_mask, addr_type, data_type, delay_ms);
default:
CAM_ERR(CAM_SENSOR, "Invalid Master Type: %d", io_master_info->master_type);
}
return -EINVAL;
}
int32_t camera_io_dev_erase(struct camera_io_master *io_master_info,
uint32_t addr, uint32_t size)
{
int rc = 0;
if (!io_master_info) {
CAM_ERR(CAM_SENSOR, "Invalid Args");
return -EINVAL;
}
if (size == 0)
return rc;
return 0;
if (io_master_info->master_type == SPI_MASTER) {
switch (io_master_info->master_type) {
case SPI_MASTER:
CAM_DBG(CAM_SENSOR, "Calling SPI Erase");
return cam_spi_erase(io_master_info, addr,
CAMERA_SENSOR_I2C_TYPE_WORD, size);
} else if (io_master_info->master_type == I2C_MASTER ||
io_master_info->master_type == CCI_MASTER) {
CAM_ERR(CAM_SENSOR, "Erase not supported on master :%d",
return cam_spi_erase(io_master_info, addr, CAMERA_SENSOR_I2C_TYPE_WORD, size);
case I2C_MASTER:
case CCI_MASTER:
case I3C_MASTER:
CAM_ERR(CAM_SENSOR, "Erase not supported on Master Type: %d",
io_master_info->master_type);
rc = -EINVAL;
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
rc = -EINVAL;
return -EINVAL;
default:
CAM_ERR(CAM_SENSOR, "Invalid Master Type: %d", io_master_info->master_type);
}
return rc;
return -EINVAL;
}
int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
@@ -75,21 +77,23 @@ int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
return -EINVAL;
}
if (io_master_info->master_type == CCI_MASTER) {
return cam_cci_i2c_read(io_master_info->cci_client,
addr, data, addr_type, data_type, is_probing);
} else if (io_master_info->master_type == I2C_MASTER) {
switch (io_master_info->master_type) {
case SPI_MASTER:
return cam_spi_read(io_master_info, addr, data, addr_type, data_type);
case I2C_MASTER:
return cam_qup_i2c_read(io_master_info->client,
addr, data, addr_type, data_type);
} else if (io_master_info->master_type == SPI_MASTER) {
return cam_spi_read(io_master_info,
case CCI_MASTER:
return cam_cci_i2c_read(io_master_info->cci_client,
addr, data, addr_type, data_type, is_probing);
case I3C_MASTER:
return cam_qup_i3c_read(io_master_info->i3c_client,
addr, data, addr_type, data_type);
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
return -EINVAL;
default:
CAM_ERR(CAM_SENSOR, "Invalid Master Type: %d", io_master_info->master_type);
}
return 0;
return -EINVAL;
}
int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info,
@@ -97,24 +101,23 @@ int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info,
enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type, int32_t num_bytes)
{
if (io_master_info->master_type == CCI_MASTER) {
switch (io_master_info->master_type) {
case CCI_MASTER:
return cam_camera_cci_i2c_read_seq(io_master_info->cci_client,
addr, data, addr_type, data_type, num_bytes);
} else if (io_master_info->master_type == I2C_MASTER) {
case I2C_MASTER:
return cam_qup_i2c_read_seq(io_master_info->client,
addr, data, addr_type, num_bytes);
} else if (io_master_info->master_type == SPI_MASTER) {
return cam_spi_read_seq(io_master_info,
case SPI_MASTER:
return cam_spi_read_seq(io_master_info, addr, data, addr_type, num_bytes);
case I3C_MASTER:
return cam_qup_i3c_read_seq(io_master_info->i3c_client,
addr, data, addr_type, num_bytes);
} else if (io_master_info->master_type == SPI_MASTER) {
return cam_spi_write_seq(io_master_info,
addr, data, addr_type, num_bytes);
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
return -EINVAL;
default:
CAM_ERR(CAM_SENSOR, "Invalid Master Type: %d", io_master_info->master_type);
}
return 0;
return -EINVAL;
}
int32_t camera_io_dev_write(struct camera_io_master *io_master_info,
@@ -132,20 +135,20 @@ int32_t camera_io_dev_write(struct camera_io_master *io_master_info,
return -EINVAL;
}
if (io_master_info->master_type == CCI_MASTER) {
return cam_cci_i2c_write_table(io_master_info,
write_setting);
} else if (io_master_info->master_type == I2C_MASTER) {
return cam_qup_i2c_write_table(io_master_info,
write_setting);
} else if (io_master_info->master_type == SPI_MASTER) {
return cam_spi_write_table(io_master_info,
write_setting);
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
return -EINVAL;
switch (io_master_info->master_type) {
case CCI_MASTER:
return cam_cci_i2c_write_table(io_master_info, write_setting);
case I2C_MASTER:
return cam_qup_i2c_write_table(io_master_info, write_setting);
case SPI_MASTER:
return cam_spi_write_table(io_master_info, write_setting);
case I3C_MASTER:
return cam_qup_i3c_write_table(io_master_info, write_setting);
default:
CAM_ERR(CAM_SENSOR, "Invalid Master Type:%d", io_master_info->master_type);
}
return -EINVAL;
}
int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info,
@@ -164,20 +167,23 @@ int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info,
return -EINVAL;
}
if (io_master_info->master_type == CCI_MASTER) {
switch (io_master_info->master_type) {
case CCI_MASTER:
return cam_cci_i2c_write_continuous_table(io_master_info,
write_setting, cam_sensor_i2c_write_flag);
} else if (io_master_info->master_type == I2C_MASTER) {
case I2C_MASTER:
return cam_qup_i2c_write_continuous_table(io_master_info,
write_setting, cam_sensor_i2c_write_flag);
} else if (io_master_info->master_type == SPI_MASTER) {
return cam_spi_write_table(io_master_info,
write_setting);
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
return -EINVAL;
case SPI_MASTER:
return cam_spi_write_table(io_master_info, write_setting);
case I3C_MASTER:
return cam_qup_i3c_write_continuous_table(io_master_info,
write_setting, cam_sensor_i2c_write_flag);
default:
CAM_ERR(CAM_SENSOR, "Invalid Master Type:%d", io_master_info->master_type);
}
return -EINVAL;
}
int32_t camera_io_init(struct camera_io_master *io_master_info)
@@ -187,14 +193,16 @@ int32_t camera_io_init(struct camera_io_master *io_master_info)
return -EINVAL;
}
if (io_master_info->master_type == CCI_MASTER) {
io_master_info->cci_client->cci_subdev =
cam_cci_get_subdev(io_master_info->cci_client->cci_device);
return cam_sensor_cci_i2c_util(io_master_info->cci_client,
MSM_CCI_INIT);
} else if ((io_master_info->master_type == I2C_MASTER) ||
(io_master_info->master_type == SPI_MASTER)) {
return 0;
switch (io_master_info->master_type) {
case CCI_MASTER:
io_master_info->cci_client->cci_subdev = cam_cci_get_subdev(
io_master_info->cci_client->cci_device);
return cam_sensor_cci_i2c_util(io_master_info->cci_client, MSM_CCI_INIT);
case I2C_MASTER:
case SPI_MASTER:
case I3C_MASTER: return 0;
default:
CAM_ERR(CAM_SENSOR, "Invalid Master Type:%d", io_master_info->master_type);
}
return -EINVAL;
@@ -207,12 +215,14 @@ int32_t camera_io_release(struct camera_io_master *io_master_info)
return -EINVAL;
}
if (io_master_info->master_type == CCI_MASTER) {
return cam_sensor_cci_i2c_util(io_master_info->cci_client,
MSM_CCI_RELEASE);
} else if ((io_master_info->master_type == I2C_MASTER) ||
(io_master_info->master_type == SPI_MASTER)) {
return 0;
switch (io_master_info->master_type) {
case CCI_MASTER:
return cam_sensor_cci_i2c_util(io_master_info->cci_client, MSM_CCI_RELEASE);
case I2C_MASTER:
case SPI_MASTER:
case I3C_MASTER: return 0;
default:
CAM_ERR(CAM_SENSOR, "Invalid Master Type:%d", io_master_info->master_type);
}
return -EINVAL;

View File

@@ -8,22 +8,25 @@
#define _CAM_SENSOR_IO_H_
#include <media/cam_sensor.h>
#include "cam_sensor_cmn_header.h"
/* Master Types */
#define CCI_MASTER 1
#define I2C_MASTER 2
#define SPI_MASTER 3
#define I3C_MASTER 4
/**
* @master_type: CCI master type
* @client: I2C client information structure
* @i2c_client: I2C client information structure
* @i3c_client: I3C client information structure
* @cci_client: CCI client information structure
* @spi_client: SPI client information structure
*/
struct camera_io_master {
int master_type;
struct i2c_client *client;
struct i3c_device *i3c_client;
struct cam_sensor_cci_client *cci_client;
struct cam_sensor_spi_client *spi_client;
};
@@ -116,4 +119,6 @@ int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
#include "cam_sensor_i2c.h"
#include "cam_sensor_spi.h"
#include "cam_sensor_i3c.h"
#endif /* _CAM_SENSOR_IO_H_ */

View File

@@ -0,0 +1,517 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "cam_sensor_i3c.h"
#include "cam_sensor_io.h"
#define I3C_REG_MAX_BUF_SIZE 8
static int cam_qup_i3c_rxdata(struct i3c_device *dev_client, unsigned char *rxdata,
enum camera_sensor_i2c_type addr_type, int data_length)
{
int rc;
struct i3c_priv_xfer read_buf[2] = {
{
.rnw = 0,
.len = addr_type,
.data.out = rxdata,
},
{
.rnw = 1,
.len = data_length,
.data.in = rxdata,
},
};
rc = i3c_device_do_priv_xfers(dev_client, read_buf, ARRAY_SIZE(read_buf));
if (rc)
CAM_ERR(CAM_SENSOR, "Failed with i3c_read: rc = %d", rc);
return rc;
}
static int cam_qup_i3c_txdata(struct camera_io_master *dev_client, unsigned char *txdata,
int length)
{
int rc;
struct i3c_priv_xfer write_buf = {
.rnw = 0,
.len = length,
.data.out = txdata,
};
rc = i3c_device_do_priv_xfers(dev_client->i3c_client, &write_buf, 1);
if (rc)
CAM_ERR(CAM_SENSOR, "Failed with i3c_write: rc = %d", rc);
return rc;
}
int cam_qup_i3c_read(struct i3c_device *client, uint32_t addr, uint32_t *data,
enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type)
{
int rc;
unsigned char *buf;
if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)
|| (addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
|| (data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)
|| (data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)) {
CAM_ERR(CAM_SENSOR, "Failed with addr/data_type verfication");
return -EINVAL;
}
buf = kzalloc(addr_type + data_type, GFP_DMA | GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
buf[0] = addr;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
buf[0] = addr >> 8;
buf[1] = addr;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
buf[0] = addr >> 16;
buf[1] = addr >> 8;
buf[2] = addr;
} else {
buf[0] = addr >> 24;
buf[1] = addr >> 16;
buf[2] = addr >> 8;
buf[3] = addr;
}
rc = cam_qup_i3c_rxdata(client, buf, addr_type, data_type);
if (rc) {
CAM_ERR(CAM_SENSOR, "failed rc: %d", rc);
goto read_fail;
}
if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE)
*data = buf[0];
else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD)
*data = (buf[0] << 8) | buf[1];
else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B)
*data = (buf[0] << 16) | (buf[1] << 8) | buf[2];
else
*data = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
CAM_DBG(CAM_SENSOR, "addr = 0x%x data: 0x%x", addr, *data);
read_fail:
kfree(buf);
return rc;
}
int cam_qup_i3c_read_seq(struct i3c_device *client,
uint32_t addr, uint8_t *data,
enum camera_sensor_i2c_type addr_type,
uint32_t num_byte)
{
int rc;
unsigned char *buf;
int i;
if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
|| addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) {
CAM_ERR(CAM_SENSOR, "Failed with addr_type verification");
return -EFAULT;
}
if ((num_byte == 0) || (num_byte > I2C_REG_DATA_MAX)) {
CAM_ERR(CAM_SENSOR, "num_byte:0x%x max supported:0x%x",
num_byte, I2C_REG_DATA_MAX);
return -EFAULT;
}
buf = kzalloc(addr_type + num_byte, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
buf[0] = addr;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
buf[0] = addr >> BITS_PER_BYTE;
buf[1] = addr;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
buf[0] = addr >> 16;
buf[1] = addr >> 8;
buf[2] = addr;
} else {
buf[0] = addr >> 24;
buf[1] = addr >> 16;
buf[2] = addr >> 8;
buf[3] = addr;
}
rc = cam_qup_i3c_rxdata(client, buf, addr_type, num_byte);
if (rc) {
CAM_ERR(CAM_SENSOR, "failed rc: %d", rc);
goto read_seq_fail;
}
for (i = 0; i < num_byte; i++)
data[i] = buf[i];
read_seq_fail:
kfree(buf);
return rc;
}
static int cam_qup_i3c_compare(struct i3c_device *client,
uint32_t addr, uint32_t data, uint16_t data_mask,
enum camera_sensor_i2c_type data_type,
enum camera_sensor_i2c_type addr_type)
{
int rc;
uint32_t reg_data;
rc = cam_qup_i3c_read(client, addr, &reg_data,
addr_type, data_type);
if (rc < 0)
return rc;
reg_data = reg_data & 0xFFFF;
if (data != (reg_data & ~data_mask))
return I2C_COMPARE_MISMATCH;
return I2C_COMPARE_MATCH;
}
int cam_qup_i3c_poll(struct i3c_device *client,
uint32_t addr, uint16_t data, uint16_t data_mask,
enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type,
uint32_t delay_ms)
{
int rc;
int i;
if ((delay_ms > MAX_POLL_DELAY_MS) || (delay_ms == 0)) {
CAM_ERR(CAM_SENSOR, "invalid delay = %d max_delay = %d",
delay_ms, MAX_POLL_DELAY_MS);
return -EINVAL;
}
if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
|| addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
|| data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
|| data_type >= CAMERA_SENSOR_I2C_TYPE_MAX))
return -EINVAL;
for (i = 0; i < delay_ms; i++) {
rc = cam_qup_i3c_compare(client,
addr, data, data_mask, data_type, addr_type);
if (rc == I2C_COMPARE_MATCH)
return rc;
usleep_range(1000, 1010);
}
/* If rc is MISMATCH then read is successful but poll is failure */
if (rc == I2C_COMPARE_MISMATCH)
CAM_ERR(CAM_SENSOR, "poll failed rc=%d(non-fatal)", rc);
if (rc < 0)
CAM_ERR(CAM_SENSOR, "poll failed rc=%d", rc);
return rc;
}
static int cam_qup_i3c_write(struct camera_io_master *client,
struct cam_sensor_i2c_reg_array *reg_setting,
enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type)
{
int rc;
unsigned char *buf = NULL;
uint8_t len = 0;
buf = kzalloc(I3C_REG_MAX_BUF_SIZE, GFP_KERNEL | GFP_DMA);
if (!buf) {
CAM_ERR(CAM_SENSOR, "Buffer memory allocation failed");
return -ENOMEM;
}
CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d",
reg_setting->reg_addr, data_type);
if (addr_type == CAMERA_SENSOR_I2C_TYPE_INVALID) {
buf[0] = reg_setting->reg_addr;
CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]);
len = 1;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
buf[0] = reg_setting->reg_addr >> 8;
buf[1] = reg_setting->reg_addr;
CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]);
CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len+1, buf[len+1]);
len = 2;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
buf[0] = reg_setting->reg_addr >> 16;
buf[1] = reg_setting->reg_addr >> 8;
buf[2] = reg_setting->reg_addr;
len = 3;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_DWORD) {
buf[0] = reg_setting->reg_addr >> 24;
buf[1] = reg_setting->reg_addr >> 16;
buf[2] = reg_setting->reg_addr >> 8;
buf[3] = reg_setting->reg_addr;
len = 4;
} else {
CAM_ERR(CAM_SENSOR, "Invalid I2C addr type");
rc = -EINVAL;
goto deallocate_buffer;
}
CAM_DBG(CAM_SENSOR, "Data: 0x%x", reg_setting->reg_data);
if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
buf[len] = reg_setting->reg_data;
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]);
len += 1;
} else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
buf[len] = reg_setting->reg_data >> 8;
buf[len+1] = reg_setting->reg_data;
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]);
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]);
len += 2;
} else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) {
buf[len] = reg_setting->reg_data >> 16;
buf[len + 1] = reg_setting->reg_data >> 8;
buf[len + 2] = reg_setting->reg_data;
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]);
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]);
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+2, buf[len+2]);
len += 3;
} else if (data_type == CAMERA_SENSOR_I2C_TYPE_DWORD) {
buf[len] = reg_setting->reg_data >> 24;
buf[len + 1] = reg_setting->reg_data >> 16;
buf[len + 2] = reg_setting->reg_data >> 8;
buf[len + 3] = reg_setting->reg_data;
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]);
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]);
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+2, buf[len+2]);
CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+3, buf[len+3]);
len += 4;
} else {
CAM_ERR(CAM_SENSOR, "Invalid Data Type");
rc = -EINVAL;
goto deallocate_buffer;
}
rc = cam_qup_i3c_txdata(client, buf, len);
if (rc)
CAM_ERR(CAM_SENSOR, "failed rc: %d", rc);
deallocate_buffer:
kfree(buf);
return rc;
}
int cam_qup_i3c_write_table(struct camera_io_master *client,
struct cam_sensor_i2c_reg_setting *write_setting)
{
int i;
int rc = -EINVAL;
struct cam_sensor_i2c_reg_array *reg_setting;
if (!client || !write_setting)
return -EINVAL;
if ((write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
|| write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
|| (write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
|| write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)))
return -EINVAL;
reg_setting = write_setting->reg_setting;
for (i = 0; i < write_setting->size; i++) {
CAM_DBG(CAM_SENSOR, "addr 0x%x data 0x%x",
reg_setting->reg_addr, reg_setting->reg_data);
rc = cam_qup_i3c_write(client, reg_setting,
write_setting->addr_type, write_setting->data_type);
if (rc < 0)
break;
reg_setting++;
}
if (write_setting->delay > 20)
msleep(write_setting->delay);
else if (write_setting->delay)
usleep_range(write_setting->delay * 1000, (write_setting->delay
* 1000) + 1000);
return rc;
}
static int cam_qup_i3c_write_seq(struct camera_io_master *client,
struct cam_sensor_i2c_reg_setting *write_setting)
{
int i;
int rc = 0;
struct cam_sensor_i2c_reg_array *reg_setting;
reg_setting = write_setting->reg_setting;
for (i = 0; i < write_setting->size; i++) {
reg_setting->reg_addr += i;
rc = cam_qup_i3c_write(client, reg_setting,
write_setting->addr_type, write_setting->data_type);
if (rc < 0) {
CAM_ERR(CAM_SENSOR,
"Sequential i2c write failed: rc: %d", rc);
break;
}
reg_setting++;
}
if (write_setting->delay > 20)
msleep(write_setting->delay);
else if (write_setting->delay)
usleep_range(write_setting->delay * 1000, (write_setting->delay
* 1000) + 1000);
return rc;
}
static int cam_qup_i3c_write_burst(struct camera_io_master *client,
struct cam_sensor_i2c_reg_setting *write_setting)
{
int i;
int rc;
uint32_t len = 0;
unsigned char *buf;
struct cam_sensor_i2c_reg_array *reg_setting;
enum camera_sensor_i2c_type addr_type;
enum camera_sensor_i2c_type data_type;
buf = kzalloc((write_setting->addr_type +
(write_setting->size * write_setting->data_type)),
GFP_DMA | GFP_KERNEL);
if (!buf) {
CAM_ERR(CAM_SENSOR, "BUF is NULL");
return -ENOMEM;
}
reg_setting = write_setting->reg_setting;
addr_type = write_setting->addr_type;
data_type = write_setting->data_type;
CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d",
reg_setting->reg_addr, data_type);
if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
buf[0] = reg_setting->reg_addr;
CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]);
len = 1;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
buf[0] = reg_setting->reg_addr >> 8;
buf[1] = reg_setting->reg_addr;
CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]);
CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len+1, buf[len+1]);
len = 2;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
buf[0] = reg_setting->reg_addr >> 16;
buf[1] = reg_setting->reg_addr >> 8;
buf[2] = reg_setting->reg_addr;
len = 3;
} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_DWORD) {
buf[0] = reg_setting->reg_addr >> 24;
buf[1] = reg_setting->reg_addr >> 16;
buf[2] = reg_setting->reg_addr >> 8;
buf[3] = reg_setting->reg_addr;
len = 4;
} else {
CAM_ERR(CAM_SENSOR, "Invalid I2C addr type");
rc = -EINVAL;
goto free_res;
}
for (i = 0; i < write_setting->size; i++) {
if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
buf[len] = reg_setting->reg_data;
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len, buf[len]);
len += 1;
} else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
buf[len] = reg_setting->reg_data >> 8;
buf[len+1] = reg_setting->reg_data;
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len, buf[len]);
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len+1, buf[len+1]);
len += 2;
} else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) {
buf[len] = reg_setting->reg_data >> 16;
buf[len + 1] = reg_setting->reg_data >> 8;
buf[len + 2] = reg_setting->reg_data;
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len, buf[len]);
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len+1, buf[len+1]);
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len+2, buf[len+2]);
len += 3;
} else if (data_type == CAMERA_SENSOR_I2C_TYPE_DWORD) {
buf[len] = reg_setting->reg_data >> 24;
buf[len + 1] = reg_setting->reg_data >> 16;
buf[len + 2] = reg_setting->reg_data >> 8;
buf[len + 3] = reg_setting->reg_data;
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len, buf[len]);
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len+1, buf[len+1]);
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len+2, buf[len+2]);
CAM_DBG(CAM_SENSOR,
"Byte %d: 0x%x", len+3, buf[len+3]);
len += 4;
} else {
CAM_ERR(CAM_SENSOR, "Invalid Data Type");
rc = -EINVAL;
goto free_res;
}
reg_setting++;
}
if (len > (write_setting->addr_type +
(write_setting->size * write_setting->data_type))) {
CAM_ERR(CAM_SENSOR, "Invalid Length: %u | Expected length: %u",
len, (write_setting->addr_type +
(write_setting->size * write_setting->data_type)));
rc = -EINVAL;
goto free_res;
}
rc = cam_qup_i3c_txdata(client, buf, len);
if (rc < 0)
CAM_ERR(CAM_SENSOR, "failed rc: %d", rc);
free_res:
kfree(buf);
return rc;
}
int cam_qup_i3c_write_continuous_table(struct camera_io_master *client,
struct cam_sensor_i2c_reg_setting *write_settings,
uint8_t cam_sensor_i2c_write_flag)
{
int rc = 0;
if (!client || !write_settings)
return -EINVAL;
if ((write_settings->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
|| write_settings->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
|| (write_settings->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
|| write_settings->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)))
return -EINVAL;
if (cam_sensor_i2c_write_flag == CAM_SENSOR_I2C_WRITE_BURST)
rc = cam_qup_i3c_write_burst(client, write_settings);
else if (cam_sensor_i2c_write_flag == CAM_SENSOR_I2C_WRITE_SEQ)
rc = cam_qup_i3c_write_seq(client, write_settings);
return rc;
}

View File

@@ -8,6 +8,7 @@
#define _CAM_SENSOR_CMN_HEADER_
#include <linux/i2c.h>
#include <linux/i3c/master.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -20,9 +21,11 @@
#include <media/cam_req_mgr.h>
#define MAX_POWER_CONFIG 12
#define MAX_PER_FRAME_ARRAY 32
#define BATCH_SIZE_MAX 16
#define CAM_SENSOR_I3C_PROBE_TIMEOUT_MS 10
#define I3C_SENSOR_DEV_ID_DT_PATH "/soc/qcom,cam-i3c-id-table"
#define MAX_I3C_DEVICE_ID_ENTRIES MAX_CAMERAS
#define CAM_SENSOR_NAME "cam-sensor"
#define CAM_ACTUATOR_NAME "cam-actuator"

View File

@@ -364,6 +364,12 @@ void cam_compat_util_put_dmabuf_va(struct dma_buf *dmabuf, void *vaddr)
dma_buf_vunmap(dmabuf, &mapping);
}
void cam_sensor_i3c_driver_remove(struct i3c_device *client)
{
CAM_DBG(CAM_SENSOR, "I3C remove invoked for %s", dev_name(i3cdev_to_dev(client)));
}
#else
void cam_smmu_util_iommu_custom(struct device *dev,
dma_addr_t discard_start, size_t discard_length)
@@ -402,4 +408,10 @@ void cam_compat_util_put_dmabuf_va(struct dma_buf *dmabuf, void *vaddr)
{
dma_buf_vunmap(dmabuf, vaddr);
}
int cam_sensor_i3c_driver_remove(struct i3c_device *client)
{
CAM_DBG(CAM_SENSOR, "I3C remove invoked for %s", dev_name(i3cdev_to_dev(client)));
return 0;
}
#endif

View File

@@ -58,9 +58,11 @@ void cam_smmu_util_iommu_custom(struct device *dev,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
int cam_req_mgr_ordered_list_cmp(void *priv,
const struct list_head *head_1, const struct list_head *head_2);
void cam_sensor_i3c_driver_remove(struct i3c_device *client);
#else
int cam_req_mgr_ordered_list_cmp(void *priv,
struct list_head *head_1, struct list_head *head_2);
int cam_sensor_i3c_driver_remove(struct i3c_device *client);
#endif
#endif /* _CAM_COMPAT_H_ */