media: i2c: maxim: local: maxim4c: driver version v3.00.00

1. local deserializer and remote devices are associated through i2c-mux
2. remote camera is abstracted as v4l2 subdev

Signed-off-by: Cai Wenzhong <cwz@rock-chips.com>
Change-Id: Id827c4a9b13a2280ec6b4b2114fa389b3e31674c
This commit is contained in:
Cai Wenzhong
2023-12-28 09:49:47 +08:00
committed by Tao Huang
parent beb9974b6f
commit acb67fd645
30 changed files with 698 additions and 2003 deletions

View File

@@ -692,7 +692,7 @@ config VIDEO_MAX96756
module will be called max96756.
source "drivers/media/i2c/maxim2c/Kconfig"
source "drivers/media/i2c/maxim4c/Kconfig"
source "drivers/media/i2c/maxim/Kconfig"
comment "Video and audio decoders"

View File

@@ -11,7 +11,7 @@ obj-$(CONFIG_VIDEO_NVP6158) += nvp6158_drv/
obj-$(CONFIG_VIDEO_NVP6188) += nvp6188.o
obj-$(CONFIG_VIDEO_NVP6324) += jaguar1_drv/
obj-$(CONFIG_VIDEO_DES_MAXIM2C) += maxim2c/
obj-$(CONFIG_VIDEO_DES_MAXIM4C) += maxim4c/
obj-$(CONFIG_VIDEO_MAXIM_SERDES) += maxim/
obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o

View File

@@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Maxim GMSL Serdes devices
#
config VIDEO_MAXIM_SERDES
tristate "Maxim GMSL Serdes Support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
This driver supports the Maxim GMSL Serdes.
To compile this driver as a module, choose M here: the
module will be called maxim.
source "drivers/media/i2c/maxim/local/Kconfig"

View File

@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_MAXIM_SERDES) += local/

View File

@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Maxim GMSL deserializer devices
#
menu "Maxim Deserializer devices support"
visible if VIDEO_MAXIM_SERDES
source "drivers/media/i2c/maxim/local/maxim4c/Kconfig"
endmenu

View File

@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_MAXIM_DES_MAXIM4C) += maxim4c/

View File

@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Maxim Quad GMSL deserializer devices
#
config VIDEO_MAXIM_DES_MAXIM4C
tristate "Maxim Quad GMSL deserializer support"
depends on VIDEO_MAXIM_SERDES
help
This driver supports the Maxim Quad GMSL2/GMSL1 deserializer.
To compile this driver as a module, choose M here: the
module will be called maxim4c.

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_DES_MAXIM4C) += maxim4c.o
obj-$(CONFIG_VIDEO_MAXIM_DES_MAXIM4C) += maxim4c.o
maxim4c-objs += maxim4c_i2c.o \
maxim4c_mipi_txphy.o \
maxim4c_video_pipe.o \
@@ -9,7 +9,3 @@ maxim4c-objs += maxim4c_i2c.o \
maxim4c_v4l2.o \
maxim4c_drv.o \
maxim4c_debugfs.o
obj-$(CONFIG_MAXIM4C_SER_MAX9295) += remote_max9295.o
obj-$(CONFIG_MAXIM4C_SER_MAX96715) += remote_max96715.o
obj-$(CONFIG_MAXIM4C_SER_MAX96717) += remote_max96717.o

View File

@@ -10,11 +10,13 @@
#ifndef __MAXIM4C_API_H__
#define __MAXIM4C_API_H__
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include "maxim4c_i2c.h"
#include "maxim4c_link.h"
#include "maxim4c_video_pipe.h"
#include "maxim4c_mipi_txphy.h"
#include "maxim4c_remote.h"
#include "maxim4c_pattern.h"
#include "maxim4c_drv.h"
@@ -26,28 +28,11 @@
/* Maxim Deserializer pwdn on/off enable */
#define MAXIM4C_LOCAL_DES_ON_OFF_EN 0
/* maxim4c i2c api */
int maxim4c_i2c_write_reg(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u16 val_len, u32 reg_val);
int maxim4c_i2c_read_reg(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u16 val_len, u32 *reg_val);
int maxim4c_i2c_update_reg(struct i2c_client *client,
u16 reg_addr, u16 reg_len,
u32 val_len, u32 val_mask, u32 reg_val);
int maxim4c_i2c_write_byte(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u8 reg_val);
int maxim4c_i2c_read_byte(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u8 *reg_val);
int maxim4c_i2c_update_byte(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u8 val_mask, u8 reg_val);
int maxim4c_i2c_write_array(struct i2c_client *client,
const struct maxim4c_i2c_regval *regs);
int maxim4c_i2c_load_init_seq(struct device *dev,
struct device_node *node, struct maxim4c_i2c_init_seq *init_seq);
int maxim4c_i2c_run_init_seq(struct i2c_client *client,
struct maxim4c_i2c_init_seq *init_seq);
/* maxim4c i2c mux api */
int maxim4c_i2c_mux_enable(maxim4c_t *maxim4c, u8 def_mask);
int maxim4c_i2c_mux_disable(maxim4c_t *maxim4c);
int maxim4c_i2c_mux_init(maxim4c_t *maxim4c);
int maxim4c_i2c_mux_deinit(maxim4c_t *maxim4c);
/* maxim4c link api */
u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask);
@@ -76,15 +61,8 @@ int maxim4c_dphy_dpll_predef_set(maxim4c_t *maxim4c, s64 link_freq_hz);
int maxim4c_mipi_csi_output(maxim4c_t *maxim4c, bool enable);
/* maxim4c remote api */
int maxim4c_remote_mfd_add_devices(maxim4c_t *maxim4c);
int maxim4c_remote_devices_init(maxim4c_t *maxim4c, u8 link_init_mask);
int maxim4c_remote_devices_deinit(maxim4c_t *maxim4c, u8 link_init_mask);
int maxim4c_remote_load_init_seq(maxim4c_remote_t *remote_device);
int maxim4c_remote_i2c_addr_select(maxim4c_remote_t *remote_device, u32 i2c_id);
int maxim4c_remote_i2c_client_init(maxim4c_remote_t *remote_device,
struct i2c_client *des_client);
int maxim4c_remote_device_register(maxim4c_t *maxim4c,
maxim4c_remote_t *remote_device);
int maxim4c_remote_devices_power(maxim4c_t *maxim4c, u8 link_mask, int on);
int maxim4c_remote_devices_s_stream(maxim4c_t *maxim4c, u8 link_mask, int enable);
/* maxim4c v4l2 subdev api */
int maxim4c_v4l2_subdev_init(maxim4c_t *maxim4c);

View File

@@ -42,6 +42,11 @@
* 2. enable hot plug detect for partial links are locked.
* 3. remote device hot plug init disable lock irq.
*
* V3.00.00
* 1. deserializer and serializer are associated through i2c-mux
* 2. remote serializer is abstracted as v4l2 subdev
* 3. remote camera is bound to remote serializer
*
*/
#include <linux/clk.h>
#include <linux/i2c.h>
@@ -65,13 +70,11 @@
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include "maxim4c_api.h"
#define DRIVER_VERSION KERNEL_VERSION(2, 0x05, 0x00)
#define DRIVER_VERSION KERNEL_VERSION(3, 0x00, 0x00)
#define MAXIM4C_XVCLK_FREQ 25000000
@@ -93,9 +96,7 @@ static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
msleep(10);
}
ret = maxim4c_i2c_read_byte(client,
MAXIM4C_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chipid);
ret = maxim4c_i2c_read_reg(client, MAXIM4C_REG_CHIP_ID, &chipid);
if (ret == 0) {
if (chipid == maxim4c->chipid) {
if (chipid == MAX96712_CHIP_ID) {
@@ -121,7 +122,7 @@ static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
static irqreturn_t maxim4c_hot_plug_detect_irq_handler(int irq, void *dev_id)
{
struct maxim4c *maxim4c = dev_id;
maxim4c_t *maxim4c = dev_id;
struct device *dev = &maxim4c->client->dev;
int lock_gpio_level = 0;
@@ -178,7 +179,7 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
{
struct maxim4c_hot_plug_work *hot_plug_work =
container_of(work, struct maxim4c_hot_plug_work, state_d_work.work);
struct maxim4c *maxim4c =
maxim4c_t *maxim4c =
container_of(hot_plug_work, struct maxim4c, hot_plug_work);
struct device *dev = &maxim4c->client->dev;
u8 curr_lock_state = 0, last_lock_state = 0, link_lock_change = 0;
@@ -196,7 +197,8 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
last_lock_state = maxim4c->link_lock_state;
if ((maxim4c->hot_plug_state == MAXIM4C_HOT_PLUG_OUT)
&& (last_lock_state == link_enable_mask)) {
maxim4c_link_select_remote_control(maxim4c, 0);
// i2c mux enable: disable all remote channel
maxim4c_i2c_mux_enable(maxim4c, 0x00);
}
curr_lock_state = maxim4c_link_get_lock_state(maxim4c, link_enable_mask);
@@ -217,7 +219,8 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
if (maxim4c->hot_plug_irq > 0)
disable_irq(maxim4c->hot_plug_irq);
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_A);
// Link A remote device start stream
maxim4c_remote_devices_s_stream(maxim4c, MAXIM4C_LINK_MASK_A, 1);
if (maxim4c->hot_plug_irq > 0)
enable_irq(maxim4c->hot_plug_irq);
@@ -226,6 +229,9 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
} else {
dev_info(dev, "Link A plug out\n");
// Link A remote device stop stream
maxim4c_remote_devices_s_stream(maxim4c, MAXIM4C_LINK_MASK_A, 0);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
}
@@ -239,7 +245,8 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
if (maxim4c->hot_plug_irq > 0)
disable_irq(maxim4c->hot_plug_irq);
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_B);
// Link B remote device start stream
maxim4c_remote_devices_s_stream(maxim4c, MAXIM4C_LINK_MASK_B, 1);
if (maxim4c->hot_plug_irq > 0)
enable_irq(maxim4c->hot_plug_irq);
@@ -248,6 +255,9 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
} else {
dev_info(dev, "Link B plug out\n");
// Link B remote device stop stream
maxim4c_remote_devices_s_stream(maxim4c, MAXIM4C_LINK_MASK_B, 0);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
}
@@ -261,7 +271,8 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
if (maxim4c->hot_plug_irq > 0)
disable_irq(maxim4c->hot_plug_irq);
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_C);
// Link C remote device start stream
maxim4c_remote_devices_s_stream(maxim4c, MAXIM4C_LINK_MASK_C, 1);
if (maxim4c->hot_plug_irq > 0)
enable_irq(maxim4c->hot_plug_irq);
@@ -270,6 +281,9 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
} else {
dev_info(dev, "Link C plug out\n");
// Link C remote device stop stream
maxim4c_remote_devices_s_stream(maxim4c, MAXIM4C_LINK_MASK_C, 0);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
}
@@ -283,7 +297,8 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
if (maxim4c->hot_plug_irq > 0)
disable_irq(maxim4c->hot_plug_irq);
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_D);
// Link D remote device start stream
maxim4c_remote_devices_s_stream(maxim4c, MAXIM4C_LINK_MASK_D, 1);
if (maxim4c->hot_plug_irq > 0)
enable_irq(maxim4c->hot_plug_irq);
@@ -292,13 +307,16 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
} else {
dev_info(dev, "Link D plug out\n");
// Link D remote device stop stream
maxim4c_remote_devices_s_stream(maxim4c, MAXIM4C_LINK_MASK_D, 0);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
}
if (curr_lock_state == link_enable_mask) {
// remote control mask enable
maxim4c_link_select_remote_control(maxim4c, link_enable_mask);
// i2c mux enable: enable all enabled link for remote control
maxim4c_i2c_mux_enable(maxim4c, link_enable_mask);
} else {
queue_delayed_work(maxim4c->hot_plug_work.state_check_wq,
&maxim4c->hot_plug_work.state_d_work,
@@ -363,10 +381,10 @@ static inline u32 maxim4c_cal_delay(u32 cycles)
return DIV_ROUND_UP(cycles, MAXIM4C_XVCLK_FREQ / 1000 / 1000);
}
static int maxim4c_local_device_power_on(maxim4c_t *maxim4c)
static int maxim4c_device_power_on(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret;
int ret = 0;
ret = regulator_bulk_enable(MAXIM4C_NUM_SUPPLIES, maxim4c->supplies);
if (ret < 0) {
@@ -374,27 +392,23 @@ static int maxim4c_local_device_power_on(maxim4c_t *maxim4c)
return -EINVAL;
}
if (!IS_ERR(maxim4c->pwdn_gpio)) {
dev_info(dev, "local device pwdn gpio on\n");
gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 1);
usleep_range(10000, 11000);
ret = regulator_enable(maxim4c->pwdn_regulator);
if (ret < 0) {
dev_err(dev, "Unable to turn pwdn regulator on\n");
return ret;
}
return 0;
}
static void maxim4c_local_device_power_off(maxim4c_t *maxim4c)
static void maxim4c_device_power_off(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret;
int ret = 0;
if (!IS_ERR(maxim4c->pwdn_gpio)) {
dev_info(dev, "local device pwdn gpio off\n");
gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 0);
}
ret = regulator_disable(maxim4c->pwdn_regulator);
if (ret < 0)
dev_warn(dev, "Unable to turn pwdn regulator off\n");
ret = regulator_bulk_disable(MAXIM4C_NUM_SUPPLIES, maxim4c->supplies);
if (ret < 0) {
@@ -402,64 +416,36 @@ static void maxim4c_local_device_power_off(maxim4c_t *maxim4c)
}
}
static int maxim4c_remote_device_power_on(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret;
dev_dbg(dev, "Turn PoC on\n");
ret = regulator_enable(maxim4c->poc_regulator);
if (ret < 0) {
dev_err(dev, "Unable to turn PoC on\n");
return ret;
}
return 0;
}
static int maxim4c_remote_device_power_off(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret;
dev_dbg(dev, "Turn PoC off\n");
ret = regulator_disable(maxim4c->poc_regulator);
if (ret < 0)
dev_warn(dev, "Unable to turn PoC off\n");
return 0;
}
static int maxim4c_runtime_resume(struct device *dev)
{
#if MAXIM4C_LOCAL_DES_ON_OFF_EN
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
int ret = 0;
#if MAXIM4C_LOCAL_DES_ON_OFF_EN
ret |= maxim4c_local_device_power_on(maxim4c);
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
ret |= maxim4c_remote_device_power_on(maxim4c);
ret |= maxim4c_device_power_on(maxim4c);
return ret;
#else
return 0;
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
}
static int maxim4c_runtime_suspend(struct device *dev)
{
#if MAXIM4C_LOCAL_DES_ON_OFF_EN
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
int ret = 0;
ret |= maxim4c_remote_device_power_off(maxim4c);
#if MAXIM4C_LOCAL_DES_ON_OFF_EN
maxim4c_local_device_power_off(maxim4c);
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
maxim4c_device_power_off(maxim4c);
return ret;
#else
return 0;
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
}
static const struct dev_pm_ops maxim4c_pm_ops = {
@@ -470,7 +456,9 @@ static const struct dev_pm_ops maxim4c_pm_ops = {
static void maxim4c_module_data_init(maxim4c_t *maxim4c)
{
maxim4c_link_data_init(maxim4c);
maxim4c_video_pipe_data_init(maxim4c);
maxim4c_mipi_txphy_data_init(maxim4c);
}
@@ -564,23 +552,17 @@ static int maxim4c_module_hw_previnit(maxim4c_t *maxim4c)
int ret = 0;
// All links disable at beginning.
ret = maxim4c_i2c_write_byte(client,
0x0006, MAXIM4C_I2C_REG_ADDR_16BITS,
0xF0);
ret = maxim4c_i2c_write_reg(client, 0x0006, 0xF0);
if (ret)
return ret;
// MIPI CSI output disable.
ret = maxim4c_i2c_write_byte(client,
0x040B, MAXIM4C_I2C_REG_ADDR_16BITS,
0x00);
ret = maxim4c_i2c_write_reg(client, 0x040B, 0x00);
if (ret)
return ret;
// MIPI TXPHY standby
ret = maxim4c_i2c_update_byte(client,
0x08A2, MAXIM4C_I2C_REG_ADDR_16BITS,
0xF0, 0x00);
ret = maxim4c_i2c_update_reg(client, 0x08A2, 0xF0, 0x00);
if (ret)
return ret;
@@ -593,9 +575,7 @@ static int maxim4c_module_hw_postinit(maxim4c_t *maxim4c)
int ret = 0;
// video pipe disable all
ret |= maxim4c_i2c_write_byte(client,
0x00F4, MAXIM4C_I2C_REG_ADDR_16BITS,
0);
ret |= maxim4c_i2c_write_reg(client, 0x00F4, 0);
// remote control disable all
ret |= maxim4c_link_select_remote_control(maxim4c, 0);
@@ -649,6 +629,18 @@ int maxim4c_module_hw_init(maxim4c_t *maxim4c)
}
EXPORT_SYMBOL(maxim4c_module_hw_init);
static int maxim4c_configure_regulators(maxim4c_t *maxim4c)
{
unsigned int i;
for (i = 0; i < MAXIM4C_NUM_SUPPLIES; i++)
maxim4c->supplies[i].supply = maxim4c_supply_names[i];
return devm_regulator_bulk_get(&maxim4c->client->dev,
MAXIM4C_NUM_SUPPLIES,
maxim4c->supplies);
}
static int maxim4c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -657,7 +649,6 @@ static int maxim4c_probe(struct i2c_client *client,
maxim4c_t *maxim4c = NULL;
u32 chip_id;
int ret = 0;
unsigned int i;
dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff);
@@ -694,53 +685,35 @@ static int maxim4c_probe(struct i2c_client *client,
return -EINVAL;
}
maxim4c->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
if (IS_ERR(maxim4c->pwdn_gpio))
dev_warn(dev, "Failed to get pwdn-gpios, maybe no use\n");
else
usleep_range(1000, 1100);
ret = maxim4c_configure_regulators(maxim4c);
if (ret) {
dev_err(dev, "Failed to get power regulators\n");
return ret;
}
maxim4c->pwdn_regulator = devm_regulator_get(dev, "pwdn");
if (IS_ERR(maxim4c->pwdn_regulator)) {
if (PTR_ERR(maxim4c->pwdn_regulator) != -EPROBE_DEFER)
dev_err(dev, "Unable to get pwdn regulator (%ld)\n",
PTR_ERR(maxim4c->pwdn_regulator));
else
dev_err(dev, "Get pwdn regulator deferred\n");
ret = PTR_ERR(maxim4c->pwdn_regulator);
return ret;
}
maxim4c->lock_gpio = devm_gpiod_get(dev, "lock", GPIOD_IN);
if (IS_ERR(maxim4c->lock_gpio))
dev_warn(dev, "Failed to get lock-gpios\n");
for (i = 0; i < MAXIM4C_NUM_SUPPLIES; i++)
maxim4c->supplies[i].supply = maxim4c_supply_names[i];
ret = devm_regulator_bulk_get(dev, MAXIM4C_NUM_SUPPLIES,
maxim4c->supplies);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Unable to get supply regulators\n");
else
dev_warn(dev, "Get PoC regulator deferred\n");
return ret;
}
maxim4c->poc_regulator = devm_regulator_get(dev, "poc");
if (IS_ERR(maxim4c->poc_regulator)) {
if (PTR_ERR(maxim4c->poc_regulator) != -EPROBE_DEFER)
dev_err(dev, "Unable to get PoC regulator (%ld)\n",
PTR_ERR(maxim4c->poc_regulator));
else
dev_err(dev, "Get PoC regulator deferred\n");
ret = PTR_ERR(maxim4c->poc_regulator);
#if !MAXIM4C_TEST_PATTERN
return ret;
#endif
}
mutex_init(&maxim4c->mutex);
ret = maxim4c_local_device_power_on(maxim4c);
ret = maxim4c_device_power_on(maxim4c);
if (ret)
goto err_destroy_mutex;
ret = maxim4c_remote_device_power_on(maxim4c);
if (ret)
dev_warn(dev, "Power on PoC regulator failed\n");
pm_runtime_set_active(dev);
pm_runtime_get_noresume(dev);
pm_runtime_enable(dev);
@@ -749,14 +722,17 @@ static int maxim4c_probe(struct i2c_client *client,
if (ret)
goto err_power_off;
// client->dev->driver_data = subdev
// subdev->dev->driver_data = maxim4c
/*
* client->dev->driver_data = subdev
* subdev->dev->driver_data = maxim4c
*/
ret = maxim4c_v4l2_subdev_init(maxim4c);
if (ret) {
dev_err(dev, "maxim4c probe v4l2 subdev init error\n");
goto err_power_off;
}
/* maxim4c test pattern */
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_data_init(maxim4c);
if (ret)
@@ -789,10 +765,13 @@ static int maxim4c_probe(struct i2c_client *client,
goto err_dbgfs_deinit;
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
ret = maxim4c_remote_mfd_add_devices(maxim4c);
ret = maxim4c_i2c_mux_init(maxim4c);
if (ret)
goto err_dbgfs_deinit;
// i2c mux enable: default disable all remote channel
maxim4c_i2c_mux_enable(maxim4c, 0x00);
maxim4c_lock_irq_init(maxim4c);
maxim4c_lock_state_work_init(maxim4c);
@@ -805,13 +784,15 @@ static int maxim4c_probe(struct i2c_client *client,
err_dbgfs_deinit:
maxim4c_dbgfs_deinit(maxim4c);
err_subdev_deinit:
maxim4c_v4l2_subdev_deinit(maxim4c);
err_power_off:
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
maxim4c_remote_device_power_off(maxim4c);
maxim4c_local_device_power_off(maxim4c);
maxim4c_device_power_off(maxim4c);
err_destroy_mutex:
mutex_destroy(&maxim4c->mutex);
@@ -820,7 +801,8 @@ err_destroy_mutex:
static int maxim4c_remove(struct i2c_client *client)
{
maxim4c_t *maxim4c = i2c_get_clientdata(client);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_lock_state_work_deinit(maxim4c);
@@ -828,11 +810,13 @@ static int maxim4c_remove(struct i2c_client *client)
maxim4c_v4l2_subdev_deinit(maxim4c);
maxim4c_i2c_mux_deinit(maxim4c);
mutex_destroy(&maxim4c->mutex);
pm_runtime_disable(&client->dev);
if (!pm_runtime_status_suspended(&client->dev))
maxim4c_local_device_power_off(maxim4c);
maxim4c_device_power_off(maxim4c);
pm_runtime_set_suspended(&client->dev);
return 0;

View File

@@ -7,29 +7,30 @@
#ifndef __MAXIM4C_DRV_H__
#define __MAXIM4C_DRV_H__
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/workqueue.h>
#include <linux/rk-camera-module.h>
#include <linux/mfd/core.h>
#include <linux/regulator/consumer.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include "maxim4c_i2c.h"
#include "maxim4c_link.h"
#include "maxim4c_video_pipe.h"
#include "maxim4c_mipi_txphy.h"
#include "maxim4c_remote.h"
#include "maxim4c_pattern.h"
// max96712/max96722 chip id register and value
#define MAXIM4C_REG_CHIP_ID 0x0D
#define MAX96712_CHIP_ID 0xA0
#define MAX96722_CHIP_ID 0xA1
#define MAXIM4C_NUM_SUPPLIES 2
/* power supply numbers */
#define MAXIM4C_NUM_SUPPLIES 2
enum {
MAXIM4C_HOT_PLUG_OUT = 0,
@@ -58,11 +59,11 @@ struct maxim4c_mode {
typedef struct maxim4c {
struct i2c_client *client;
struct maxim4c_i2c_mux i2c_mux;
struct clk *xvclk;
struct gpio_desc *pwdn_gpio;
struct gpio_desc *lock_gpio;
struct regulator_bulk_data supplies[MAXIM4C_NUM_SUPPLIES];
struct regulator *poc_regulator;
struct regulator *pwdn_regulator;
struct gpio_desc *lock_gpio;
struct mutex mutex;
@@ -106,9 +107,6 @@ typedef struct maxim4c {
struct maxim4c_i2c_init_seq extra_init_seq;
struct mfd_cell remote_mfd_devs[MAXIM4C_LINK_ID_MAX];
maxim4c_remote_t *remote_device[MAXIM4C_LINK_ID_MAX];
struct dentry *dbgfs_root;
} maxim4c_t;

View File

@@ -7,13 +7,15 @@
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "maxim4c_i2c.h"
#include <linux/i2c-mux.h>
#include <linux/delay.h>
#include "maxim4c_api.h"
/* Write registers up to 4 at a time */
int maxim4c_i2c_write_reg(struct i2c_client *client,
int maxim4c_i2c_write(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u32 val_len, u32 reg_val)
{
u32 buf_i, val_i;
@@ -54,10 +56,10 @@ int maxim4c_i2c_write_reg(struct i2c_client *client,
return 0;
}
EXPORT_SYMBOL(maxim4c_i2c_write_reg);
EXPORT_SYMBOL(maxim4c_i2c_write);
/* Read registers up to 4 at a time */
int maxim4c_i2c_read_reg(struct i2c_client *client,
int maxim4c_i2c_read(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u32 val_len, u32 *reg_val)
{
struct i2c_msg msgs[2];
@@ -102,74 +104,74 @@ int maxim4c_i2c_read_reg(struct i2c_client *client,
return 0;
}
EXPORT_SYMBOL(maxim4c_i2c_read_reg);
EXPORT_SYMBOL(maxim4c_i2c_read);
/* Update registers up to 4 at a time */
int maxim4c_i2c_update_reg(struct i2c_client *client,
int maxim4c_i2c_update(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u32 val_len, u32 val_mask, u32 reg_val)
{
u32 value;
int ret;
ret = maxim4c_i2c_read_reg(client, reg_addr, reg_len, val_len, &value);
ret = maxim4c_i2c_read(client, reg_addr, reg_len, val_len, &value);
if (ret)
return ret;
value &= ~val_mask;
value |= (reg_val & val_mask);
ret = maxim4c_i2c_write_reg(client, reg_addr, reg_len, val_len, value);
ret = maxim4c_i2c_write(client, reg_addr, reg_len, val_len, value);
return ret;
}
EXPORT_SYMBOL(maxim4c_i2c_update_reg);
EXPORT_SYMBOL(maxim4c_i2c_update);
int maxim4c_i2c_write_byte(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u8 reg_val)
int maxim4c_i2c_write_reg(struct i2c_client *client,
u16 reg_addr, u8 reg_val)
{
int ret = 0;
ret = maxim4c_i2c_write_reg(client,
reg_addr, reg_len,
ret = maxim4c_i2c_write(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_08BITS, reg_val);
return ret;
}
EXPORT_SYMBOL(maxim4c_i2c_write_byte);
EXPORT_SYMBOL(maxim4c_i2c_write_reg);
int maxim4c_i2c_read_byte(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u8 *reg_val)
int maxim4c_i2c_read_reg(struct i2c_client *client,
u16 reg_addr, u8 *reg_val)
{
int ret = 0;
u32 value = 0;
u8 *value_be_p = (u8 *)&value;
ret = maxim4c_i2c_read_reg(client,
reg_addr, reg_len,
ret = maxim4c_i2c_read(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_08BITS, &value);
*reg_val = *value_be_p;
return ret;
}
EXPORT_SYMBOL(maxim4c_i2c_read_byte);
EXPORT_SYMBOL(maxim4c_i2c_read_reg);
int maxim4c_i2c_update_byte(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u8 val_mask, u8 reg_val)
int maxim4c_i2c_update_reg(struct i2c_client *client,
u16 reg_addr, u8 val_mask, u8 reg_val)
{
u8 value;
int ret;
ret = maxim4c_i2c_read_byte(client, reg_addr, reg_len, &value);
ret = maxim4c_i2c_read_reg(client, reg_addr, &value);
if (ret)
return ret;
value &= ~val_mask;
value |= (reg_val & val_mask);
ret = maxim4c_i2c_write_byte(client, reg_addr, reg_len, value);
ret = maxim4c_i2c_write_reg(client, reg_addr, value);
return ret;
}
EXPORT_SYMBOL(maxim4c_i2c_update_byte);
EXPORT_SYMBOL(maxim4c_i2c_update_reg);
int maxim4c_i2c_write_array(struct i2c_client *client,
const struct maxim4c_i2c_regval *regs)
@@ -179,11 +181,11 @@ int maxim4c_i2c_write_array(struct i2c_client *client,
for (i = 0; (ret == 0) && (regs[i].reg_addr != MAXIM4C_REG_NULL); i++) {
if (regs[i].val_mask != 0)
ret = maxim4c_i2c_update_reg(client,
ret = maxim4c_i2c_update(client,
regs[i].reg_addr, regs[i].reg_len,
regs[i].val_len, regs[i].val_mask, regs[i].reg_val);
else
ret = maxim4c_i2c_write_reg(client,
ret = maxim4c_i2c_write(client,
regs[i].reg_addr, regs[i].reg_len,
regs[i].val_len, regs[i].reg_val);
@@ -397,11 +399,189 @@ int maxim4c_i2c_run_init_seq(struct i2c_client *client,
{
int ret = 0;
if (init_seq == NULL || init_seq->reg_init_seq == NULL)
if ((init_seq == NULL) || (init_seq->reg_init_seq == NULL))
return 0;
ret = maxim4c_i2c_write_array(client,
init_seq->reg_init_seq);
return ret;
}
EXPORT_SYMBOL(maxim4c_i2c_run_init_seq);
static int __maybe_unused maxim4c_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
{
maxim4c_t *maxim4c = i2c_mux_priv(muxc);
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
int ret = 0;
dev_dbg(dev, "maxim4c i2c mux select chan = %d\n", chan);
/* Channel select is disabled when configured in the disabled state. */
if (maxim4c->i2c_mux.mux_disable) {
dev_err(dev, "maxim4c i2c mux is disabled, select error\n");
return 0;
}
if (maxim4c->i2c_mux.mux_channel == chan)
return 0;
maxim4c->i2c_mux.mux_channel = chan;
ret = maxim4c_link_select_remote_control(maxim4c, BIT(chan));
if (ret) {
dev_err(dev, "maxim4c link select remote control error\n");
return ret;
}
return 0;
}
static int __maybe_unused maxim4c_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
{
maxim4c_t *maxim4c = i2c_mux_priv(muxc);
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
int ret = 0;
dev_dbg(dev, "maxim4c i2c mux deselect chan = %d\n", chan);
/* Channel deselect is disabled when configured in the disabled state. */
if (maxim4c->i2c_mux.mux_disable) {
dev_err(dev, "maxim4c i2c mux is disabled, deselect error\n");
return 0;
}
ret = maxim4c_link_select_remote_control(maxim4c, 0);
if (ret) {
dev_err(dev, "maxim4c link select remote control error\n");
return ret;
}
return 0;
}
int maxim4c_i2c_mux_disable(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret = 0;
dev_info(dev, "maxim4c i2c mux disable\n");
ret = maxim4c_link_select_remote_control(maxim4c, 0xff);
if (ret) {
dev_err(dev, "maxim4c link select remote control error\n");
return ret;
}
maxim4c->i2c_mux.mux_disable = true;
return 0;
}
EXPORT_SYMBOL(maxim4c_i2c_mux_disable);
int maxim4c_i2c_mux_enable(maxim4c_t *maxim4c, u8 def_mask)
{
struct device *dev = &maxim4c->client->dev;
int ret = 0;
dev_info(dev, "maxim4c i2c mux enable, mask = 0x%02x\n", def_mask);
ret = maxim4c_link_select_remote_control(maxim4c, def_mask);
if (ret) {
dev_err(dev, "maxim4c link select remote control error\n");
return ret;
}
maxim4c->i2c_mux.mux_disable = false;
maxim4c->i2c_mux.mux_channel = -1;
return 0;
}
EXPORT_SYMBOL(maxim4c_i2c_mux_enable);
static u32 maxim4c_i2c_mux_mask(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
struct device_node *i2c_mux;
struct device_node *node = NULL;
u32 i2c_mux_mask = 0;
/* Balance the of_node_put() performed by of_find_node_by_name(). */
of_node_get(dev->of_node);
i2c_mux = of_find_node_by_name(dev->of_node, "i2c-mux");
if (!i2c_mux) {
dev_err(dev, "Failed to find i2c-mux node\n");
return -EINVAL;
}
/* Identify which i2c-mux channels are enabled */
for_each_child_of_node(i2c_mux, node) {
u32 id = 0;
of_property_read_u32(node, "reg", &id);
if (id >= MAXIM4C_LINK_ID_MAX)
continue;
if (!of_device_is_available(node)) {
dev_dbg(dev, "Skipping disabled I2C bus port %u\n", id);
continue;
}
i2c_mux_mask |= BIT(id);
}
of_node_put(node);
of_node_put(i2c_mux);
return i2c_mux_mask;
}
int maxim4c_i2c_mux_init(maxim4c_t *maxim4c)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
u32 i2c_mux_mask = 0;
int i = 0;
int ret = 0;
dev_info(dev, "maxim4c i2c mux init\n");
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -ENODEV;
maxim4c->i2c_mux.muxc = i2c_mux_alloc(client->adapter, dev,
MAXIM4C_LINK_ID_MAX, 0, I2C_MUX_LOCKED,
maxim4c_i2c_mux_select, NULL);
if (!maxim4c->i2c_mux.muxc)
return -ENOMEM;
maxim4c->i2c_mux.muxc->priv = maxim4c;
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
ret = i2c_mux_add_adapter(maxim4c->i2c_mux.muxc, 0, i, 0);
if (ret) {
i2c_mux_del_adapters(maxim4c->i2c_mux.muxc);
return ret;
}
}
i2c_mux_mask = maxim4c_i2c_mux_mask(maxim4c);
maxim4c->i2c_mux.i2c_mux_mask = i2c_mux_mask;
dev_info(dev, "maxim4c i2c mux mask = 0x%x\n", i2c_mux_mask);
return 0;
}
EXPORT_SYMBOL(maxim4c_i2c_mux_init);
int maxim4c_i2c_mux_deinit(maxim4c_t *maxim4c)
{
if (maxim4c->i2c_mux.muxc)
i2c_mux_del_adapters(maxim4c->i2c_mux.muxc);
maxim4c->i2c_mux.i2c_mux_mask = 0;
maxim4c->i2c_mux.mux_disable = false;
maxim4c->i2c_mux.mux_channel = -1;
return 0;
}
EXPORT_SYMBOL(maxim4c_i2c_mux_deinit);

View File

@@ -8,6 +8,7 @@
#define __MAXIM4C_I2C_H__
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
/* register address: 8bit or 16bit */
#define MAXIM4C_I2C_REG_ADDR_08BITS 1
@@ -31,6 +32,13 @@ enum {
MAXIM4C_I2C_DEV_MAX,
};
struct maxim4c_i2c_mux {
struct i2c_mux_core *muxc;
u32 i2c_mux_mask;
u32 mux_channel;
bool mux_disable;
};
/* i2c register array end */
#define MAXIM4C_REG_NULL 0xFFFF
@@ -52,4 +60,27 @@ struct maxim4c_i2c_init_seq {
u32 val_len;
};
/* maxim4c i2c read/write api */
int maxim4c_i2c_write(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u32 val_len, u32 reg_val);
int maxim4c_i2c_read(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u32 val_len, u32 *reg_val);
int maxim4c_i2c_update(struct i2c_client *client,
u16 reg_addr, u16 reg_len,
u32 val_len, u32 val_mask, u32 reg_val);
int maxim4c_i2c_write_reg(struct i2c_client *client,
u16 reg_addr, u8 reg_val);
int maxim4c_i2c_read_reg(struct i2c_client *client,
u16 reg_addr, u8 *reg_val);
int maxim4c_i2c_update_reg(struct i2c_client *client,
u16 reg_addr, u8 val_mask, u8 reg_val);
int maxim4c_i2c_write_array(struct i2c_client *client,
const struct maxim4c_i2c_regval *regs);
int maxim4c_i2c_load_init_seq(struct device *dev,
struct device_node *node, struct maxim4c_i2c_init_seq *init_seq);
int maxim4c_i2c_run_init_seq(struct i2c_client *client,
struct maxim4c_i2c_init_seq *init_seq);
#endif /* __MAXIM4C_I2C_H__ */

View File

@@ -19,10 +19,8 @@ static int maxim4c_link_enable_vdd_ldo1(maxim4c_t *maxim4c)
* CTRL0: Enable REG_ENABLE
* CTRL2: Enable REG_MNL
*/
ret |= maxim4c_i2c_update_byte(client,
0x0017, MAXIM4C_I2C_REG_ADDR_16BITS, BIT(2), BIT(2));
ret |= maxim4c_i2c_update_byte(client,
0x0019, MAXIM4C_I2C_REG_ADDR_16BITS, BIT(4), BIT(4));
ret |= maxim4c_i2c_update_reg(client, 0x0017, BIT(2), BIT(2));
ret |= maxim4c_i2c_update_reg(client, 0x0019, BIT(4), BIT(4));
return ret;
}
@@ -32,9 +30,7 @@ static int maxim4c_link_enable_vdd_ldo2(maxim4c_t *maxim4c)
struct i2c_client *client = maxim4c->client;
int ret = 0;
ret |= maxim4c_i2c_write_byte(client,
0x06C2, MAXIM4C_I2C_REG_ADDR_16BITS,
0x10);
ret |= maxim4c_i2c_write_reg(client, 0x06C2, 0x10);
// delay 10ms
msleep(10);
@@ -68,9 +64,7 @@ static int maxim4c_link_set_rate(maxim4c_t *maxim4c)
link_rate |= (0x2 << 4);
}
if (link_rate != 0) {
ret |= maxim4c_i2c_write_byte(client,
0x0010, MAXIM4C_I2C_REG_ADDR_16BITS,
link_rate);
ret |= maxim4c_i2c_write_reg(client, 0x0010, link_rate);
}
/* Link C/D rate setting */
@@ -92,9 +86,7 @@ static int maxim4c_link_set_rate(maxim4c_t *maxim4c)
link_rate |= (0x2 << 4);
}
if (link_rate != 0) {
ret |= maxim4c_i2c_write_byte(client,
0x0011, MAXIM4C_I2C_REG_ADDR_16BITS,
link_rate);
ret |= maxim4c_i2c_write_reg(client, 0x0011, link_rate);
}
return ret;
@@ -152,32 +144,26 @@ static int maxim4c_link_status_init(maxim4c_t *maxim4c)
}
}
ret = maxim4c_i2c_write_byte(client,
0x0006, MAXIM4C_I2C_REG_ADDR_16BITS,
link_type | link_enable);
ret = maxim4c_i2c_write_reg(client, 0x0006, link_type | link_enable);
reg_mask = BIT(1) | BIT(0);
reg_value = 0;
for (link_idx = 0; link_idx < MAXIM4C_LINK_ID_MAX; link_idx++) {
reg_addr = 0x0B04 + 0x100 * link_idx;
ret |= maxim4c_i2c_update_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, reg_value);
}
if (gmsl_link->i2c_ctrl_port == MAXIM4C_I2C_PORT2) {
reg_mask = 0x0F;
reg_value = 0x0F;
ret |= maxim4c_i2c_update_byte(client,
0x000E, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x000E, reg_mask, reg_value);
}
reg_mask = 0xFF;
reg_value = 0xFF;
ret |= maxim4c_i2c_update_byte(client,
0x0003, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client, 0x0003, reg_mask, reg_value);
return ret;
}
@@ -196,18 +182,14 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask)
link_type = gmsl_link->link_cfg[MAXIM4C_LINK_ID_A].link_type;
if (link_type == MAXIM4C_GMSL2) {
// GMSL2 Link A
maxim4c_i2c_read_byte(client,
0x001A, MAXIM4C_I2C_REG_ADDR_16BITS,
&link_lock);
maxim4c_i2c_read_reg(client, 0x001A, &link_lock);
if (link_lock & BIT(3)) {
lock_state |= MAXIM4C_LINK_MASK_A;
dev_dbg(dev, "GMSL2 Link A locked\n");
}
} else {
// GMSL1 Link A
maxim4c_i2c_read_byte(client,
0x0BCB, MAXIM4C_I2C_REG_ADDR_16BITS,
&link_lock);
maxim4c_i2c_read_reg(client, 0x0BCB, &link_lock);
if (link_lock & BIT(0)) {
lock_state |= MAXIM4C_LINK_MASK_A;
dev_dbg(dev, "GMSL1 Link A locked\n");
@@ -226,18 +208,14 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask)
link_type = gmsl_link->link_cfg[MAXIM4C_LINK_ID_B].link_type;
if (link_type == MAXIM4C_GMSL2) {
// GMSL2 Link B
maxim4c_i2c_read_byte(client,
0x000A, MAXIM4C_I2C_REG_ADDR_16BITS,
&link_lock);
maxim4c_i2c_read_reg(client, 0x000A, &link_lock);
if (link_lock & BIT(3)) {
lock_state |= MAXIM4C_LINK_MASK_B;
dev_dbg(dev, "GMSL2 Link B locked\n");
}
} else {
// GMSL1 Link B
maxim4c_i2c_read_byte(client,
0x0CCB, MAXIM4C_I2C_REG_ADDR_16BITS,
&link_lock);
maxim4c_i2c_read_reg(client, 0x0CCB, &link_lock);
if (link_lock & BIT(0)) {
lock_state |= MAXIM4C_LINK_MASK_B;
dev_dbg(dev, "GMSL1 Link B locked\n");
@@ -256,18 +234,14 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask)
link_type = gmsl_link->link_cfg[MAXIM4C_LINK_ID_C].link_type;
if (link_type == MAXIM4C_GMSL2) {
// GMSL2 Link C
maxim4c_i2c_read_byte(client,
0x000B, MAXIM4C_I2C_REG_ADDR_16BITS,
&link_lock);
maxim4c_i2c_read_reg(client, 0x000B, &link_lock);
if (link_lock & BIT(3)) {
lock_state |= MAXIM4C_LINK_MASK_C;
dev_dbg(dev, "GMSL2 Link C locked\n");
}
} else {
// GMSL1 Link C
maxim4c_i2c_read_byte(client,
0x0DCB, MAXIM4C_I2C_REG_ADDR_16BITS,
&link_lock);
maxim4c_i2c_read_reg(client, 0x0DCB, &link_lock);
if (link_lock & BIT(0)) {
lock_state |= MAXIM4C_LINK_MASK_C;
dev_dbg(dev, "GMSL1 Link C locked\n");
@@ -286,18 +260,14 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask)
link_type = gmsl_link->link_cfg[MAXIM4C_LINK_ID_D].link_type;
if (link_type == MAXIM4C_GMSL2) {
// GMSL2 Link D
maxim4c_i2c_read_byte(client,
0x000C, MAXIM4C_I2C_REG_ADDR_16BITS,
&link_lock);
maxim4c_i2c_read_reg(client, 0x000C, &link_lock);
if (link_lock & BIT(3)) {
lock_state |= MAXIM4C_LINK_MASK_D;
dev_dbg(dev, "GMSL2 Link D locked\n");
}
} else {
// GMSL1 Link D
maxim4c_i2c_read_byte(client,
0x0ECB, MAXIM4C_I2C_REG_ADDR_16BITS,
&link_lock);
maxim4c_i2c_read_reg(client, 0x0ECB, &link_lock);
if (link_lock & BIT(0)) {
lock_state |= MAXIM4C_LINK_MASK_D;
dev_dbg(dev, "GMSL1 Link D locked\n");
@@ -315,7 +285,7 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask)
}
EXPORT_SYMBOL(maxim4c_link_get_lock_state);
int maxim4c_link_oneshot_reset(struct maxim4c *maxim4c, u8 link_mask)
int maxim4c_link_oneshot_reset(maxim4c_t *maxim4c, u8 link_mask)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
@@ -335,16 +305,14 @@ int maxim4c_link_oneshot_reset(struct maxim4c *maxim4c, u8 link_mask)
if (oneshot_reset != 0) {
// One-Shot Reset
ret = maxim4c_i2c_write_byte(client,
0x0018, MAXIM4C_I2C_REG_ADDR_16BITS,
oneshot_reset);
ret = maxim4c_i2c_write_reg(client, 0x0018, oneshot_reset);
}
return ret;
}
EXPORT_SYMBOL(maxim4c_link_oneshot_reset);
int maxim4c_link_mask_enable(struct maxim4c *maxim4c, u8 link_mask, bool enable)
int maxim4c_link_mask_enable(maxim4c_t *maxim4c, u8 link_mask, bool enable)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
@@ -366,16 +334,15 @@ int maxim4c_link_mask_enable(struct maxim4c *maxim4c, u8 link_mask, bool enable)
if (reg_mask != 0) {
reg_value = enable ? reg_mask : 0;
ret = maxim4c_i2c_update_byte(client,
0x0006, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret = maxim4c_i2c_update_reg(client,
0x0006, reg_mask, reg_value);
}
return ret;
}
EXPORT_SYMBOL(maxim4c_link_mask_enable);
int maxim4c_link_wait_linklock(struct maxim4c *maxim4c, u8 link_mask)
int maxim4c_link_wait_linklock(maxim4c_t *maxim4c, u8 link_mask)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
@@ -425,7 +392,7 @@ int maxim4c_link_wait_linklock(struct maxim4c *maxim4c, u8 link_mask)
}
EXPORT_SYMBOL(maxim4c_link_wait_linklock);
int maxim4c_link_select_remote_enable(struct maxim4c *maxim4c, u8 link_mask)
int maxim4c_link_select_remote_enable(maxim4c_t *maxim4c, u8 link_mask)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
@@ -454,14 +421,11 @@ int maxim4c_link_select_remote_enable(struct maxim4c *maxim4c, u8 link_mask)
if (link_mask != 0) {
// One-Shot Reset
ret |= maxim4c_i2c_write_byte(client,
0x0018, MAXIM4C_I2C_REG_ADDR_16BITS,
link_reset);
ret |= maxim4c_i2c_write_reg(client, 0x0018, link_reset);
// Link Enable
ret |= maxim4c_i2c_update_byte(client,
0x0006, MAXIM4C_I2C_REG_ADDR_16BITS,
link_enable, link_enable);
ret |= maxim4c_i2c_update_reg(client,
0x0006, link_enable, link_enable);
if (ret) {
dev_err(dev, "%s: link oneshot reset or enable error, link mask = 0x%x\n",
@@ -480,7 +444,7 @@ int maxim4c_link_select_remote_enable(struct maxim4c *maxim4c, u8 link_mask)
}
EXPORT_SYMBOL(maxim4c_link_select_remote_enable);
int maxim4c_link_select_remote_control(struct maxim4c *maxim4c, u8 link_mask)
int maxim4c_link_select_remote_control(maxim4c_t *maxim4c, u8 link_mask)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
@@ -510,9 +474,8 @@ int maxim4c_link_select_remote_control(struct maxim4c *maxim4c, u8 link_mask)
reg_value = 0;
reg_addr = 0x0B04 + 0x100 * link_idx;
ret |= maxim4c_i2c_update_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, reg_value);
link_mask &= ~BIT(link_idx);
}
@@ -523,9 +486,8 @@ int maxim4c_link_select_remote_control(struct maxim4c *maxim4c, u8 link_mask)
reg_mask = 0x0F;
reg_value = ~link_mask;
ret |= maxim4c_i2c_update_byte(client,
0x000E, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x000E, reg_mask, reg_value);
} else if (gmsl_link->i2c_ctrl_port == MAXIM4C_I2C_PORT1) {
reg_mask = 0xFF;
reg_value = 0;
@@ -536,9 +498,8 @@ int maxim4c_link_select_remote_control(struct maxim4c *maxim4c, u8 link_mask)
}
reg_value = ~reg_value;
ret |= maxim4c_i2c_update_byte(client,
0x0003, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x0003, reg_mask, reg_value);
} else {
reg_mask = 0xFF;
reg_value = 0;
@@ -549,9 +510,8 @@ int maxim4c_link_select_remote_control(struct maxim4c *maxim4c, u8 link_mask)
}
reg_value = ~reg_value;
ret |= maxim4c_i2c_update_byte(client,
0x0003, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x0003, reg_mask, reg_value);
}
return ret;
@@ -563,6 +523,7 @@ static int maxim4c_gmsl_link_config_parse_dt(struct device *dev,
struct device_node *parent_node)
{
struct device_node *node = NULL;
struct device_node *remote_cam_node = NULL;
struct device_node *init_seq_node = NULL;
struct maxim4c_i2c_init_seq *init_seq = NULL;
struct maxim4c_link_cfg *link_cfg = NULL;
@@ -633,6 +594,15 @@ static int maxim4c_gmsl_link_config_parse_dt(struct device *dev,
link_cfg->link_rx_rate = value;
}
/* link get remote camera node */
remote_cam_node = of_parse_phandle(node, "link-remote-cam", 0);
if (!IS_ERR_OR_NULL(remote_cam_node)) {
dev_info(dev, "remote camera node: %pOF\n", remote_cam_node);
link_cfg->remote_cam_node = remote_cam_node;
} else {
dev_warn(dev, "link-remote-cam node isn't exist\n");
}
/* link init sequence */
init_seq_node = of_get_child_by_name(node, "link-init-sequence");
if (!IS_ERR_OR_NULL(init_seq_node)) {
@@ -758,6 +728,7 @@ void maxim4c_link_data_init(maxim4c_t *maxim4c)
else
link_cfg->link_rx_rate = MAXIM4C_LINK_RX_RATE_6GBPS;
link_cfg->link_tx_rate = MAXIM4C_LINK_TX_RATE_187_5MPS;
link_cfg->remote_cam_node = NULL;
link_cfg->link_init_seq.reg_init_seq = NULL;
}
}

View File

@@ -7,6 +7,7 @@
#ifndef __MAXIM4C_LINK_H__
#define __MAXIM4C_LINK_H__
#include <linux/of_device.h>
#include "maxim4c_i2c.h"
/* Link cable */
@@ -69,6 +70,7 @@ struct maxim4c_link_cfg {
u8 link_rx_rate;
u8 link_tx_rate;
struct device_node *remote_cam_node;
struct maxim4c_i2c_init_seq link_init_seq;
};

View File

@@ -27,61 +27,52 @@ static int maxim4c_txphy_init_timing(maxim4c_t *maxim4c)
(maxim4c->mipi_txphy.timing.t_hs_prep & 0x3) << 4 |
(maxim4c->mipi_txphy.timing.t_clk_trail & 0x3) << 2 |
(maxim4c->mipi_txphy.timing.t_clk_przero & 0x3) << 0);
ret |= maxim4c_i2c_write_byte(client, 0x08A1,
MAXIM4C_I2C_REG_ADDR_16BITS, timing);
ret |= maxim4c_i2c_write_reg(client, 0x08A1, timing);
reg_mask = 0x0F;
timing = ((maxim4c->mipi_txphy.timing.t_lpx & 0x3) << 2 |
(maxim4c->mipi_txphy.timing.t_hs_trail & 0x3) << 0);
ret |= maxim4c_i2c_update_byte(
client, 0x08A2, MAXIM4C_I2C_REG_ADDR_16BITS, reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
0x08A2, reg_mask, timing);
reg_mask = (0x3 << 6);
timing = (maxim4c->mipi_txphy.timing.t_lpxesc & 0x3) << 6;
ret |= maxim4c_i2c_update_byte(
client, 0x08A5, MAXIM4C_I2C_REG_ADDR_16BITS, reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
0x08A5, reg_mask, timing);
reg_mask = (0x7 << 5);
timing = (maxim4c->mipi_txphy.timing.t_lpxesc & 0x7) << 5;
ret |= maxim4c_i2c_update_byte(
client, 0x08A8, MAXIM4C_I2C_REG_ADDR_16BITS, reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
0x08A8, reg_mask, timing);
for (phy_idx = 0; phy_idx < MAXIM4C_TXPHY_ID_MAX; phy_idx++) {
reg_mask = 0xFF;
reg_addr = 0x0905 + 0x40 * phy_idx;
timing = maxim4c->mipi_txphy.timing.csi2_t_pre;
ret |= maxim4c_i2c_update_byte(client, reg_addr,
MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, timing);
reg_addr = 0x0906 + 0x40 * phy_idx;
timing = maxim4c->mipi_txphy.timing.csi2_t_post;
ret |= maxim4c_i2c_update_byte(client, reg_addr,
MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, timing);
reg_addr = 0x0907 + 0x40 * phy_idx;
timing = maxim4c->mipi_txphy.timing.csi2_tx_gap;
ret |= maxim4c_i2c_update_byte(client, reg_addr,
MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, timing);
reg_addr = 0x0908 + 0x40 * phy_idx;
timing = maxim4c->mipi_txphy.timing.csi2_twakeup & 0xFF;
ret |= maxim4c_i2c_update_byte(client, reg_addr,
MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, timing);
timing = (maxim4c->mipi_txphy.timing.csi2_twakeup >> 8) & 0xFF;
ret |= maxim4c_i2c_update_byte(client, reg_addr + 1,
MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
reg_addr + 1, reg_mask, timing);
reg_mask = 0x7;
timing = (maxim4c->mipi_txphy.timing.csi2_twakeup >> 16) & 0x7;
ret |= maxim4c_i2c_update_byte(client, reg_addr + 2,
MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, timing);
ret |= maxim4c_i2c_update_reg(client,
reg_addr + 2, reg_mask, timing);
}
return ret;
@@ -101,9 +92,8 @@ static int maxim4c_txphy_auto_init_deskew(maxim4c_t *maxim4c)
phy_cfg = &mipi_txphy->phy_cfg[phy_idx];
if (phy_cfg->phy_enable && (phy_cfg->auto_deskew & BIT(7))) {
reg_addr = 0x0903 + 0x40 * phy_idx;
ret |= maxim4c_i2c_write_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
phy_cfg->auto_deskew);
ret |= maxim4c_i2c_write_reg(client,
reg_addr, phy_cfg->auto_deskew);
}
}
@@ -132,9 +122,8 @@ static int maxim4c_mipi_txphy_lane_mapping(maxim4c_t *maxim4c)
reg_value |= (phy_cfg->data_lane_map << 4);
}
if (reg_mask != 0) {
ret |= maxim4c_i2c_update_byte(client,
0x08A3, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x08A3, reg_mask, reg_value);
}
// MIPI TXPHY C/D: data lane mapping
@@ -151,9 +140,8 @@ static int maxim4c_mipi_txphy_lane_mapping(maxim4c_t *maxim4c)
reg_value |= (phy_cfg->data_lane_map << 4);
}
if (reg_mask != 0) {
ret |= maxim4c_i2c_update_byte(client,
0x08A4, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x08A4, reg_mask, reg_value);
}
return ret;
@@ -185,9 +173,8 @@ static int maxim4c_mipi_txphy_type_vcx_lane_num(maxim4c_t *maxim4c)
reg_value |= ((phy_cfg->data_lane_num - 1) << 6);
reg_addr = 0x090A + 0x40 * phy_idx;
ret |= maxim4c_i2c_update_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, reg_value);
}
return ret;
@@ -214,9 +201,8 @@ int maxim4c_mipi_txphy_enable(maxim4c_t *maxim4c, bool enable)
}
}
ret |= maxim4c_i2c_update_byte(client,
0x08A2, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x08A2, reg_mask, reg_value);
return ret;
}
@@ -254,26 +240,19 @@ int maxim4c_dphy_dpll_predef_set(maxim4c_t *maxim4c, s64 link_freq_hz)
// Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate
reg_addr = 0x1C00 + 0x100 * phy_idx;
ret |= maxim4c_i2c_write_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
0xf4);
ret |= maxim4c_i2c_write_reg(client, reg_addr, 0xf4);
reg_addr = 0x1C03 + 0x100 * phy_idx;
ret |= maxim4c_i2c_update_byte(client, reg_addr,
MAXIM4C_I2C_REG_ADDR_16BITS,
0x07, phy_cfg->ssc_ratio);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, 0x07, phy_cfg->ssc_ratio);
// Set dpll data rate
reg_addr = 0x0415 + 0x03 * phy_idx;
ret |= maxim4c_i2c_update_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
0x3F, dpll_val);
ret |= maxim4c_i2c_update_reg(client, reg_addr, 0x3F, dpll_val);
// Release reset to DPLL (config_soft_rst_n = 1)
reg_addr = 0x1C00 + 0x100 * phy_idx;
ret |= maxim4c_i2c_write_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
0xf5);
ret |= maxim4c_i2c_write_reg(client, reg_addr, 0xf5);
}
if (ret) {
@@ -281,12 +260,10 @@ int maxim4c_dphy_dpll_predef_set(maxim4c_t *maxim4c, s64 link_freq_hz)
return ret;
}
ret = read_poll_timeout(maxim4c_i2c_read_byte, ret,
ret = read_poll_timeout(maxim4c_i2c_read_reg, ret,
!(ret < 0) && (dpll_lock & dpll_mask),
1000, 10000, false,
client,
0x0400, MAXIM4C_I2C_REG_ADDR_16BITS,
&dpll_lock);
client, 0x0400, &dpll_lock);
if (ret < 0) {
dev_err(dev, "DPLL is unlocked: 0x%02x\n", dpll_lock);
return ret;
@@ -312,9 +289,8 @@ int maxim4c_mipi_csi_output(maxim4c_t *maxim4c, bool enable)
reg_value = enable ? BIT(7) : 0;
// Force all MIPI clocks running Config
ret |= maxim4c_i2c_update_byte(client,
0x08A0, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x08A0, reg_mask, reg_value);
}
/* Bit1 of the register 0x040B: CSI_OUT_EN
@@ -325,9 +301,8 @@ int maxim4c_mipi_csi_output(maxim4c_t *maxim4c, bool enable)
reg_value = enable ? BIT(1) : 0;
// MIPI CSI output Setting
ret |= maxim4c_i2c_update_byte(client,
0x040B, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x040B, reg_mask, reg_value);
return ret;
}
@@ -584,9 +559,7 @@ int maxim4c_mipi_txphy_hw_init(maxim4c_t *maxim4c)
}
// MIPI TXPHY Mode setting
ret |= maxim4c_i2c_write_byte(client,
0x08A0, MAXIM4C_I2C_REG_ADDR_16BITS,
mode);
ret |= maxim4c_i2c_write_reg(client, 0x08A0, mode);
// mipi txphy data lane mapping
ret |= maxim4c_mipi_txphy_lane_mapping(maxim4c);

View File

@@ -71,9 +71,8 @@ int maxim4c_pattern_enable(maxim4c_t *maxim4c, bool enable)
/* Generate gradient pattern. */
reg_val = enable ? BIT(5) : 0;
}
ret = maxim4c_i2c_update_byte(client,
VPGx_REG(vpgx, 0x1051), MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_val);
ret = maxim4c_i2c_update_reg(client,
VPGx_REG(vpgx, 0x1051), reg_mask, reg_val);
return ret;
}
@@ -85,30 +84,22 @@ static int maxim4c_pattern_previnit(maxim4c_t *maxim4c)
int ret = 0;
// All links disable at beginning.
ret = maxim4c_i2c_write_byte(client,
0x0006, MAXIM4C_I2C_REG_ADDR_16BITS,
0xF0);
ret = maxim4c_i2c_write_reg(client, 0x0006, 0xF0);
if (ret)
return ret;
// video pipe disable.
ret = maxim4c_i2c_write_byte(client,
0x00F4, MAXIM4C_I2C_REG_ADDR_16BITS,
0x00);
ret = maxim4c_i2c_write_reg(client, 0x00F4, 0x00);
if (ret)
return ret;
// MIPI CSI output disable.
ret = maxim4c_i2c_write_byte(client,
0x040B, MAXIM4C_I2C_REG_ADDR_16BITS,
0x00);
ret = maxim4c_i2c_write_reg(client, 0x040B, 0x00);
if (ret)
return ret;
// MIPI TXPHY standby
ret = maxim4c_i2c_update_byte(client,
0x08A2, MAXIM4C_I2C_REG_ADDR_16BITS,
0xF0, 0x00);
ret = maxim4c_i2c_update_reg(client, 0x08A2, 0xF0, 0x00);
if (ret)
return ret;
@@ -144,9 +135,8 @@ static int maxim4c_pattern_config(maxim4c_t *maxim4c)
// PATGEN_MODE = 0, Pattern generator disabled
// use video from the serializer input
ret |= maxim4c_i2c_update_byte(client,
VPGx_REG(vpgx, 0x1051), MAXIM4C_I2C_REG_ADDR_16BITS,
BIT(5) | BIT(4), 0x00);
ret |= maxim4c_i2c_update_reg(client,
VPGx_REG(vpgx, 0x1051), BIT(5) | BIT(4), 0x00);
/* Pattern PCLK:
* 0b00 - 25MHz
@@ -154,9 +144,7 @@ static int maxim4c_pattern_config(maxim4c_t *maxim4c)
* 0b1x - (PATGEN_CLK_SRC: 0 - 150MHz, 1 - 375MHz).
*/
pattern_pclk = (pattern_pclk & 0x03);
ret |= maxim4c_i2c_write_byte(client,
0x0009, MAXIM4C_I2C_REG_ADDR_16BITS,
pattern_pclk);
ret |= maxim4c_i2c_write_reg(client, 0x0009, pattern_pclk);
if (pattern_pclk >= PATTERN_PCLK_150M) {
reg_mask = BIT(7);
if (pattern_pclk == PATTERN_PCLK_375M)
@@ -167,90 +155,84 @@ static int maxim4c_pattern_config(maxim4c_t *maxim4c)
if (vpgx == PATTERN_GENERATOR_0) {
for (i = 0; i < 4; i++) {
reg_addr = 0x01DC + i * 0x20;
ret |= maxim4c_i2c_update_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_val);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, reg_val);
}
} else {
for (i = 0; i < 4; i++) {
reg_addr = 0x025C + i * 0x20;
ret |= maxim4c_i2c_update_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_val);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, reg_val);
}
}
}
/* Configure Video Timing Generator for 1920x1080 @ 30 fps. */
// VS_DLY = 0
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1052), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_24BITS, 0x000000);
// VS_HIGH = Vsw * Htot
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1055), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_24BITS, v_sw * h_tot);
// VS_LOW = (Vactive + Vfp + Vbp) * Htot
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1058), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_24BITS, (v_active + v_fp + v_bp) * h_tot);
// V2H = VS_DLY
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x105b), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_24BITS, 0x000000);
// HS_HIGH = Hsw
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x105e), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_16BITS, h_sw);
// HS_LOW = Hactive + Hfp + Hbp
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1060), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_16BITS, h_active + h_fp + h_bp);
// HS_CNT = Vtot
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1062), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_16BITS, v_tot);
// V2D = VS_DLY + Htot * (Vsw + Vbp) + (Hsw + Hbp)
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1064), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_24BITS, h_tot * (v_sw + v_bp) + (h_sw + h_bp));
// DE_HIGH = Hactive
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1067), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_16BITS, h_active);
// DE_LOW = Hfp + Hsw + Hbp
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1069), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_16BITS, h_fp + h_sw + h_bp);
// DE_CNT = Vactive
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x106b), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_16BITS, v_active);
/* Generate VS, HS and DE in free-running mode, Invert HS and VS. */
ret |= maxim4c_i2c_write_byte(client,
VPGx_REG(vpgx, 0x1050), MAXIM4C_I2C_REG_ADDR_16BITS,
0xfb);
ret |= maxim4c_i2c_write_reg(client, VPGx_REG(vpgx, 0x1050), 0xfb);
/* Configure Video Pattern Generator. */
if (pattern_mode == PATTERN_CHECKERBOARD) {
/* Set checkerboard pattern size. */
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1074), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_24BITS, 0x3c3c3c);
/* Set checkerboard pattern colors. */
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x106e), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_24BITS, 0xfecc00);
ret |= maxim4c_i2c_write_reg(client,
ret |= maxim4c_i2c_write(client,
VPGx_REG(vpgx, 0x1071), MAXIM4C_I2C_REG_ADDR_16BITS,
MAXIM4C_I2C_REG_VALUE_24BITS, 0x006aa7);
} else {
/* Set gradient increment. */
ret |= maxim4c_i2c_write_byte(client,
VPGx_REG(vpgx, 0x106d), MAXIM4C_I2C_REG_ADDR_16BITS,
0x10);
ret |= maxim4c_i2c_write_reg(client, VPGx_REG(vpgx, 0x106d), 0x10);
}
return ret;

View File

@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Maxim Quad GMSL Deserializer Remode Device Manage
*
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
*
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
*/
#include <linux/module.h>
#include <linux/of_graph.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-fwnode.h>
#include "maxim4c_api.h"
int maxim4c_remote_devices_power(maxim4c_t *maxim4c, u8 link_mask, int on)
{
struct device *dev = &maxim4c->client->dev;
maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link;
struct maxim4c_link_cfg *link_cfg = NULL;
struct device_node *remote_cam_node = NULL;
struct i2c_client *remote_cam_client = NULL;
struct v4l2_subdev *remote_cam_sd = NULL;
int ret = 0, i = 0;
dev_dbg(dev, "%s: link mask = 0x%02x, on = %d\n", __func__, link_mask, on);
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
if ((link_mask & BIT(i)) == 0) {
dev_dbg(dev, "link id = %d mask is disabled\n", i);
continue;
}
link_cfg = &gmsl_link->link_cfg[i];
if (link_cfg->link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
continue;
}
remote_cam_node = link_cfg->remote_cam_node;
if (IS_ERR_OR_NULL(remote_cam_node)) {
dev_info(dev, "link id = %d remote camera node error\n", i);
continue;
}
remote_cam_client = of_find_i2c_device_by_node(remote_cam_node);
if (IS_ERR_OR_NULL(remote_cam_client)) {
dev_info(dev, "link id = %d remote camera client error\n", i);
continue;
}
remote_cam_sd = i2c_get_clientdata(remote_cam_client);
if (IS_ERR_OR_NULL(remote_cam_sd)) {
dev_info(dev, "link id = %d remote camera v4l2_subdev error\n", i);
continue;
}
dev_info(dev, "link id = %d remote camera power = %d\n", i, on);
ret |= v4l2_subdev_call(remote_cam_sd, core, s_power, on);
}
return ret;
}
EXPORT_SYMBOL(maxim4c_remote_devices_power);
int maxim4c_remote_devices_s_stream(maxim4c_t *maxim4c, u8 link_mask, int enable)
{
struct device *dev = &maxim4c->client->dev;
maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link;
struct maxim4c_link_cfg *link_cfg = NULL;
struct device_node *remote_cam_node = NULL;
struct i2c_client *remote_cam_client = NULL;
struct v4l2_subdev *remote_cam_sd = NULL;
int ret = 0, i = 0;
dev_dbg(dev, "%s: link mask = 0x%02x, enable = %d\n", __func__, link_mask, enable);
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
if ((link_mask & BIT(i)) == 0) {
dev_dbg(dev, "link id = %d mask is disabled\n", i);
continue;
}
link_cfg = &gmsl_link->link_cfg[i];
if (link_cfg->link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
continue;
}
remote_cam_node = link_cfg->remote_cam_node;
if (IS_ERR_OR_NULL(remote_cam_node)) {
dev_info(dev, "link id = %d remote camera node error\n", i);
continue;
}
remote_cam_client = of_find_i2c_device_by_node(remote_cam_node);
if (IS_ERR_OR_NULL(remote_cam_client)) {
dev_info(dev, "link id = %d remote camera client error\n", i);
continue;
}
remote_cam_sd = i2c_get_clientdata(remote_cam_client);
if (IS_ERR_OR_NULL(remote_cam_sd)) {
dev_info(dev, "link id = %d remote camera v4l2_subdev error\n", i);
continue;
}
dev_info(dev, "link id = %d remote camera s_stream = %d\n", i, enable);
ret |= v4l2_subdev_call(remote_cam_sd, video, s_stream, enable);
}
return ret;
}
EXPORT_SYMBOL(maxim4c_remote_devices_s_stream);

View File

@@ -16,9 +16,7 @@
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include "maxim4c_api.h"
@@ -96,9 +94,8 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c)
dev_info(dev, "=== maxim4c support mode init ===\n");
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_support_mode_init(maxim4c);
return ret;
#endif
return maxim4c_pattern_support_mode_init(maxim4c);
#endif /* MAXIM4C_TEST_PATTERN */
maxim4c->cfg_modes_num = 1;
maxim4c->cur_mode = &maxim4c->supported_mode;
@@ -214,7 +211,7 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c)
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static int maxim4c_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *try_fmt =
v4l2_subdev_get_try_format(sd, fh->pad, 0);
const struct maxim4c_mode *def_mode = &maxim4c->supported_mode;
@@ -236,7 +233,7 @@ static int maxim4c_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
static int maxim4c_s_power(struct v4l2_subdev *sd, int on)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
struct i2c_client *client = maxim4c->client;
int ret = 0;
@@ -265,7 +262,7 @@ unlock_and_return:
return ret;
}
static void maxim4c_get_module_inf(struct maxim4c *maxim4c,
static void maxim4c_get_module_inf(maxim4c_t *maxim4c,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
@@ -275,7 +272,7 @@ static void maxim4c_get_module_inf(struct maxim4c *maxim4c,
strscpy(inf->base.lens, maxim4c->len_name, sizeof(inf->base.lens));
}
static void maxim4c_get_vicap_rst_inf(struct maxim4c *maxim4c,
static void maxim4c_get_vicap_rst_inf(maxim4c_t *maxim4c,
struct rkmodule_vicap_reset_info *rst_info)
{
struct i2c_client *client = maxim4c->client;
@@ -288,7 +285,7 @@ static void maxim4c_get_vicap_rst_inf(struct maxim4c *maxim4c,
__func__, rst_info->is_reset);
}
static void maxim4c_set_vicap_rst_inf(struct maxim4c *maxim4c,
static void maxim4c_set_vicap_rst_inf(maxim4c_t *maxim4c,
struct rkmodule_vicap_reset_info rst_info)
{
maxim4c->is_reset = rst_info.is_reset;
@@ -296,7 +293,7 @@ static void maxim4c_set_vicap_rst_inf(struct maxim4c *maxim4c,
static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
struct rkmodule_csi_dphy_param *dphy_param;
long ret = 0;
@@ -425,7 +422,7 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
}
#endif /* CONFIG_COMPAT */
static int __maxim4c_start_stream(struct maxim4c *maxim4c)
static int __maxim4c_start_stream(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret = 0;
@@ -452,12 +449,14 @@ static int __maxim4c_start_stream(struct maxim4c *maxim4c)
link_mask = maxim4c->gmsl_link.link_enable_mask;
video_pipe_mask = maxim4c->video_pipe.pipe_enable_mask;
// disable all remote control
ret = maxim4c_link_select_remote_control(maxim4c, 0);
#if (MAXIM4C_TEST_PATTERN == 0)
// remote devices power on
ret = maxim4c_remote_devices_power(maxim4c, link_mask, 1);
if (ret) {
dev_err(dev, "link disable remote control error\n");
dev_err(dev, "remote devices power on error\n");
return ret;
}
#endif /* MAXIM4C_TEST_PATTERN */
// disable all video pipe
ret = maxim4c_video_pipe_mask_enable(maxim4c, video_pipe_mask, false);
@@ -473,11 +472,15 @@ static int __maxim4c_start_stream(struct maxim4c *maxim4c)
}
link_mask = maxim4c->gmsl_link.link_locked_mask;
ret = maxim4c_remote_devices_init(maxim4c, link_mask);
#if (MAXIM4C_TEST_PATTERN == 0)
// remote devices start stream
ret = maxim4c_remote_devices_s_stream(maxim4c, link_mask, 1);
if (ret) {
dev_err(dev, "remote devices init error\n");
dev_err(dev, "remote devices start stream error\n");
return ret;
}
#endif /* MAXIM4C_TEST_PATTERN */
// mipi txphy enable setting: standby or enable
ret = maxim4c_mipi_txphy_enable(maxim4c, true);
@@ -502,12 +505,6 @@ static int __maxim4c_start_stream(struct maxim4c *maxim4c)
return ret;
}
ret = maxim4c_link_select_remote_control(maxim4c, link_mask);
if (ret) {
dev_err(dev, "remote control enable error\n");
return ret;
}
/* In case these controls are set before streaming */
mutex_unlock(&maxim4c->mutex);
ret = v4l2_ctrl_handler_setup(&maxim4c->ctrl_handler);
@@ -540,7 +537,7 @@ static int __maxim4c_start_stream(struct maxim4c *maxim4c)
return 0;
}
static int __maxim4c_stop_stream(struct maxim4c *maxim4c)
static int __maxim4c_stop_stream(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
u8 link_mask = 0, pipe_mask = 0;
@@ -564,9 +561,16 @@ static int __maxim4c_stop_stream(struct maxim4c *maxim4c)
ret |= maxim4c_video_pipe_mask_enable(maxim4c, pipe_mask, false);
ret |= maxim4c_remote_devices_deinit(maxim4c, link_mask);
#if (MAXIM4C_TEST_PATTERN == 0)
// remote devices stop stream
ret |= maxim4c_remote_devices_s_stream(maxim4c, link_mask, 0);
// remote devices power off
ret |= maxim4c_remote_devices_power(maxim4c, link_mask, 0);
#endif /* MAXIM4C_TEST_PATTERN */
// i2c mux enable: default disable all remote channel
ret |= maxim4c_i2c_mux_enable(maxim4c, 0x00);
ret |= maxim4c_link_select_remote_control(maxim4c, 0);
ret |= maxim4c_link_mask_enable(maxim4c, link_mask, false);
if (ret) {
@@ -579,7 +583,7 @@ static int __maxim4c_stop_stream(struct maxim4c *maxim4c)
static int maxim4c_s_stream(struct v4l2_subdev *sd, int on)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
struct i2c_client *client = maxim4c->client;
int ret = 0;
@@ -621,7 +625,7 @@ unlock_and_return:
static int maxim4c_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *fi)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
const struct maxim4c_mode *mode = maxim4c->cur_mode;
mutex_lock(&maxim4c->mutex);
@@ -635,7 +639,7 @@ static int maxim4c_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
const struct maxim4c_mode *mode = maxim4c->cur_mode;
if (code->index != 0)
@@ -649,7 +653,7 @@ static int maxim4c_enum_frame_sizes(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
if (fse->index >= maxim4c->cfg_modes_num)
return -EINVAL;
@@ -670,7 +674,7 @@ maxim4c_enum_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
if (fie->index >= maxim4c->cfg_modes_num)
return -EINVAL;
@@ -687,7 +691,7 @@ static int maxim4c_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
const struct maxim4c_mode *mode = maxim4c->cur_mode;
mutex_lock(&maxim4c->mutex);
@@ -717,7 +721,7 @@ static int maxim4c_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
struct device *dev = &maxim4c->client->dev;
const struct maxim4c_mode *mode = NULL;
u64 link_freq = 0, pixel_rate = 0;
@@ -769,7 +773,7 @@ static int maxim4c_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
sel->r.left = 0;
@@ -785,7 +789,7 @@ static int maxim4c_get_selection(struct v4l2_subdev *sd,
static int maxim4c_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_mbus_config *config)
{
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
u32 val = 0;
u8 data_lanes = maxim4c->bus_cfg.bus.mipi_csi2.num_data_lanes;
@@ -836,7 +840,7 @@ static const struct v4l2_subdev_ops maxim4c_subdev_ops = {
.pad = &maxim4c_pad_ops,
};
static int maxim4c_initialize_controls(struct maxim4c *maxim4c)
static int maxim4c_initialize_controls(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
const struct maxim4c_mode *mode;

View File

@@ -35,9 +35,8 @@ static int maxim4c_video_pipe_select(maxim4c_t *maxim4c)
if ((i % 2 == 1) && (reg_mask != 0)) {
reg_addr = 0x00F0 + (i / 2);
ret |= maxim4c_i2c_update_byte(client,
reg_addr, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
reg_addr, reg_mask, reg_value);
// Prepare for next register
reg_mask = 0;
@@ -252,9 +251,8 @@ int maxim4c_video_pipe_mask_enable(maxim4c_t *maxim4c, u8 video_pipe_mask, bool
}
if (reg_mask != 0) {
ret |= maxim4c_i2c_update_byte(client,
0x00F4, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret |= maxim4c_i2c_update_reg(client,
0x00F4, reg_mask, reg_value);
}
return ret;
@@ -288,9 +286,8 @@ int maxim4c_video_pipe_linkid_enable(maxim4c_t *maxim4c, u8 link_id, bool enable
}
if (reg_mask != 0) {
ret = maxim4c_i2c_update_byte(client,
0x00F4, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
ret = maxim4c_i2c_update_reg(client,
0x00F4, reg_mask, reg_value);
}
return ret;

View File

@@ -9,7 +9,7 @@
#include "maxim4c_i2c.h"
/* Maxim4c Video Pipe In ID: 0 ~ 3 */
/* Video Pipe In ID: 0 ~ 3 */
enum {
MAXIM4C_PIPE_I_ID_X = 0,
MAXIM4C_PIPE_I_ID_Y,
@@ -18,7 +18,7 @@ enum {
MAXIM4C_PIPE_I_ID_MAX,
};
/* Maxim4c Video Pipe Out ID: 0 ~ 7 */
/* Video Pipe Out ID: 0 ~ 7 */
enum {
MAXIM4C_PIPE_O_ID_0 = 0,
MAXIM4C_PIPE_O_ID_1,
@@ -31,7 +31,7 @@ enum {
MAXIM4C_PIPE_O_ID_MAX,
};
/* Maxim4c Video Pipe Out Config */
/* Video Pipe Out Config */
struct maxim4c_pipe_cfg {
u8 pipe_enable;
u8 pipe_idx;

View File

@@ -1,46 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Maxim Quad GMSL deserializer and serializer devices
#
config VIDEO_DES_MAXIM4C
tristate "Maxim Quad GMSL deserializer support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
This driver supports the Maxim Quad GMSL2/GMSL1 deserializer.
To compile this driver as a module, choose M here: the
module will be called maxim4c.
menu "Maxim Quad GMSL serializer devices support"
visible if VIDEO_DES_MAXIM4C
config MAXIM4C_SER_MAX9295
tristate "Maxim GMSL2 serializer max9295 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL2 max9295 serializer.
To compile this driver as a module, choose M here: the
module will be called remote_max9295.
config MAXIM4C_SER_MAX96715
tristate "Maxim GMSL1 Serializer max96715 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL1 max96715 serializer.
To compile this driver as a module, choose M here: the
module will be called remote_max96715.
config MAXIM4C_SER_MAX96717
tristate "Maxim GMSL2 Serializer max96717 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL2 max96717 serializer.
To compile this driver as a module, choose M here: the
module will be called remote_max96717.
endmenu

View File

@@ -1,434 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Maxim Quad GMSL Deserializer Remode Device Manage
*
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
*
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
*/
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/mfd/core.h>
#include "maxim4c_api.h"
static const char *maxim4c_remote_devs_name[MAXIM4C_LINK_ID_MAX] = {
"remote0", "remote1", "remote2", "remote3"
};
static const char *maxim4c_remote_link_compat[MAXIM4C_LINK_ID_MAX] = {
"maxim4c,link0", "maxim4c,link1", "maxim4c,link2", "maxim4c,link3"
};
static int maxim4c_remote_dev_info_parse(struct device *dev,
struct mfd_cell *remote_mfd_dev, u8 link_id)
{
struct device_node *node = NULL;
const char *remote_device_name = "serdes-remote-device";
const char *prop_str = NULL, *link_compat = NULL;
u32 sub_idx = 0, remote_id = 0;
int ret = 0;
node = NULL;
sub_idx = 0;
while ((node = of_get_next_child(dev->of_node, node))) {
if (!strncasecmp(node->name,
remote_device_name,
strlen(remote_device_name))) {
if (sub_idx >= MAXIM4C_LINK_ID_MAX) {
dev_err(dev, "%pOF: Too many matching %s node\n",
dev->of_node, remote_device_name);
of_node_put(node);
break;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
sub_idx++;
continue;
}
/* remote id */
ret = of_property_read_u32(node, "remote-id", &remote_id);
if (ret) {
sub_idx++;
continue;
}
if (remote_id >= MAXIM4C_LINK_ID_MAX) {
sub_idx++;
continue;
}
if (remote_id != link_id) {
sub_idx++;
continue;
}
dev_info(dev, "remote device id = %d\n", remote_id);
ret = of_property_read_string(node, "compatible", &prop_str);
if (ret) {
dev_err(dev, "%pOF no compatible error\n", node);
of_node_put(node);
return -EINVAL;
}
link_compat = maxim4c_remote_link_compat[remote_id];
if (!strncasecmp(prop_str,
link_compat, strlen(link_compat))) {
dev_info(dev, "compatible property: %s\n", prop_str);
remote_mfd_dev->name = maxim4c_remote_devs_name[remote_id];
remote_mfd_dev->of_compatible = prop_str;
of_node_put(node);
return 0;
}
dev_err(dev, "%pOF compatible and remote_id mismatch\n", node);
of_node_put(node);
return -EINVAL;
}
}
return -EINVAL;
}
static int maxim4c_remote_mfd_devs_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link;
struct mfd_cell *remote_mfd_dev = NULL;
int link_idx = 0, nr_mfd_cell = 0;
int ret = 0;
remote_mfd_dev = maxim4c->remote_mfd_devs;
nr_mfd_cell = 0;
for (link_idx = 0; link_idx < MAXIM4C_LINK_ID_MAX; link_idx++) {
remote_mfd_dev->name = NULL;
remote_mfd_dev->of_compatible = NULL;
if (gmsl_link->link_cfg[link_idx].link_enable == 0) {
dev_dbg(dev, "%s: link id = %d is disabled\n",
__func__, link_idx);
continue;
}
ret = maxim4c_remote_dev_info_parse(dev, remote_mfd_dev, link_idx);
if (ret == 0) {
remote_mfd_dev++;
nr_mfd_cell++;
}
}
dev_info(dev, "Total number of remote devices is %d", nr_mfd_cell);
return nr_mfd_cell;
}
int maxim4c_remote_mfd_add_devices(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int nr_mfd_cell = 0, ret = 0;
dev_info(dev, "=== maxim4c add remote devices ===");
nr_mfd_cell = maxim4c_remote_mfd_devs_init(maxim4c);
if (nr_mfd_cell == 0) {
dev_err(dev, "%s: remote mfd devices init error\n",
__func__);
return -EINVAL;
}
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
maxim4c->remote_mfd_devs, nr_mfd_cell,
NULL, 0, NULL);
if (ret)
dev_err(dev, "%s: add remote mfd devices error: %d\n",
__func__, ret);
return ret;
}
EXPORT_SYMBOL(maxim4c_remote_mfd_add_devices);
int maxim4c_remote_devices_init(maxim4c_t *maxim4c, u8 link_init_mask)
{
struct device *dev = &maxim4c->client->dev;
struct maxim4c_remote *remote_device = NULL;
const struct maxim4c_remote_ops *remote_ops = NULL;
u8 link_mask = 0, link_enable = 0, link_locked = 0;
int ret = 0, i = 0;
dev_dbg(dev, "%s: link init mask = 0x%02x\n", __func__, link_init_mask);
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
if ((link_init_mask & BIT(i)) == 0) {
dev_dbg(dev, "link id = %d init mask is disabled\n", i);
continue;
}
link_enable = maxim4c->gmsl_link.link_cfg[i].link_enable;
if (link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
continue;
}
remote_device = maxim4c->remote_device[i];
if (remote_device == NULL) {
dev_info(dev, "remote device id = %d isn't detected\n", i);
continue;
}
if (remote_device->remote_enable == 0) {
dev_info(dev, "remote device id = %d isn't enabled\n", i);
continue;
}
remote_ops = remote_device->remote_ops;
if (remote_ops == NULL) {
dev_info(dev, "remote device id = %d is no ops\n", i);
continue;
}
link_mask = BIT(i);
link_locked = maxim4c_link_get_lock_state(maxim4c, link_mask);
if (link_locked != link_mask) {
dev_info(dev, "link id = %d is unlocked\n", i);
continue;
}
maxim4c_link_select_remote_control(maxim4c, link_mask);
if (remote_ops->remote_init)
ret |= remote_ops->remote_init(remote_device);
}
return ret;
}
EXPORT_SYMBOL(maxim4c_remote_devices_init);
int maxim4c_remote_devices_deinit(maxim4c_t *maxim4c, u8 link_init_mask)
{
struct device *dev = &maxim4c->client->dev;
struct maxim4c_remote *remote_device = NULL;
const struct maxim4c_remote_ops *remote_ops = NULL;
u8 link_mask = 0, link_enable = 0, link_locked = 0;
int ret = 0, i = 0;
dev_dbg(dev, "%s: link init mask = 0x%02x\n", __func__, link_init_mask);
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
if ((link_init_mask & BIT(i)) == 0) {
dev_dbg(dev, "link id = %d init mask is disabled\n", i);
continue;
}
link_enable = maxim4c->gmsl_link.link_cfg[i].link_enable;
if (link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
continue;
}
remote_device = maxim4c->remote_device[i];
if (remote_device == NULL) {
dev_info(dev, "remote device id = %d isn't detected\n", i);
continue;
}
if (remote_device->remote_enable == 0) {
dev_info(dev, "remote device id = %d isn't enabled\n", i);
continue;
}
remote_ops = remote_device->remote_ops;
if (remote_ops == NULL) {
dev_info(dev, "remote device id = %d is no ops\n", i);
continue;
}
link_mask = BIT(i);
link_locked = maxim4c_link_get_lock_state(maxim4c, link_mask);
if (link_locked != link_mask) {
dev_info(dev, "link id = %d is unlocked\n", i);
continue;
}
maxim4c_link_select_remote_control(maxim4c, link_mask);
if (remote_ops->remote_deinit)
ret |= remote_ops->remote_deinit(remote_device);
}
return ret;
}
EXPORT_SYMBOL(maxim4c_remote_devices_deinit);
int maxim4c_remote_load_init_seq(maxim4c_remote_t *remote_device)
{
struct device *dev = remote_device->dev;
struct device_node *node = NULL;
int ret = 0;
node = of_get_child_by_name(dev->of_node, "remote-init-sequence");
if (!IS_ERR_OR_NULL(node)) {
dev_info(dev, "load remote-init-sequence\n");
ret = maxim4c_i2c_load_init_seq(dev, node,
&remote_device->remote_init_seq);
of_node_put(node);
return ret;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_remote_load_init_seq);
int maxim4c_remote_i2c_addr_select(maxim4c_remote_t *remote_device, u32 i2c_id)
{
struct device *dev = remote_device->dev;
struct i2c_client *client = remote_device->client;
if (i2c_id == MAXIM4C_I2C_SER_DEF) {
client->addr = remote_device->ser_i2c_addr_def;
dev_info(dev, "ser select default i2c addr = 0x%02x\n", client->addr);
} else if (i2c_id == MAXIM4C_I2C_SER_MAP) {
client->addr = remote_device->ser_i2c_addr_map;
dev_info(dev, "ser select mapping i2c addr = 0x%02x\n", client->addr);
} else {
dev_err(dev, "i2c select id = %d error\n", i2c_id);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_remote_i2c_addr_select);
int maxim4c_remote_i2c_client_init(maxim4c_remote_t *remote_device,
struct i2c_client *des_client)
{
struct device *dev = remote_device->dev;
struct i2c_client *ser_client = NULL;
u16 ser_client_addr = 0;
if (remote_device->ser_i2c_addr_map)
ser_client_addr = remote_device->ser_i2c_addr_map;
else
ser_client_addr = remote_device->ser_i2c_addr_def;
ser_client = devm_i2c_new_dummy_device(&des_client->dev,
des_client->adapter, ser_client_addr);
if (IS_ERR(ser_client)) {
dev_err(dev, "failed to alloc i2c client.\n");
return -PTR_ERR(ser_client);
}
ser_client->addr = remote_device->ser_i2c_addr_def;
remote_device->client = ser_client;
i2c_set_clientdata(ser_client, remote_device);
dev_info(dev, "remote i2c client init, i2c_addr = 0x%02x\n",
ser_client_addr);
return 0;
}
EXPORT_SYMBOL(maxim4c_remote_i2c_client_init);
static int maxim4c_remote_device_chain_check(maxim4c_remote_t *remote_device)
{
struct device *dev = NULL;
struct device_node *endpoint = NULL;
struct device_node *link_node = NULL;
u8 remote_id, link_id;
u32 value;
int ret = 0;
if (remote_device == NULL) {
dev_err(dev, "%s: input parameter is error\n", __func__);
return -EINVAL;
}
dev = remote_device->dev;
remote_id = remote_device->remote_id;
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
if (!endpoint) {
dev_err(dev, "%s: no endpoint error\n", __func__);
return -EINVAL;
}
link_node = of_graph_get_remote_port_parent(endpoint);
if (!link_node) {
dev_err(dev, "%pOF: endpoint has no remote port parent error\n",
endpoint);
return -EINVAL;
}
ret = of_property_read_u32(link_node, "link-id", &value);
if (ret) {
dev_err(dev, "%pOF: no property link_id error\n", link_node);
of_node_put(link_node);
return -EINVAL;
}
of_node_put(link_node);
link_id = value;
if (remote_id != link_id) {
dev_err(dev, "remote_id (%d) != link_id (%d) of %pOF\n",
remote_id, link_id, link_node);
return -EINVAL;
}
return 0;
}
int maxim4c_remote_device_register(maxim4c_t *maxim4c,
maxim4c_remote_t *remote_device)
{
struct device *dev = NULL;
u8 remote_id;
int ret = 0;
if ((maxim4c == NULL) || (remote_device == NULL)) {
dev_err(dev, "%s: input parameter is error!\n", __func__);
return -EINVAL;
}
dev = remote_device->dev;
remote_id = remote_device->remote_id;
if (remote_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(dev, "%s: remote_id = %d is error\n",
__func__, remote_id);
return -EINVAL;
}
if (maxim4c->remote_device[remote_id] != NULL) {
dev_err(dev, "%s: remote_id = %d is conflict\n",
__func__, remote_id);
return -EINVAL;
}
ret = maxim4c_remote_device_chain_check(remote_device);
if (ret) {
dev_err(dev, "%s: remote device id = %d chain error\n",
__func__, remote_id);
return -EINVAL;
}
remote_device->remote_enable = 1;
maxim4c->remote_device[remote_id] = remote_device;
return 0;
}
EXPORT_SYMBOL(maxim4c_remote_device_register);

View File

@@ -1,36 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#ifndef __MAXIM4C_REMOTE_H__
#define __MAXIM4C_REMOTE_H__
#include "maxim4c_i2c.h"
struct maxim4c_remote;
struct maxim4c_remote_ops {
int (*remote_init)(struct maxim4c_remote *remote);
int (*remote_deinit)(struct maxim4c_remote *remote);
};
typedef struct maxim4c_remote {
struct i2c_client *client;
struct device *dev;
void *local;
const struct maxim4c_remote_ops *remote_ops;
struct maxim4c_i2c_init_seq remote_init_seq;
u8 remote_id;
u8 remote_enable;
u8 ser_i2c_addr_def;
u8 ser_i2c_addr_map;
u8 cam_i2c_addr_def;
u8 cam_i2c_addr_map;
} maxim4c_remote_t;
#endif /* __MAXIM4C_REMOTE_H__ */

View File

@@ -1,337 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Maxim Quad GMSL2/GMSL1 to CSI-2 Serializer driver
*
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
*
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include "maxim4c_api.h"
#define MAX9295_I2C_ADDR_DEF 0x40
#define MAX9295_CHIP_ID 0x91
#define MAX9295_REG_CHIP_ID 0x0D
static int max9295_i2c_addr_remap(maxim4c_remote_t *max9295)
{
struct device *dev = max9295->dev;
struct i2c_client *client = max9295->client;
u16 i2c_8bit_addr = 0;
int ret = 0;
if (max9295->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
i2c_8bit_addr = (max9295->ser_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
0x0000, MAXIM4C_I2C_REG_ADDR_16BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "ser i2c address map setting error!\n");
return ret;
}
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
}
if (max9295->cam_i2c_addr_map) {
dev_info(dev, "Camera i2c address remap\n");
i2c_8bit_addr = (max9295->cam_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
0x0042, MAXIM4C_I2C_REG_ADDR_16BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "cam i2c address source setting error!\n");
return ret;
}
i2c_8bit_addr = (max9295->cam_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
0x0043, MAXIM4C_I2C_REG_ADDR_16BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "cam i2c address destination setting error!\n");
return ret;
}
}
return 0;
}
static int max9295_i2c_addr_def(maxim4c_remote_t *max9295)
{
struct device *dev = max9295->dev;
struct i2c_client *client = max9295->client;
u16 i2c_8bit_addr = 0;
int ret = 0;
if (max9295->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
i2c_8bit_addr = (max9295->ser_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
0x0000, MAXIM4C_I2C_REG_ADDR_16BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "ser i2c address def setting error!\n");
return ret;
}
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
}
return 0;
}
static int max9295_check_chipid(maxim4c_remote_t *max9295)
{
struct device *dev = max9295->dev;
struct i2c_client *client = max9295->client;
u8 chip_id;
int ret = 0;
// max9295
ret = maxim4c_i2c_read_byte(client,
MAX9295_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
ret = maxim4c_i2c_read_byte(client,
MAX9295_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chip_id);
if (ret != 0) {
dev_err(dev, "MAX9295 detect error, ret(%d)\n", ret);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
max9295_i2c_addr_def(max9295);
}
if (chip_id != MAX9295_CHIP_ID) {
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX9295 chip id: 0x%02x\n", chip_id);
return 0;
}
static int max9295_soft_power_down(maxim4c_remote_t *max9295)
{
struct device *dev = max9295->dev;
struct i2c_client *client = max9295->client;
int ret = 0;
ret = maxim4c_i2c_write_byte(client,
0x10, MAXIM4C_I2C_REG_ADDR_16BITS,
BIT(7));
if (ret) {
dev_err(dev, "soft power down setting error!\n");
return ret;
}
return 0;
}
static int max9295_module_init(maxim4c_remote_t *max9295)
{
struct device *dev = max9295->dev;
struct i2c_client *client = max9295->client;
int ret = 0;
ret = maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
ret = max9295_check_chipid(max9295);
if (ret)
return ret;
ret = max9295_i2c_addr_remap(max9295);
if (ret)
return ret;
ret = maxim4c_i2c_run_init_seq(client,
&max9295->remote_init_seq);
if (ret) {
dev_err(dev, "remote id = %d init sequence error\n",
max9295->remote_id);
return ret;
}
return 0;
}
static int max9295_module_deinit(maxim4c_remote_t *max9295)
{
int ret = 0;
#if 0
ret |= max9295_i2c_addr_def(max9295);
#endif
ret |= max9295_soft_power_down(max9295);
return ret;
}
static const struct maxim4c_remote_ops max9295_ops = {
.remote_init = max9295_module_init,
.remote_deinit = max9295_module_deinit,
};
static int max9295_parse_dt(maxim4c_remote_t *max9295)
{
struct device *dev = max9295->dev;
struct device_node *of_node = dev->of_node;
u32 value = 0;
int ret = 0;
dev_info(dev, "=== maxim4c remote max9295 parse dt ===\n");
ret = of_property_read_u32(of_node, "remote-id", &value);
if (ret == 0) {
dev_info(dev, "remote-id property: %d\n", value);
max9295->remote_id = value;
} else {
max9295->remote_id = MAXIM4C_LINK_ID_MAX;
}
dev_info(dev, "max9295 remote id: %d\n", max9295->remote_id);
ret = of_property_read_u32(of_node, "ser-i2c-addr-def", &value);
if (ret == 0) {
dev_info(dev, "ser-i2c-addr-def property: 0x%x", value);
max9295->ser_i2c_addr_def = value;
} else {
max9295->ser_i2c_addr_def = MAX9295_I2C_ADDR_DEF;
}
ret = of_property_read_u32(of_node, "ser-i2c-addr-map", &value);
if (ret == 0) {
dev_info(dev, "ser-i2c-addr-map property: 0x%x", value);
max9295->ser_i2c_addr_map = value;
}
ret = of_property_read_u32(of_node, "cam-i2c-addr-def", &value);
if (ret == 0) {
dev_info(dev, "cam-i2c-addr-def property: 0x%x", value);
max9295->cam_i2c_addr_def = value;
}
ret = of_property_read_u32(of_node, "cam-i2c-addr-map", &value);
if (ret == 0) {
dev_info(dev, "cam-i2c-addr-map property: 0x%x", value);
max9295->cam_i2c_addr_map = value;
}
return 0;
}
static int max9295_probe(struct platform_device *pdev)
{
struct i2c_client *client = to_i2c_client(pdev->dev.parent);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
struct maxim4c_remote *max9295 = NULL;
u32 link_id = MAXIM4C_LINK_ID_MAX;
int ret = 0;
dev_info(&pdev->dev, "max9295 serializer probe\n");
link_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
link_id = link_id - MAXIM4C_LINK_ID_MAX;
if (link_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(&pdev->dev, "max9295 probe match data error\n");
return -EINVAL;
}
dev_info(&pdev->dev, "max9295 probe link id = %d\n", link_id);
max9295 = devm_kzalloc(&pdev->dev, sizeof(*max9295), GFP_KERNEL);
if (!max9295) {
dev_err(&pdev->dev, "max9295 probe no memory error\n");
return -ENOMEM;
}
max9295->dev = &pdev->dev;
max9295->remote_ops = &max9295_ops;
max9295->local = maxim4c;
dev_set_drvdata(max9295->dev, max9295);
max9295_parse_dt(max9295);
if (max9295->remote_id != link_id) {
dev_err(&pdev->dev, "max9295 probe remote_id error\n");
return -EINVAL;
}
ret = maxim4c_remote_i2c_client_init(max9295, client);
if (ret) {
dev_err(&pdev->dev, "remote i2c client init error\n");
return ret;
}
ret = maxim4c_remote_device_register(maxim4c, max9295);
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max9295);
return 0;
}
static int max9295_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id max9295_of_table[] = {
{
.compatible = "maxim4c,link0,max9295",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_A)
}, {
.compatible = "maxim4c,link1,max9295",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_B)
}, {
.compatible = "maxim4c,link2,max9295",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_C)
}, {
.compatible = "maxim4c,link3,max9295",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_D)
},
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, max9295_of_table);
static struct platform_driver max9295_driver = {
.probe = max9295_probe,
.remove = max9295_remove,
.driver = {
.name = "maxim4c-max9295",
.of_match_table = max9295_of_table,
},
};
module_platform_driver(max9295_driver);
MODULE_AUTHOR("Cai Wenzhong <cwz@rock-chips.com>");
MODULE_DESCRIPTION("Maxim MAX9295 Serializer Driver");
MODULE_LICENSE("GPL");

View File

@@ -1,387 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Maxim Quad GMSL2/GMSL1 to CSI-2 Serializer driver
*
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
*
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include "maxim4c_api.h"
#define MAX96715_I2C_ADDR_DEF 0x40
#define MAX96715_CHIP_ID 0x45
#define MAX96715_REG_CHIP_ID 0x1E
/* Config and Video mode switch */
#define MAX96715_MODE_SWITCH 1
enum {
LINK_MODE_VIDEO = 0,
LINK_MODE_CONFIG,
};
static int __maybe_unused max96715_link_mode_select(maxim4c_remote_t *max96715, u32 mode)
{
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
u8 reg_mask = 0, reg_value = 0;
u32 delay_ms = 0;
int ret = 0;
dev_dbg(dev, "%s: mode = %d\n", __func__, mode);
reg_mask = BIT(7) | BIT(6);
if (mode == LINK_MODE_CONFIG) {
reg_value = BIT(6);
delay_ms = 5;
} else {
reg_value = BIT(7);
delay_ms = 50;
}
ret |= maxim4c_i2c_update_byte(client,
0x04, MAXIM4C_I2C_REG_ADDR_08BITS,
reg_mask, reg_value);
msleep(delay_ms);
return ret;
}
static int max96715_i2c_addr_remap(maxim4c_remote_t *max96715)
{
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
u16 i2c_8bit_addr = 0;
int ret = 0;
if (max96715->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
i2c_8bit_addr = (max96715->ser_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
0x00, MAXIM4C_I2C_REG_ADDR_08BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "ser i2c address map setting error!\n");
return ret;
}
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
}
if (max96715->cam_i2c_addr_map) {
dev_info(dev, "Camera i2c address remap\n");
i2c_8bit_addr = (max96715->cam_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
0x09, MAXIM4C_I2C_REG_ADDR_08BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "cam i2c address source setting error!\n");
return ret;
}
i2c_8bit_addr = (max96715->cam_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
0x0A, MAXIM4C_I2C_REG_ADDR_08BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "cam i2c address destination setting error!\n");
return ret;
}
}
return 0;
}
static int max96715_i2c_addr_def(maxim4c_remote_t *max96715)
{
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
u16 i2c_8bit_addr = 0;
int ret = 0;
if (max96715->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
i2c_8bit_addr = (max96715->ser_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
0x00, MAXIM4C_I2C_REG_ADDR_08BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "ser i2c address def setting error!\n");
return ret;
}
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
}
return 0;
}
static int max96715_check_chipid(maxim4c_remote_t *max96715)
{
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
u8 chip_id;
int ret = 0;
// max96715
ret = maxim4c_i2c_read_byte(client,
MAX96715_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_08BITS,
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
ret = maxim4c_i2c_read_byte(client,
MAX96715_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_08BITS,
&chip_id);
if (ret != 0) {
dev_err(dev, "MAX96715 detect error, ret(%d)\n", ret);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
max96715_i2c_addr_def(max96715);
}
if (chip_id != MAX96715_CHIP_ID) {
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX96715 chip id: 0x%02x\n", chip_id);
return 0;
}
static int max96715_soft_power_down(maxim4c_remote_t *max96715)
{
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
int ret = 0;
ret = maxim4c_i2c_write_byte(client,
0x13, MAXIM4C_I2C_REG_ADDR_08BITS,
BIT(7));
if (ret) {
dev_err(dev, "soft power down setting error!\n");
return ret;
}
return 0;
}
static int max96715_module_init(maxim4c_remote_t *max96715)
{
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
int ret = 0;
ret = maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
ret = max96715_check_chipid(max96715);
if (ret)
return ret;
ret = max96715_i2c_addr_remap(max96715);
if (ret)
return ret;
#if MAX96715_MODE_SWITCH
ret = max96715_link_mode_select(max96715, LINK_MODE_CONFIG);
if (ret)
return ret;
#endif
ret = maxim4c_i2c_run_init_seq(client,
&max96715->remote_init_seq);
if (ret) {
dev_err(dev, "remote id = %d init sequence error\n",
max96715->remote_id);
return ret;
}
#if MAX96715_MODE_SWITCH
ret = max96715_link_mode_select(max96715, LINK_MODE_VIDEO);
if (ret)
return ret;
#endif
return 0;
}
static int max96715_module_deinit(maxim4c_remote_t *max96715)
{
int ret = 0;
#if 0
ret |= max96715_i2c_addr_def(max96715);
#endif
ret |= max96715_soft_power_down(max96715);
return ret;
}
static const struct maxim4c_remote_ops max96715_ops = {
.remote_init = max96715_module_init,
.remote_deinit = max96715_module_deinit,
};
static int max96715_parse_dt(maxim4c_remote_t *max96715)
{
struct device *dev = max96715->dev;
struct device_node *of_node = dev->of_node;
u32 value = 0;
int ret = 0;
dev_info(dev, "=== maxim4c remote max96715 parse dt ===\n");
ret = of_property_read_u32(of_node, "remote-id", &value);
if (ret == 0) {
dev_info(dev, "remote-id property: %d\n", value);
max96715->remote_id = value;
} else {
max96715->remote_id = MAXIM4C_LINK_ID_MAX;
}
dev_info(dev, "max96715 remote id: %d\n", max96715->remote_id);
ret = of_property_read_u32(of_node, "ser-i2c-addr-def", &value);
if (ret == 0) {
dev_info(dev, "ser-i2c-addr-def property: 0x%x", value);
max96715->ser_i2c_addr_def = value;
} else {
max96715->ser_i2c_addr_def = MAX96715_I2C_ADDR_DEF;
}
ret = of_property_read_u32(of_node, "ser-i2c-addr-map", &value);
if (ret == 0) {
dev_info(dev, "ser-i2c-addr-map property: 0x%x", value);
max96715->ser_i2c_addr_map = value;
}
ret = of_property_read_u32(of_node, "cam-i2c-addr-def", &value);
if (ret == 0) {
dev_info(dev, "cam-i2c-addr-def property: 0x%x", value);
max96715->cam_i2c_addr_def = value;
}
ret = of_property_read_u32(of_node, "cam-i2c-addr-map", &value);
if (ret == 0) {
dev_info(dev, "cam-i2c-addr-map property: 0x%x", value);
max96715->cam_i2c_addr_map = value;
}
return 0;
}
static int max96715_probe(struct platform_device *pdev)
{
struct i2c_client *client = to_i2c_client(pdev->dev.parent);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
struct maxim4c_remote *max96715 = NULL;
u32 link_id = MAXIM4C_LINK_ID_MAX;
int ret = 0;
dev_info(&pdev->dev, "max96715 serializer probe\n");
link_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
link_id = link_id - MAXIM4C_LINK_ID_MAX;
if (link_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(&pdev->dev, "max96715 probe match data error\n");
return -EINVAL;
}
dev_info(&pdev->dev, "max96715 probe link id = %d\n", link_id);
max96715 = devm_kzalloc(&pdev->dev, sizeof(*max96715), GFP_KERNEL);
if (!max96715) {
dev_err(&pdev->dev, "max96715 probe no memory error\n");
return -ENOMEM;
}
max96715->dev = &pdev->dev;
max96715->remote_ops = &max96715_ops;
max96715->local = maxim4c;
dev_set_drvdata(max96715->dev, max96715);
max96715_parse_dt(max96715);
if (max96715->remote_id != link_id) {
dev_err(&pdev->dev, "max96715 probe remote_id error\n");
return -EINVAL;
}
ret = maxim4c_remote_i2c_client_init(max96715, client);
if (ret) {
dev_err(&pdev->dev, "remote i2c client init error\n");
return ret;
}
ret = maxim4c_remote_device_register(maxim4c, max96715);
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max96715);
return 0;
}
static int max96715_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id max96715_of_table[] = {
{
.compatible = "maxim4c,link0,max96715",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_A)
}, {
.compatible = "maxim4c,link1,max96715",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_B)
}, {
.compatible = "maxim4c,link2,max96715",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_C)
}, {
.compatible = "maxim4c,link3,max96715",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_D)
},
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, max96715_of_table);
static struct platform_driver max96715_driver = {
.probe = max96715_probe,
.remove = max96715_remove,
.driver = {
.name = "maxim4c-max96715",
.of_match_table = max96715_of_table,
},
};
module_platform_driver(max96715_driver);
MODULE_AUTHOR("Cai Wenzhong <cwz@rock-chips.com>");
MODULE_DESCRIPTION("Maxim MAX96715 Serializer Driver");
MODULE_LICENSE("GPL");

View File

@@ -1,316 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Maxim Quad GMSL2/GMSL1 to CSI-2 Serializer driver
*
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
*
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include "maxim4c_api.h"
#define MAX96717_I2C_ADDR_DEF 0x40
#define MAX96717_CHIP_ID 0xBF
#define MAX96717_REG_CHIP_ID 0x0D
static int max96717_i2c_addr_remap(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
struct i2c_client *client = max96717->client;
u16 i2c_8bit_addr = 0;
int ret = 0;
if (max96717->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
i2c_8bit_addr = (max96717->ser_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
0x0000, MAXIM4C_I2C_REG_ADDR_16BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "ser i2c address map setting error!\n");
return ret;
}
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
}
if (max96717->cam_i2c_addr_map) {
dev_info(dev, "Camera i2c address remap\n");
i2c_8bit_addr = (max96717->cam_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
0x0042, MAXIM4C_I2C_REG_ADDR_16BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "cam i2c address source setting error!\n");
return ret;
}
i2c_8bit_addr = (max96717->cam_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
0x0043, MAXIM4C_I2C_REG_ADDR_16BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "cam i2c address destination setting error!\n");
return ret;
}
}
return 0;
}
static int max96717_i2c_addr_def(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
struct i2c_client *client = max96717->client;
u16 i2c_8bit_addr = 0;
int ret = 0;
if (max96717->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
i2c_8bit_addr = (max96717->ser_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
0x0000, MAXIM4C_I2C_REG_ADDR_16BITS,
i2c_8bit_addr);
if (ret) {
dev_err(dev, "ser i2c address def setting error!\n");
return ret;
}
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
}
return 0;
}
static int max96717_check_chipid(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
struct i2c_client *client = max96717->client;
u8 chip_id;
int ret = 0;
// max96717
ret = maxim4c_i2c_read_byte(client,
MAX96717_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
ret = maxim4c_i2c_read_byte(client,
MAX96717_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chip_id);
if (ret != 0) {
dev_err(dev, "MAX96717 detect error, ret(%d)\n", ret);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
max96717_i2c_addr_def(max96717);
}
if (chip_id != MAX96717_CHIP_ID) {
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX96717 chip id: 0x%02x\n", chip_id);
return 0;
}
static int max96717_module_init(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
struct i2c_client *client = max96717->client;
int ret = 0;
ret = maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
ret = max96717_check_chipid(max96717);
if (ret)
return ret;
ret = max96717_i2c_addr_remap(max96717);
if (ret)
return ret;
ret = maxim4c_i2c_run_init_seq(client,
&max96717->remote_init_seq);
if (ret) {
dev_err(dev, "remote id = %d init sequence error\n",
max96717->remote_id);
return ret;
}
return 0;
}
static int max96717_module_deinit(maxim4c_remote_t *max96717)
{
int ret = 0;
ret |= max96717_i2c_addr_def(max96717);
return ret;
}
static const struct maxim4c_remote_ops max96717_ops = {
.remote_init = max96717_module_init,
.remote_deinit = max96717_module_deinit,
};
static int max96717_parse_dt(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
struct device_node *of_node = dev->of_node;
u32 value = 0;
int ret = 0;
dev_info(dev, "=== maxim4c remote max96717 parse dt ===\n");
ret = of_property_read_u32(of_node, "remote-id", &value);
if (ret == 0) {
dev_info(dev, "remote-id property: %d\n", value);
max96717->remote_id = value;
} else {
max96717->remote_id = MAXIM4C_LINK_ID_MAX;
}
dev_info(dev, "max96717 remote id: %d\n", max96717->remote_id);
ret = of_property_read_u32(of_node, "ser-i2c-addr-def", &value);
if (ret == 0) {
dev_info(dev, "ser-i2c-addr-def property: 0x%x", value);
max96717->ser_i2c_addr_def = value;
} else {
max96717->ser_i2c_addr_def = MAX96717_I2C_ADDR_DEF;
}
ret = of_property_read_u32(of_node, "ser-i2c-addr-map", &value);
if (ret == 0) {
dev_info(dev, "ser-i2c-addr-map property: 0x%x", value);
max96717->ser_i2c_addr_map = value;
}
ret = of_property_read_u32(of_node, "cam-i2c-addr-def", &value);
if (ret == 0) {
dev_info(dev, "cam-i2c-addr-def property: 0x%x", value);
max96717->cam_i2c_addr_def = value;
}
ret = of_property_read_u32(of_node, "cam-i2c-addr-map", &value);
if (ret == 0) {
dev_info(dev, "cam-i2c-addr-map property: 0x%x", value);
max96717->cam_i2c_addr_map = value;
}
return 0;
}
static int max96717_probe(struct platform_device *pdev)
{
struct i2c_client *client = to_i2c_client(pdev->dev.parent);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
struct maxim4c_remote *max96717 = NULL;
u32 link_id = MAXIM4C_LINK_ID_MAX;
int ret = 0;
dev_info(&pdev->dev, "max96717 serializer probe\n");
link_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
link_id = link_id - MAXIM4C_LINK_ID_MAX;
if (link_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(&pdev->dev, "max96717 probe match data error\n");
return -EINVAL;
}
dev_info(&pdev->dev, "max96717 probe link id = %d\n", link_id);
max96717 = devm_kzalloc(&pdev->dev, sizeof(*max96717), GFP_KERNEL);
if (!max96717) {
dev_err(&pdev->dev, "max96717 probe no memory error\n");
return -ENOMEM;
}
max96717->dev = &pdev->dev;
max96717->remote_ops = &max96717_ops;
max96717->local = maxim4c;
dev_set_drvdata(max96717->dev, max96717);
max96717_parse_dt(max96717);
if (max96717->remote_id != link_id) {
dev_err(&pdev->dev, "max96717 probe remote_id error\n");
return -EINVAL;
}
ret = maxim4c_remote_i2c_client_init(max96717, client);
if (ret) {
dev_err(&pdev->dev, "remote i2c client init error\n");
return ret;
}
ret = maxim4c_remote_device_register(maxim4c, max96717);
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max96717);
return 0;
}
static int max96717_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id max96717_of_table[] = {
{
.compatible = "maxim4c,link0,max96717",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_A)
}, {
.compatible = "maxim4c,link1,max96717",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_B)
}, {
.compatible = "maxim4c,link2,max96717",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_C)
}, {
.compatible = "maxim4c,link3,max96717",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_D)
},
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, max96717_of_table);
static struct platform_driver max96717_driver = {
.probe = max96717_probe,
.remove = max96717_remove,
.driver = {
.name = "maxim4c-max96717",
.of_match_table = max96717_of_table,
},
};
module_platform_driver(max96717_driver);
MODULE_AUTHOR("Cai Wenzhong <cwz@rock-chips.com>");
MODULE_DESCRIPTION("Maxim MAX96717 Serializer Driver");
MODULE_LICENSE("GPL");