mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
media: camera: Build tegra-camera as OOT module
Port camera drivers below from /kenrel/nvidia to /kernel/nvidia-oot as OOT modules: - Fusa-capture driver - Tegra V4L2 framework driver - vi/csi driver - tegra camera platform driver Change-Id: I390af27096425bb11e0934201dd1a90f001bb3fa Signed-off-by: Frank Chen <frankc@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2780698 Reviewed-by: FNU Raunak <fraunak@nvidia.com> Reviewed-by: Ankur Pawar <ankurp@nvidia.com> Reviewed-by: Shiva Dubey <sdubey@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
e2b55e1a2c
commit
92ac7bc35a
249
drivers/media/platform/tegra/camera/tegracam_utils.c
Normal file
249
drivers/media/platform/tegra/camera/tegracam_utils.c
Normal file
@@ -0,0 +1,249 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* tegracam_utils - tegra camera framework utilities
|
||||
*
|
||||
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <media/tegracam_core.h>
|
||||
#include <media/tegracam_utils.h>
|
||||
|
||||
bool is_tvcf_supported(u32 version)
|
||||
{
|
||||
/* 2.0.0 is the base tvcf version sensor driver*/
|
||||
return (version >= tegracam_version(2, 0, 0) ? true : false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(is_tvcf_supported);
|
||||
|
||||
int format_tvcf_version(u32 version, char *buff, size_t size)
|
||||
{
|
||||
if (buff == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return snprintf(buff, size, "%u.%u.%u",
|
||||
(u8)(version >> 16),
|
||||
(u8)(version >> 8),
|
||||
(u8)(version));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(format_tvcf_version);
|
||||
|
||||
void conv_u32_u8arr(u32 input, u8 *output)
|
||||
{
|
||||
output[0] = (input >> 24) & 0xFF;
|
||||
output[1] = (input >> 16) & 0xFF;
|
||||
output[2] = (input >> 8) & 0xFF;
|
||||
output[3] = input & 0xFF;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(conv_u32_u8arr);
|
||||
|
||||
void conv_u16_u8arr(u16 input, u8 *output)
|
||||
{
|
||||
output[0] = (input >> 8) & 0xFF;
|
||||
output[1] = input & 0xFF;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(conv_u16_u8arr);
|
||||
|
||||
static inline int is_valid_blob(struct sensor_blob *blob, u32 size)
|
||||
{
|
||||
if (!blob)
|
||||
return -EINVAL;
|
||||
|
||||
if ((blob->num_cmds >= MAX_COMMANDS) ||
|
||||
((blob->buf_size + size) >= MAX_BLOB_SIZE))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prepare_write_cmd(struct sensor_blob *blob,
|
||||
u32 size, u32 addr, u8 *buf)
|
||||
{
|
||||
struct sensor_cmd *cmd = NULL;
|
||||
int err = 0;
|
||||
|
||||
err = is_valid_blob(blob, size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cmd = &blob->cmds[blob->num_cmds++];
|
||||
cmd->opcode = ((SENSOR_OPCODE_WRITE << 24) | size);
|
||||
cmd->addr = addr;
|
||||
|
||||
memcpy(&blob->buf[blob->buf_size], buf, size);
|
||||
|
||||
blob->buf_size += size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prepare_write_cmd);
|
||||
|
||||
int prepare_read_cmd(struct sensor_blob *blob,
|
||||
u32 size, u32 addr)
|
||||
{
|
||||
struct sensor_cmd *cmd = NULL;
|
||||
int err = 0;
|
||||
|
||||
err = is_valid_blob(blob, size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cmd = &blob->cmds[blob->num_cmds++];
|
||||
cmd->opcode = ((SENSOR_OPCODE_READ << 24) | size);
|
||||
cmd->addr = addr;
|
||||
|
||||
blob->buf_size += size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prepare_read_cmd);
|
||||
|
||||
int prepare_sleep_cmd(struct sensor_blob *blob, u32 time_in_us)
|
||||
{
|
||||
struct sensor_cmd *cmd = NULL;
|
||||
int err = 0;
|
||||
|
||||
err = is_valid_blob(blob, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cmd = &blob->cmds[blob->num_cmds++];
|
||||
cmd->opcode = (SENSOR_OPCODE_SLEEP << 24) | time_in_us;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prepare_sleep_cmd);
|
||||
|
||||
int prepare_done_cmd(struct sensor_blob *blob)
|
||||
{
|
||||
struct sensor_cmd *cmd = NULL;
|
||||
int err = 0;
|
||||
|
||||
err = is_valid_blob(blob, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cmd = &blob->cmds[blob->num_cmds++];
|
||||
cmd->opcode = SENSOR_OPCODE_DONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prepare_done_cmd);
|
||||
|
||||
int convert_table_to_blob(struct sensor_blob *blob,
|
||||
const struct reg_8 table[],
|
||||
u16 wait_ms_addr, u16 end_addr)
|
||||
{
|
||||
const struct reg_8 *next;
|
||||
u16 addr;
|
||||
u8 val;
|
||||
int range_start = -1;
|
||||
u32 range_count = 0;
|
||||
u8 buf[16];
|
||||
|
||||
for (next = table;; next++) {
|
||||
val = next->val;
|
||||
addr = next->addr;
|
||||
if (range_start == -1)
|
||||
range_start = next->addr;
|
||||
|
||||
if (range_count == 16 ||
|
||||
(addr != (range_start + range_count))) {
|
||||
/* write opcode and size for store index*/
|
||||
prepare_write_cmd(blob, range_count,
|
||||
range_start, &buf[0]);
|
||||
range_start = addr;
|
||||
range_count = 0;
|
||||
}
|
||||
|
||||
/* Done command must be added by client */
|
||||
if (addr == end_addr)
|
||||
break;
|
||||
|
||||
if (addr == wait_ms_addr) {
|
||||
prepare_sleep_cmd(blob, (next->val * 1000));
|
||||
range_start = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
buf[range_count++] = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(convert_table_to_blob);
|
||||
|
||||
int write_sensor_blob(struct regmap *regmap, struct sensor_blob *blob)
|
||||
{
|
||||
int err = 0;
|
||||
int cmd_idx = 0;
|
||||
int buf_index = 0;
|
||||
|
||||
while (cmd_idx < blob->num_cmds) {
|
||||
struct sensor_cmd *cmd = &blob->cmds[cmd_idx++];
|
||||
u32 val;
|
||||
|
||||
val = cmd->opcode;
|
||||
if ((val >> 24) == SENSOR_OPCODE_DONE)
|
||||
break;
|
||||
|
||||
if ((val >> 24) == SENSOR_OPCODE_SLEEP) {
|
||||
val = val & 0x00FFFFFF;
|
||||
usleep_range(val, val + 10);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((val >> 24) == SENSOR_OPCODE_WRITE) {
|
||||
int size = val & 0x00FFFFFF;
|
||||
|
||||
err = regmap_bulk_write(regmap, cmd->addr,
|
||||
&blob->buf[buf_index], size);
|
||||
if (err)
|
||||
return err;
|
||||
buf_index += size;
|
||||
} else {
|
||||
pr_err("blob has been packaged with errors\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(write_sensor_blob);
|
||||
|
||||
int tegracam_write_blobs(struct tegracam_ctrl_handler *hdl)
|
||||
{
|
||||
struct camera_common_data *s_data = hdl->tc_dev->s_data;
|
||||
struct tegracam_sensor_data *sensor_data = &hdl->sensor_data;
|
||||
struct sensor_blob *ctrl_blob = &sensor_data->ctrls_blob;
|
||||
struct sensor_blob *mode_blob = &sensor_data->mode_blob;
|
||||
const struct tegracam_ctrl_ops *ops = hdl->ctrl_ops;
|
||||
int err = 0;
|
||||
|
||||
/* no blob control available */
|
||||
if (ops == NULL || !ops->is_blob_supported)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* TODO: Extend this to multiple subdevices
|
||||
* mode blob commands can be zero for auto control updates
|
||||
* and stop streaming cases
|
||||
*/
|
||||
if (mode_blob->num_cmds) {
|
||||
err = write_sensor_blob(s_data->regmap, mode_blob);
|
||||
if (err) {
|
||||
dev_err(s_data->dev, "Error writing mode blob\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = write_sensor_blob(s_data->regmap, ctrl_blob);
|
||||
if (err) {
|
||||
dev_err(s_data->dev, "Error writing control blob\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegracam_write_blobs);
|
||||
Reference in New Issue
Block a user