Files
CoolPi-Armbian-Rockchip-RK3…/drivers/media/i2c/maxim/local/maxim2c/maxim2c_video_pipe.c
2025-02-04 12:41:12 -06:00

344 lines
8.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Maxim Dual GMSL Deserializer Video Pipe driver
*
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
*
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
*/
#include "maxim2c_api.h"
static int maxim2c_video_pipe_select(maxim2c_t *maxim2c)
{
struct i2c_client *client = maxim2c->client;
maxim2c_video_pipe_t *video_pipe = &maxim2c->video_pipe;
struct maxim2c_pipe_cfg *video_pipe_cfg = NULL;
u8 link_idx, pipe_idx;
u8 reg_mask = 0, reg_value = 0;
int ret = 0;
// video pipe selection
reg_mask = 0;
reg_value = 0;
video_pipe_cfg = &video_pipe->pipe_cfg[MAXIM2C_PIPE_O_ID_Y];
if (video_pipe_cfg->pipe_enable) {
reg_mask |= (0x7 << 0);
pipe_idx = video_pipe_cfg->pipe_idx;
link_idx = video_pipe_cfg->link_idx;
reg_value |= ((pipe_idx + link_idx * MAXIM2C_PIPE_I_ID_MAX) << 0);
}
video_pipe_cfg = &video_pipe->pipe_cfg[MAXIM2C_PIPE_O_ID_Z];
if (video_pipe_cfg->pipe_enable) {
reg_mask |= (0x7 << 3);
pipe_idx = video_pipe_cfg->pipe_idx;
link_idx = video_pipe_cfg->link_idx;
reg_value |= ((pipe_idx + link_idx * MAXIM2C_PIPE_I_ID_MAX) << 3);
}
ret |= maxim2c_i2c_update_reg(client,
0x0161, reg_mask, reg_value);
return ret;
}
static int maxim2c_video_pipe_run_init_seq(maxim2c_t *maxim2c)
{
struct i2c_client *client = maxim2c->client;
struct device *dev = &client->dev;
maxim2c_video_pipe_t *video_pipe = &maxim2c->video_pipe;
struct maxim2c_pipe_cfg *video_pipe_cfg = NULL;
struct maxim2c_i2c_init_seq *init_seq = NULL;
int i = 0;
int ret = 0;
// video pipe init sequence
for (i = 0; i < MAXIM2C_PIPE_O_ID_MAX; i++) {
video_pipe_cfg = &video_pipe->pipe_cfg[i];
init_seq = &video_pipe_cfg->pipe_init_seq;
ret = maxim2c_i2c_run_init_seq(client, init_seq);
if (ret) {
dev_err(dev, "pipe id = %d init sequence error\n", i);
return ret;
}
}
// video pipe parallel mode init sequence
init_seq = &video_pipe->parallel_init_seq;
ret = maxim2c_i2c_run_init_seq(client, init_seq);
if (ret) {
dev_err(dev, "pipe parallel init sequence error\n");
return ret;
}
return 0;
}
static int maxim2c_video_pipe_config_parse_dt(struct device *dev,
maxim2c_video_pipe_t *video_pipe,
struct device_node *parent_node)
{
struct device_node *node = NULL;
struct device_node *init_seq_node = NULL;
struct maxim2c_i2c_init_seq *init_seq = NULL;
struct maxim2c_pipe_cfg *video_pipe_cfg = NULL;
const char *pipe_cfg_name = "video-pipe-config";
u32 sub_idx = 0, pipe_id = 0;
u32 value = 0;
int ret = 0;
node = NULL;
sub_idx = 0;
while ((node = of_get_next_child(parent_node, node))) {
if (!strncasecmp(node->name,
pipe_cfg_name,
strlen(pipe_cfg_name))) {
if (sub_idx >= MAXIM2C_PIPE_O_ID_MAX) {
dev_err(dev, "%pOF: Too many matching %s node\n",
parent_node, pipe_cfg_name);
of_node_put(node);
break;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
sub_idx++;
continue;
}
/* Video Pipe: pipe id */
ret = of_property_read_u32(node, "pipe-id", &pipe_id);
if (ret) {
// if pipe_id is error, parse next node
dev_err(dev, "Can not get pipe-id property!");
sub_idx++;
continue;
}
if (pipe_id >= MAXIM2C_PIPE_O_ID_MAX) {
// if pipe_id is error, parse next node
dev_err(dev, "Error pipe-id = %d!", pipe_id);
sub_idx++;
continue;
}
video_pipe_cfg = &video_pipe->pipe_cfg[pipe_id];
/* Video Pipe: pipe enable */
video_pipe_cfg->pipe_enable = 1;
video_pipe->pipe_enable_mask |= BIT(pipe_id);
dev_info(dev, "video pipe id = %d: pipe enable = %d\n",
pipe_id, video_pipe_cfg->pipe_enable);
/* Video Pipe: other config */
ret = of_property_read_u32(node, "pipe-idx", &value);
if (ret == 0) {
dev_info(dev, "pipe-idx property: %d", value);
video_pipe_cfg->pipe_idx = value;
}
ret = of_property_read_u32(node, "link-idx", &value);
if (ret == 0) {
dev_info(dev, "link-idx property: %d", value);
video_pipe_cfg->link_idx = value;
}
init_seq_node = of_get_child_by_name(node, "pipe-init-sequence");
if (!IS_ERR_OR_NULL(init_seq_node)) {
dev_info(dev, "load pipe-init-sequence\n");
init_seq = &video_pipe_cfg->pipe_init_seq;
maxim2c_i2c_load_init_seq(dev, init_seq_node, init_seq);
of_node_put(init_seq_node);
}
sub_idx++;
}
}
node = of_get_child_by_name(parent_node, "parallel-mode-config");
if (!IS_ERR_OR_NULL(node)) {
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
of_node_put(node);
return 0;
}
init_seq_node = of_get_child_by_name(node, "parallel-init-sequence");
if (!IS_ERR_OR_NULL(init_seq_node)) {
dev_info(dev, "load parallel-init-sequence\n");
init_seq = &video_pipe->parallel_init_seq;
maxim2c_i2c_load_init_seq(dev, init_seq_node, init_seq);
of_node_put(init_seq_node);
}
of_node_put(node);
}
return 0;
}
int maxim2c_video_pipe_parse_dt(maxim2c_t *maxim2c, struct device_node *of_node)
{
struct device *dev = &maxim2c->client->dev;
struct device_node *node = NULL;
maxim2c_video_pipe_t *video_pipe = &maxim2c->video_pipe;
int ret = 0;
dev_info(dev, "=== maxim2c video pipe parse dt ===\n");
node = of_get_child_by_name(of_node, "video-pipes");
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: video-pipes\n",
of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
of_node_put(node);
return -ENODEV;
}
ret = maxim2c_video_pipe_config_parse_dt(dev, video_pipe, node);
of_node_put(node);
return ret;
}
EXPORT_SYMBOL(maxim2c_video_pipe_parse_dt);
int maxim2c_video_pipe_mask_enable(maxim2c_t *maxim2c, u8 video_pipe_mask, bool enable)
{
struct i2c_client *client = maxim2c->client;
struct device *dev = &client->dev;
maxim2c_video_pipe_t *video_pipe = &maxim2c->video_pipe;
struct maxim2c_pipe_cfg *video_pipe_cfg = NULL;
u8 reg_mask = 0, reg_value = 0;
int i = 0;
int ret = 0;
dev_dbg(dev, "%s, video_pipe_mask = 0x%x, enable = %d\n",
__func__, video_pipe_mask, enable);
reg_mask = 0;
reg_value = 0;
// video pipe enable
for (i = 0; i < MAXIM2C_PIPE_O_ID_MAX; i++) {
video_pipe_cfg = &video_pipe->pipe_cfg[i];
if (video_pipe_cfg->pipe_enable
&& (video_pipe_mask & BIT(i))) {
reg_mask |= BIT(i);
if (enable)
reg_value |= BIT(i);
}
}
if (reg_mask != 0) {
ret |= maxim2c_i2c_update_reg(client,
0x0160, reg_mask, reg_value);
}
return ret;
}
EXPORT_SYMBOL(maxim2c_video_pipe_mask_enable);
int maxim2c_video_pipe_linkid_enable(maxim2c_t *maxim2c, u8 link_id, bool enable)
{
struct i2c_client *client = maxim2c->client;
struct device *dev = &client->dev;
maxim2c_video_pipe_t *video_pipe = &maxim2c->video_pipe;
struct maxim2c_pipe_cfg *video_pipe_cfg = NULL;
u8 reg_mask = 0, reg_value = 0;
int i = 0;
int ret = 0;
dev_dbg(dev, "%s, link_id = %d, enable = %d\n",
__func__, link_id, enable);
reg_mask = 0;
reg_value = 0;
// video pipe enable
for (i = 0; i < MAXIM2C_PIPE_O_ID_MAX; i++) {
video_pipe_cfg = &video_pipe->pipe_cfg[i];
if (video_pipe_cfg->pipe_enable
&& (video_pipe_cfg->link_idx == link_id)) {
reg_mask = BIT(i);
if (enable)
reg_value = BIT(i);
}
}
if (reg_mask != 0) {
ret = maxim2c_i2c_update_reg(client,
0x0160, reg_mask, reg_value);
}
return ret;
}
EXPORT_SYMBOL(maxim2c_video_pipe_linkid_enable);
void maxim2c_video_pipe_data_init(maxim2c_t *maxim2c)
{
maxim2c_video_pipe_t *video_pipe = &maxim2c->video_pipe;
struct maxim2c_pipe_cfg *video_pipe_cfg = NULL;
int i = 0;
video_pipe->pipe_enable_mask = 0;
video_pipe->parallel_init_seq.reg_init_seq = NULL;
for (i = 0; i < MAXIM2C_PIPE_O_ID_MAX; i++) {
video_pipe_cfg = &video_pipe->pipe_cfg[i];
video_pipe_cfg->pipe_enable = 0;
video_pipe_cfg->pipe_idx = MAXIM2C_PIPE_I_ID_Z;
video_pipe_cfg->link_idx = i;
video_pipe_cfg->pipe_init_seq.reg_init_seq = NULL;
}
}
EXPORT_SYMBOL(maxim2c_video_pipe_data_init);
int maxim2c_video_pipe_hw_init(maxim2c_t *maxim2c)
{
struct device *dev = &maxim2c->client->dev;
u8 pipe_enable_mask = 0;
int ret = 0;
ret = maxim2c_video_pipe_select(maxim2c);
if (ret) {
dev_err(dev, "%s: video pipe select error\n", __func__);
return ret;
}
pipe_enable_mask = maxim2c->video_pipe.pipe_enable_mask;
ret = maxim2c_video_pipe_mask_enable(maxim2c, pipe_enable_mask, true);
if (ret) {
dev_err(dev, "%s: video pipe mask enable error\n", __func__);
return ret;
}
ret = maxim2c_video_pipe_run_init_seq(maxim2c);
if (ret) {
dev_err(dev, "%s: video pipe run init seq error\n", __func__);
return ret;
}
return 0;
}
EXPORT_SYMBOL(maxim2c_video_pipe_hw_init);