media: i2c: maxim4c: driver version v2.01.00

1. remote device and local link are bound through link id
2. support local and remote port chain check
3. drivers/media/i2c/maxim4c/Kconfig support menu select
4. optimize delay time and error messages
5. power control: local by pwdn gpio, remote by pocen gpio
6. local pwdn on/off enable depend on MAXIM4C_LOCAL_DES_ON_OFF_EN

Signed-off-by: Cai Wenzhong <cwz@rock-chips.com>
Change-Id: Ife74e6251b09628e8413aa810c995e7a71449f1d
This commit is contained in:
Cai Wenzhong
2023-08-23 12:05:26 +08:00
committed by Tao Huang
parent ca9f8fb207
commit 49d91f5a0f
15 changed files with 698 additions and 443 deletions

View File

@@ -3,42 +3,44 @@
# Maxim Quad GMSL deserializer and serializer devices
#
config VIDEO_DES_MAXIM4C
tristate "Maxim Qual GMSL deserializer support"
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 Qual GMSL2/GMSL1 deserializer.
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 GMSL serializer support"
depends on I2C
select VIDEO_DES_MAXIM4C
tristate "Maxim GMSL2 serializer max9295 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL2 serializer.
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 GMSL serializer support"
depends on I2C
select VIDEO_DES_MAXIM4C
tristate "Maxim GMSL1 Serializer max96715 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL1 serializer.
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 GMSL serializer support"
depends on I2C
select VIDEO_DES_MAXIM4C
tristate "Maxim GMSL2 Serializer max96717 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL2 serializer.
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

@@ -23,6 +23,9 @@
/* Maxim Deserializer Test Pattern */
#define MAXIM4C_TEST_PATTERN 0
/* 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);
@@ -77,15 +80,22 @@ 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);
maxim4c_remote_t *remote_device);
/* maxim4c v4l2 subdev api */
int maxim4c_v4l2_subdev_init(maxim4c_t *maxim4c);
void maxim4c_v4l2_subdev_deinit(maxim4c_t *maxim4c);
int maxim4c_module_hw_init(maxim4c_t *maxim4c);
/* maxim4c pattern api */
int maxim4c_pattern_init(maxim4c_t *maxim4c);
int maxim4c_pattern_hw_init(maxim4c_t *maxim4c);
int maxim4c_pattern_support_mode_init(maxim4c_t *maxim4c);
int maxim4c_pattern_data_init(maxim4c_t *maxim4c);
int maxim4c_pattern_enable(maxim4c_t *maxim4c, bool enable);
#endif /* __MAXIM4C_API_H__ */

View File

@@ -6,7 +6,7 @@
*
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
* V2.0.00 maxim serdes qual GMSL2/GMSL1 driver framework.
* V2.00.00 maxim serdes quad GMSL2/GMSL1 driver framework.
* 1. local deserializer support: max96712/max96722
* 2. remote serializer support: max9295/max96715/max96717
* 3. support deserializer and serializer auto adaptive
@@ -14,6 +14,14 @@
* 5. support remote serializer I2c address mapping
* 6. support remote serializer hot plug detection and recovery
*
* V2.01.00
* 1. remote device and local link are bound through link id
* 2. support local and remote port chain check
* 3. drivers/media/i2c/maxim4c/Kconfig support menu select
* 4. optimize delay time and error messages
* 5. power control: local by pwdn gpio, remote by pocen gpio
* 6. local pwdn on/off enable depend on MAXIM4C_LOCAL_DES_ON_OFF_EN
*
*/
#include <linux/clk.h>
#include <linux/i2c.h>
@@ -43,14 +51,10 @@
#include "maxim4c_api.h"
#define DRIVER_VERSION KERNEL_VERSION(2, 0x00, 0x00)
#define DRIVER_VERSION KERNEL_VERSION(2, 0x01, 0x00)
#define MAXIM4C_XVCLK_FREQ 25000000
/* device compatible */
#define MAXIM4C_MAX96712_COMPAT "maxim4c,max96712"
#define MAXIM4C_MAX96722_COMPAT "maxim4c,max96722"
static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
{
struct i2c_client *client = maxim4c->client;
@@ -59,6 +63,11 @@ static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
u8 chipid = 0;
for (loop = 0; loop < 5; loop++) {
if (loop != 0) {
dev_info(dev, "check local chipid retry (%d)", loop);
msleep(10);
}
ret = maxim4c_i2c_read_byte(client,
MAXIM4C_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chipid);
@@ -74,13 +83,10 @@ static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
return 0;
}
} else {
dev_err(dev, "Unexpected maxim chipid(%02x)\n", chipid);
dev_err(dev, "Unexpected maxim chipid = %02x\n", chipid);
return -ENODEV;
}
}
dev_info(dev, "retry (%d) to check local chipid", loop + 1);
msleep(10);
}
dev_err(dev, "maxim check chipid error, ret(%d)\n", ret);
@@ -181,13 +187,13 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
link_id = MAXIM4C_LINK_ID_A;
if (curr_lock_state & MAXIM4C_LINK_MASK_A) {
dev_info(dev, "link A plug in\n");
dev_info(dev, "Link A plug in\n");
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_A);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
} else {
dev_info(dev, "link A plug out\n");
dev_info(dev, "Link A plug out\n");
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
@@ -197,13 +203,13 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
link_id = MAXIM4C_LINK_ID_B;
if (curr_lock_state & MAXIM4C_LINK_MASK_B) {
dev_info(dev, "link B plug in\n");
dev_info(dev, "Link B plug in\n");
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_B);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
} else {
dev_info(dev, "link B plug out\n");
dev_info(dev, "Link B plug out\n");
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
@@ -213,13 +219,13 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
link_id = MAXIM4C_LINK_ID_C;
if (curr_lock_state & MAXIM4C_LINK_MASK_C) {
dev_info(dev, "link C plug in\n");
dev_info(dev, "Link C plug in\n");
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_C);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
} else {
dev_info(dev, "link C plug out\n");
dev_info(dev, "Link C plug out\n");
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
@@ -229,13 +235,13 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
link_id = MAXIM4C_LINK_ID_D;
if (curr_lock_state & MAXIM4C_LINK_MASK_D) {
dev_info(dev, "link D plug in\n");
dev_info(dev, "Link D plug in\n");
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_D);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
} else {
dev_info(dev, "link D plug out\n");
dev_info(dev, "Link D plug out\n");
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
@@ -290,10 +296,10 @@ static int maxim4c_local_device_power_on(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
if (!IS_ERR(maxim4c->power_gpio)) {
dev_info(dev, "local device power gpio on\n");
if (!IS_ERR(maxim4c->pwdn_gpio)) {
dev_info(dev, "local device pwdn gpio on\n");
gpiod_set_value_cansleep(maxim4c->power_gpio, 1);
gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 1);
usleep_range(5000, 10000);
}
@@ -305,10 +311,10 @@ static void maxim4c_local_device_power_off(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
if (!IS_ERR(maxim4c->power_gpio)) {
dev_info(dev, "local device power gpio off\n");
if (!IS_ERR(maxim4c->pwdn_gpio)) {
dev_info(dev, "local device pwdn gpio off\n");
gpiod_set_value_cansleep(maxim4c->power_gpio, 0);
gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 0);
}
}
@@ -318,7 +324,7 @@ static int maxim4c_remote_device_power_on(maxim4c_t *maxim4c)
// remote PoC enable
if (!IS_ERR(maxim4c->pocen_gpio)) {
dev_info(dev, "remote device poc gpio on\n");
dev_info(dev, "remote device pocen gpio on\n");
gpiod_set_value_cansleep(maxim4c->pocen_gpio, 1);
usleep_range(5000, 10000);
@@ -333,7 +339,7 @@ static int maxim4c_remote_device_power_off(maxim4c_t *maxim4c)
// remote PoC enable
if (!IS_ERR(maxim4c->pocen_gpio)) {
dev_info(dev, "remote device poc gpio off\n");
dev_info(dev, "remote device pocen gpio off\n");
gpiod_set_value_cansleep(maxim4c->pocen_gpio, 0);
}
@@ -346,8 +352,15 @@ static int maxim4c_runtime_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
int ret = 0;
return maxim4c_remote_device_power_on(maxim4c);
#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);
return ret;
}
static int maxim4c_runtime_suspend(struct device *dev)
@@ -355,8 +368,15 @@ static int maxim4c_runtime_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
int ret = 0;
return maxim4c_remote_device_power_off(maxim4c);
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 */
return ret;
}
static const struct dev_pm_ops maxim4c_pm_ops = {
@@ -378,22 +398,26 @@ static int maxim4c_extra_init_seq_parse(maxim4c_t *maxim4c, struct device_node *
struct maxim4c_i2c_init_seq *init_seq = NULL;
init_seq_node = of_get_child_by_name(node, "extra-init-sequence");
if (!IS_ERR_OR_NULL(init_seq_node)) {
if (!of_device_is_available(init_seq_node)) {
dev_info(dev, "%pOF is disabled\n", init_seq_node);
if (IS_ERR_OR_NULL(init_seq_node)) {
dev_dbg(dev, "%pOF no child node extra-init-sequence\n", node);
return 0;
}
return 0;
}
dev_info(dev, "load extra-init-sequence\n");
init_seq = &maxim4c->extra_init_seq;
maxim4c_i2c_load_init_seq(dev,
init_seq_node, init_seq);
if (!of_device_is_available(init_seq_node)) {
dev_dbg(dev, "%pOF is disabled\n", init_seq_node);
of_node_put(init_seq_node);
return 0;
}
dev_info(dev, "load extra-init-sequence\n");
init_seq = &maxim4c->extra_init_seq;
maxim4c_i2c_load_init_seq(dev,
init_seq_node, init_seq);
of_node_put(init_seq_node);
return 0;
}
@@ -404,8 +428,12 @@ static int maxim4c_module_parse_dt(maxim4c_t *maxim4c)
// maxim serdes local
node = of_get_child_by_name(dev->of_node, "serdes-local-device");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: serdes-local-device\n",
dev->of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@@ -492,36 +520,51 @@ static int maxim4c_module_hw_postinit(maxim4c_t *maxim4c)
return ret;
}
static int maxim4c_module_hw_init(maxim4c_t *maxim4c)
int maxim4c_module_hw_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret = 0;
ret = maxim4c_module_hw_previnit(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw prev init error\n", __func__);
return ret;
}
ret = maxim4c_link_hw_init(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw link init error\n", __func__);
return ret;
}
ret = maxim4c_video_pipe_hw_init(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw pipe init error\n", __func__);
return ret;
}
ret = maxim4c_mipi_txphy_hw_init(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw txphy init error\n", __func__);
return ret;
}
ret = maxim4c_run_extra_init_seq(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: run extra init seq error\n", __func__);
return ret;
}
ret = maxim4c_module_hw_postinit(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw post init error\n", __func__);
return ret;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_module_hw_init);
static int maxim4c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -529,32 +572,30 @@ static int maxim4c_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
maxim4c_t *maxim4c = NULL;
const u32 *chip_id = NULL;
u32 chip_id;
int ret = 0;
dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff);
chip_id = of_device_get_match_data(dev);
if (chip_id == NULL) {
dev_err(dev, "maxim4c driver get match data error\n");
return -EINVAL;
}
if (*chip_id == MAX96712_CHIP_ID) {
dev_info(dev, "maxim4c driver for max96712");
} else if (*chip_id == MAX96722_CHIP_ID) {
dev_info(dev, "maxim4c driver for max96722");
chip_id = (uintptr_t)of_device_get_match_data(dev);
if (chip_id == MAX96712_CHIP_ID) {
dev_info(dev, "maxim4c driver for max96712\n");
} else if (chip_id == MAX96722_CHIP_ID) {
dev_info(dev, "maxim4c driver for max96722\n");
} else {
dev_err(dev, "maxim4c driver unknown chip");
dev_err(dev, "maxim4c driver unknown chip\n");
return -EINVAL;
}
maxim4c = devm_kzalloc(dev, sizeof(*maxim4c), GFP_KERNEL);
if (!maxim4c)
if (!maxim4c) {
dev_err(dev, "maxim4c probe no memory error\n");
return -ENOMEM;
}
maxim4c->client = client;
maxim4c->chipid = *chip_id;
maxim4c->chipid = chip_id;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&maxim4c->module_index);
@@ -569,9 +610,9 @@ static int maxim4c_probe(struct i2c_client *client,
return -EINVAL;
}
maxim4c->power_gpio = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(maxim4c->power_gpio))
dev_warn(dev, "Failed to get power-gpios, maybe no use\n");
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");
maxim4c->pocen_gpio = devm_gpiod_get(dev, "pocen", GPIOD_OUT_LOW);
if (IS_ERR(maxim4c->pocen_gpio))
@@ -594,13 +635,21 @@ static int maxim4c_probe(struct i2c_client *client,
// 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;
}
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_data_init(maxim4c);
if (ret)
goto err_power_off;
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_init(maxim4c);
#if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0)
ret = maxim4c_pattern_hw_init(maxim4c);
if (ret)
goto err_power_off;
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
@@ -612,9 +661,11 @@ static int maxim4c_probe(struct i2c_client *client,
maxim4c_module_data_init(maxim4c);
maxim4c_module_parse_dt(maxim4c);
#if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0)
ret = maxim4c_module_hw_init(maxim4c);
if (ret)
goto err_subdev_deinit;
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
ret = maxim4c_remote_mfd_add_devices(maxim4c);
if (ret)
@@ -657,28 +708,17 @@ static int maxim4c_remove(struct i2c_client *client)
return 0;
}
#if IS_ENABLED(CONFIG_OF)
static const u32 max96712_chip_id = MAX96712_CHIP_ID;
static const u32 max96722_chip_id = MAX96722_CHIP_ID;
static const struct of_device_id maxim4c_of_match[] = {
{
.compatible = MAXIM4C_MAX96712_COMPAT,
.data = &max96712_chip_id,
.compatible = "maxim4c,max96712",
.data = (const void *)MAX96712_CHIP_ID
}, {
.compatible = MAXIM4C_MAX96722_COMPAT,
.data = &max96722_chip_id,
.compatible = "maxim4c,max96722",
.data = (const void *)MAX96722_CHIP_ID
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, maxim4c_of_match);
#endif
static const struct i2c_device_id maxim4c_match_id[] = {
{ MAXIM4C_MAX96712_COMPAT, 0 },
{ MAXIM4C_MAX96722_COMPAT, 0 },
{},
};
static struct i2c_driver maxim4c_i2c_driver = {
.driver = {
@@ -688,11 +728,10 @@ static struct i2c_driver maxim4c_i2c_driver = {
},
.probe = &maxim4c_probe,
.remove = &maxim4c_remove,
.id_table = maxim4c_match_id,
};
module_i2c_driver(maxim4c_i2c_driver);
MODULE_AUTHOR("Cai wenzhong <cwz@rock-chips.com>");
MODULE_DESCRIPTION("Maxim qual gmsl deserializer driver");
MODULE_AUTHOR("Cai Wenzhong <cwz@rock-chips.com>");
MODULE_DESCRIPTION("Maxim quad gmsl deserializer driver");
MODULE_LICENSE("GPL");

View File

@@ -9,6 +9,7 @@
#include <linux/workqueue.h>
#include <linux/rk-camera-module.h>
#include <linux/mfd/core.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
@@ -55,7 +56,7 @@ struct maxim4c_mode {
typedef struct maxim4c {
struct i2c_client *client;
struct clk *xvclk;
struct gpio_desc *power_gpio;
struct gpio_desc *pwdn_gpio;
struct gpio_desc *pocen_gpio;
struct gpio_desc *lock_gpio;
@@ -101,6 +102,7 @@ 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];
} maxim4c_t;

View File

@@ -88,7 +88,7 @@ int maxim4c_i2c_read_reg(struct i2c_client *client,
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs)) {
dev_err(&client->dev,
"%s: reading register 0x%x from 0x%x failed\n",
"%s: reading register 0x%04x from 0x%02x failed\n",
__func__, reg_addr, client->addr);
return -EIO;
}

View File

@@ -107,16 +107,16 @@ static int maxim4c_link_run_init_seq(maxim4c_t *maxim4c)
maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link;
struct maxim4c_link_cfg *link_cfg = NULL;
struct maxim4c_i2c_init_seq *init_seq = NULL;
int i = 0;
int link_idx = 0;
int ret = 0;
// link init sequence
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
link_cfg = &gmsl_link->link_cfg[i];
for (link_idx = 0; link_idx < MAXIM4C_LINK_ID_MAX; link_idx++) {
link_cfg = &gmsl_link->link_cfg[link_idx];
init_seq = &link_cfg->link_init_seq;
ret = maxim4c_i2c_run_init_seq(client, init_seq);
if (ret) {
dev_err(dev, "link id = %d init sequence error\n", i);
dev_err(dev, "link id = %d init sequence error\n", link_idx);
return ret;
}
}
@@ -386,6 +386,11 @@ int maxim4c_link_wait_linklock(struct maxim4c *maxim4c, u8 link_mask)
msleep(time_ms);
for (loop_idx = 0; loop_idx < 20; loop_idx++) {
if (loop_idx != 0) {
msleep(10);
time_ms += 10;
}
for (link_idx = 0; link_idx < MAXIM4C_LINK_ID_MAX; link_idx++) {
link_bit_mask = BIT(link_idx);
@@ -405,9 +410,6 @@ int maxim4c_link_wait_linklock(struct maxim4c *maxim4c, u8 link_mask)
maxim4c->link_lock_state = lock_state;
return 0;
}
msleep(10);
time_ms += 10;
}
if ((lock_state & link_mask) != 0) {
@@ -554,9 +556,7 @@ static int maxim4c_gmsl_link_config_parse_dt(struct device *dev,
struct device_node *init_seq_node = NULL;
struct maxim4c_i2c_init_seq *init_seq = NULL;
struct maxim4c_link_cfg *link_cfg = NULL;
struct maxim4c_remote_info *remote_info;
const char *link_cfg_name = "gmsl-link-config";
const char *prop_str = NULL;
u32 value = 0;
u32 sub_idx = 0, link_id = 0;
int ret = 0;
@@ -568,7 +568,8 @@ static int maxim4c_gmsl_link_config_parse_dt(struct device *dev,
link_cfg_name,
strlen(link_cfg_name))) {
if (sub_idx >= MAXIM4C_LINK_ID_MAX) {
dev_err(dev, "Too many matching %s node\n", link_cfg_name);
dev_err(dev, "%pOF: Too many matching %s node\n",
parent_node, link_cfg_name);
of_node_put(node);
break;
@@ -622,20 +623,6 @@ static int maxim4c_gmsl_link_config_parse_dt(struct device *dev,
link_cfg->link_rx_rate = value;
}
/* remote info */
remote_info = &link_cfg->remote_info;
ret = of_property_read_string(node, "remote-name", &prop_str);
if (ret == 0) {
dev_info(dev, "remote-name property: %s", prop_str);
remote_info->remote_name = prop_str;
}
ret = of_property_read_string(node, "remote-compatible", &prop_str);
if (ret == 0) {
dev_info(dev, "remote-compatible property: %s", prop_str);
remote_info->remote_compatible = prop_str;
}
/* link init sequence */
init_seq_node = of_get_child_by_name(node, "link-init-sequence");
if (!IS_ERR_OR_NULL(init_seq_node)) {
@@ -666,8 +653,11 @@ int maxim4c_link_parse_dt(maxim4c_t *maxim4c, struct device_node *of_node)
dev_info(dev, "=== maxim4c link parse dt ===\n");
node = of_get_child_by_name(of_node, "gmsl-links");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: gmsl-links\n",
of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@@ -699,29 +689,42 @@ EXPORT_SYMBOL(maxim4c_link_parse_dt);
int maxim4c_link_hw_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link;
int ret = 0;
// All links disable at beginning.
ret = maxim4c_link_status_init(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: link status error\n", __func__);
return ret;
}
if (gmsl_link->link_vdd_ldo1_en)
ret |= maxim4c_link_enable_vdd_ldo1(maxim4c);
if (gmsl_link->link_vdd_ldo2_en)
ret |= maxim4c_link_enable_vdd_ldo2(maxim4c);
if (ret) {
dev_err(dev, "%s: link vdd ldo enable error\n", __func__);
return ret;
}
// Link Rate Setting
ret |= maxim4c_link_set_rate(maxim4c);
if (ret)
ret = maxim4c_link_set_rate(maxim4c);
if (ret) {
dev_err(dev, "%s: link set rate error\n", __func__);
return ret;
}
// link init sequence
ret = maxim4c_link_run_init_seq(maxim4c);
if (ret) {
dev_err(dev, "%s: link run init seq error\n", __func__);
return ret;
}
return ret;
return 0;
}
EXPORT_SYMBOL(maxim4c_link_hw_init);
@@ -745,8 +748,6 @@ 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_info.remote_name = NULL;
link_cfg->remote_info.remote_compatible = NULL;
link_cfg->link_init_seq.reg_init_seq = NULL;
}
}

View File

@@ -63,18 +63,12 @@ enum maxim4c_link_tx_rate {
MAXIM4C_LINK_TX_RATE_187_5MPS = 0,
};
struct maxim4c_remote_info {
const char *remote_name;
const char *remote_compatible;
};
struct maxim4c_link_cfg {
u8 link_enable;
u8 link_type;
u8 link_rx_rate;
u8 link_tx_rate;
struct maxim4c_remote_info remote_info;
struct maxim4c_i2c_init_seq link_init_seq;
};

View File

@@ -259,7 +259,8 @@ static int maxim4c_mipi_txphy_config_parse_dt(struct device *dev,
txphy_cfg_name,
strlen(txphy_cfg_name))) {
if (sub_idx >= MAXIM4C_TXPHY_ID_MAX) {
dev_err(dev, "Too many matching %s node\n", txphy_cfg_name);
dev_err(dev, "%pOF: Too many matching %s node\n",
parent_node, txphy_cfg_name);
of_node_put(node);
break;
@@ -355,8 +356,11 @@ int maxim4c_mipi_txphy_parse_dt(maxim4c_t *maxim4c, struct device_node *of_node)
dev_info(dev, "=== maxim4c mipi txphy parse dt ===\n");
node = of_get_child_by_name(of_node, "mipi-txphys");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: mipi-txphys\n",
of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@@ -404,6 +408,7 @@ EXPORT_SYMBOL(maxim4c_mipi_txphy_parse_dt);
int maxim4c_mipi_txphy_hw_init(maxim4c_t *maxim4c)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
maxim4c_mipi_txphy_t *mipi_txphy = &maxim4c->mipi_txphy;
struct maxim4c_txphy_cfg *phy_cfg = NULL;
u8 mode = 0;
@@ -497,7 +502,12 @@ int maxim4c_mipi_txphy_hw_init(maxim4c_t *maxim4c)
// mipi txphy auto init deskew
ret |= maxim4c_txphy_auto_init_deskew(maxim4c);
return ret;
if (ret) {
dev_err(dev, "%s: txphy hw init error\n", __func__);
return ret;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_mipi_txphy_hw_init);

View File

@@ -91,6 +91,13 @@ static int maxim4c_pattern_previnit(maxim4c_t *maxim4c)
if (ret)
return ret;
// video pipe disable.
ret = maxim4c_i2c_write_byte(client,
0x00F4, MAXIM4C_I2C_REG_ADDR_16BITS,
0x00);
if (ret)
return ret;
// MIPI CSI output disable.
ret = maxim4c_i2c_write_byte(client,
0x040B, MAXIM4C_I2C_REG_ADDR_16BITS,
@@ -108,7 +115,7 @@ static int maxim4c_pattern_previnit(maxim4c_t *maxim4c)
return 0;
}
static int maxim4c_pattern_hw_init(maxim4c_t *maxim4c)
static int maxim4c_pattern_config(maxim4c_t *maxim4c)
{
const u32 h_active = PATTERN_WIDTH;
const u32 h_fp = 88;
@@ -249,7 +256,25 @@ static int maxim4c_pattern_hw_init(maxim4c_t *maxim4c)
return ret;
}
int maxim4c_pattern_init(maxim4c_t *maxim4c)
int maxim4c_pattern_support_mode_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
struct maxim4c_mode *supported_mode = NULL;
dev_info(dev, "=== maxim4c pattern support mode init ===\n");
maxim4c->cfg_modes_num = 1;
maxim4c->cur_mode = &maxim4c->supported_mode;
supported_mode = &maxim4c->supported_mode;
// init using def mode
memcpy(supported_mode, &maxim4c_pattern_mode, sizeof(struct maxim4c_mode));
return 0;
}
EXPORT_SYMBOL(maxim4c_pattern_support_mode_init);
int maxim4c_pattern_data_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
struct device_node *node = NULL;
@@ -259,8 +284,11 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
// maxim serdes local
node = of_get_child_by_name(dev->of_node, "serdes-local-device");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: serdes-local-device\n",
dev->of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@@ -273,23 +301,10 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
/* mipi txphy parse dt */
ret = maxim4c_mipi_txphy_parse_dt(maxim4c, node);
if (ret)
if (ret) {
dev_err(dev, "%s: txphy parse dt error\n", __func__);
return ret;
ret = maxim4c_pattern_previnit(maxim4c);
if (ret)
return ret;
ret = maxim4c_mipi_txphy_hw_init(maxim4c);
if (ret)
return ret;
maxim4c->cfg_modes_num = 1;
maxim4c->cur_mode = &maxim4c->supported_mode;
supported_mode = &maxim4c->supported_mode;
// init using def mode
memcpy(supported_mode, &maxim4c_pattern_mode, sizeof(struct maxim4c_mode));
}
// pattern generator and mode init
pattern = &maxim4c->pattern;
@@ -297,6 +312,7 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
pattern->pattern_mode = PATTERN_CHECKERBOARD;
pattern->pattern_pclk = PATTERN_PCLK_75M;
supported_mode = &maxim4c->supported_mode;
switch (pattern->pattern_pclk) {
case PATTERN_PCLK_25M:
supported_mode->max_fps.denominator = 100000;
@@ -307,13 +323,13 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
case PATTERN_PCLK_150M:
supported_mode->max_fps.denominator = 600000;
if (supported_mode->link_freq_idx < 12)
dev_info(dev, "link_freq_idx = %d is too low\n",
dev_warn(dev, "link_freq_idx = %d is too low\n",
supported_mode->link_freq_idx);
break;
case PATTERN_PCLK_375M:
supported_mode->max_fps.denominator = 1500000;
if (supported_mode->link_freq_idx < 22)
dev_info(dev, "link_freq_idx = %d is too low\n",
dev_warn(dev, "link_freq_idx = %d is too low\n",
supported_mode->link_freq_idx);
break;
}
@@ -321,8 +337,33 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
dev_info(dev, "video pattern: generator = %d, mode = %d, pclk = %d\n",
pattern->pattern_generator, pattern->pattern_mode, pattern->pattern_pclk);
ret = maxim4c_pattern_hw_init(maxim4c);
return ret;
return 0;
}
EXPORT_SYMBOL(maxim4c_pattern_init);
EXPORT_SYMBOL(maxim4c_pattern_data_init);
int maxim4c_pattern_hw_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret = 0;
ret = maxim4c_pattern_previnit(maxim4c);
if (ret) {
dev_err(dev, "%s: pattern previnit error\n", __func__);
return ret;
}
ret = maxim4c_mipi_txphy_hw_init(maxim4c);
if (ret) {
dev_err(dev, "%s: txphy hw init error\n", __func__);
return ret;
}
ret = maxim4c_pattern_config(maxim4c);
if (ret) {
dev_err(dev, "%s: pattern config error\n", __func__);
return ret;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_pattern_hw_init);

View File

@@ -8,48 +8,129 @@
*
*/
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/mfd/core.h>
#include "maxim4c_api.h"
static struct mfd_cell maxim4c_remote_devs[MAXIM4C_LINK_ID_MAX];
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 maxim4c_link_cfg *link_cfg = NULL;
struct mfd_cell *remote_mfd_dev = NULL;
const char *remote_name = NULL, *remote_compatible = NULL;
int link_idx = 0, nr_mfd_cell = 0;
int ret = 0;
remote_mfd_dev = maxim4c_remote_devs;
remote_mfd_dev = maxim4c->remote_mfd_devs;
nr_mfd_cell = 0;
for (link_idx = 0; link_idx < MAXIM4C_LINK_ID_MAX; link_idx++) {
link_cfg = &gmsl_link->link_cfg[link_idx];
if (link_cfg->link_enable == 0)
continue;
remote_mfd_dev->name = NULL;
remote_mfd_dev->of_compatible = NULL;
remote_name = link_cfg->remote_info.remote_name;
remote_compatible = link_cfg->remote_info.remote_compatible;
if (remote_compatible == NULL) {
dev_err(dev, "%s: link id = %d, remote compatible = NULL",
__func__, link_idx);
if (gmsl_link->link_cfg[link_idx].link_enable == 0) {
dev_dbg(dev, "%s: link id = %d is disabled\n",
__func__, link_idx);
continue;
}
if (remote_name == NULL) {
dev_err(dev, "%s: link id = %d, remote name = NULL",
__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++;
}
remote_mfd_dev->name = remote_name;
remote_mfd_dev->of_compatible = remote_compatible;
remote_mfd_dev++;
nr_mfd_cell++;
}
dev_info(dev, "Total number of remote devices is %d", nr_mfd_cell);
return nr_mfd_cell;
}
@@ -58,19 +139,21 @@ 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__);
__func__);
return -EINVAL;
}
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
maxim4c_remote_devs, nr_mfd_cell,
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);
__func__, ret);
return ret;
}
@@ -87,14 +170,14 @@ int maxim4c_remote_devices_init(maxim4c_t *maxim4c, u8 link_init_mask)
dev_dbg(dev, "%s: link init mask = 0x%02x\n", __func__, link_init_mask);
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
link_enable = maxim4c->gmsl_link.link_cfg[i].link_enable;
if (link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
if ((link_init_mask & BIT(i)) == 0) {
dev_dbg(dev, "link id = %d init mask is disabled\n", i);
continue;
}
if ((link_init_mask & BIT(i)) == 0) {
dev_info(dev, "link id = %d init mask is disabled\n", i);
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;
}
@@ -143,14 +226,14 @@ int maxim4c_remote_devices_deinit(maxim4c_t *maxim4c, u8 link_init_mask)
dev_dbg(dev, "%s: link init mask = 0x%02x\n", __func__, link_init_mask);
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
link_enable = maxim4c->gmsl_link.link_cfg[i].link_enable;
if (link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
if ((link_init_mask & BIT(i)) == 0) {
dev_dbg(dev, "link id = %d init mask is disabled\n", i);
continue;
}
if ((link_init_mask & BIT(i)) == 0) {
dev_info(dev, "link id = %d init mask is disabled\n", i);
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;
}
@@ -196,54 +279,156 @@ int maxim4c_remote_load_init_seq(maxim4c_remote_t *remote_device)
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);
} else {
ret = 0;
dev_info(dev, "no node remote-init-sequence\n");
return ret;
}
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__);
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) {
if (maxim4c->remote_device[remote_id] == NULL) {
remote_device->remote_enable = 1;
maxim4c->remote_device[remote_id] = remote_device;
dev_dbg(dev, "%s: remote_id = %d is success\n",
__func__, remote_id);
return 0;
} else {
dev_err(dev, "%s: remote_id = %d is conflict\n",
__func__, remote_id);
return -EINVAL;
}
} else {
if (remote_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(dev, "%s: remote_id = %d is error\n",
__func__, remote_id);
__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

@@ -95,6 +95,11 @@ 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
maxim4c->cfg_modes_num = 1;
maxim4c->cur_mode = &maxim4c->supported_mode;
mode = &maxim4c->supported_mode;
@@ -311,14 +316,12 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
break;
case RKMODULE_SET_CSI_DPHY_PARAM:
dphy_param = (struct rkmodule_csi_dphy_param *)arg;
if (dphy_param->vendor == rk3588_dcphy_param.vendor)
rk3588_dcphy_param = *dphy_param;
rk3588_dcphy_param = *dphy_param;
dev_dbg(&maxim4c->client->dev, "set dcphy param\n");
break;
case RKMODULE_GET_CSI_DPHY_PARAM:
dphy_param = (struct rkmodule_csi_dphy_param *)arg;
if (dphy_param->vendor == rk3588_dcphy_param.vendor)
*dphy_param = rk3588_dcphy_param;
*dphy_param = rk3588_dcphy_param;
dev_dbg(&maxim4c->client->dev, "get dcphy param\n");
break;
default:
@@ -430,6 +433,22 @@ static int __maxim4c_start_stream(struct maxim4c *maxim4c)
u8 link_mask = 0, link_freq_idx = 0;
u8 video_pipe_mask = 0;
#if MAXIM4C_LOCAL_DES_ON_OFF_EN
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_hw_init(maxim4c);
if (ret) {
dev_err(dev, "test pattern hw init error\n");
return ret;
}
#else
ret = maxim4c_module_hw_init(maxim4c);
if (ret) {
dev_err(dev, "maxim4c module hw init error\n");
return ret;
}
#endif /* MAXIM4C_TEST_PATTERN */
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
link_mask = maxim4c->gmsl_link.link_enable_mask;
video_pipe_mask = maxim4c->video_pipe.pipe_enable_mask;

View File

@@ -100,8 +100,8 @@ static int maxim4c_video_pipe_config_parse_dt(struct device *dev,
pipe_cfg_name,
strlen(pipe_cfg_name))) {
if (sub_idx >= MAXIM4C_PIPE_O_ID_MAX) {
dev_err(dev, "Too many matching %s node\n",
pipe_cfg_name);
dev_err(dev, "%pOF: Too many matching %s node\n",
parent_node, pipe_cfg_name);
of_node_put(node);
break;
@@ -205,8 +205,11 @@ int maxim4c_video_pipe_parse_dt(maxim4c_t *maxim4c, struct device_node *of_node)
dev_info(dev, "=== maxim4c video pipe parse dt ===\n");
node = of_get_child_by_name(of_node, "video-pipes");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: video-pipes\n",
of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@@ -325,21 +328,28 @@ EXPORT_SYMBOL(maxim4c_video_pipe_data_init);
int maxim4c_video_pipe_hw_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
u8 pipe_enable_mask = 0;
int ret = 0;
ret = maxim4c_video_pipe_select(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: video pipe select error\n", __func__);
return ret;
}
pipe_enable_mask = maxim4c->video_pipe.pipe_enable_mask;
ret = maxim4c_video_pipe_mask_enable(maxim4c, pipe_enable_mask, true);
if (ret)
if (ret) {
dev_err(dev, "%s: video pipe mask enable error\n", __func__);
return ret;
}
ret = maxim4c_video_pipe_run_init_seq(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: video pipe run init seq error\n", __func__);
return ret;
}
return 0;
}

View File

@@ -20,25 +20,6 @@
#define MAX9295_CHIP_ID 0x91
#define MAX9295_REG_CHIP_ID 0x0D
static int max9295_i2c_addr_select(maxim4c_remote_t *max9295, u32 i2c_id)
{
struct device *dev = max9295->dev;
struct i2c_client *client = max9295->client;
if (i2c_id == MAXIM4C_I2C_SER_DEF) {
client->addr = max9295->ser_i2c_addr_def;
dev_info(dev, "select default i2c addr = 0x%x\n", client->addr);
} else if (i2c_id == MAXIM4C_I2C_SER_MAP) {
client->addr = max9295->ser_i2c_addr_map;
dev_info(dev, "select mapping i2c addr = 0x%x\n", client->addr);
} else {
dev_err(dev, "i2c select id = %d error\n", i2c_id);
return -EINVAL;
}
return 0;
}
static int max9295_i2c_addr_remap(maxim4c_remote_t *max9295)
{
struct device *dev = max9295->dev;
@@ -49,7 +30,7 @@ static int max9295_i2c_addr_remap(maxim4c_remote_t *max9295)
if (max9295->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
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,
@@ -60,7 +41,7 @@ static int max9295_i2c_addr_remap(maxim4c_remote_t *max9295)
return ret;
}
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
}
if (max9295->cam_i2c_addr_map) {
@@ -98,7 +79,7 @@ static int max9295_i2c_addr_def(maxim4c_remote_t *max9295)
if (max9295->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
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,
@@ -109,7 +90,7 @@ static int max9295_i2c_addr_def(maxim4c_remote_t *max9295)
return ret;
}
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
}
return 0;
@@ -128,13 +109,13 @@ static int max9295_check_chipid(maxim4c_remote_t *max9295)
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
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);
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
@@ -143,13 +124,13 @@ static int max9295_check_chipid(maxim4c_remote_t *max9295)
}
if (chip_id != MAX9295_CHIP_ID) {
dev_err(dev, "Unexpected MAX9295 chip id(%02x)\n", chip_id);
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX9295 chipid: 0x%02x\n", chip_id);
dev_info(dev, "Detected MAX9295 chip id: 0x%02x\n", chip_id);
return ret;
return 0;
}
static int max9295_soft_power_down(maxim4c_remote_t *max9295)
@@ -175,7 +156,7 @@ static int max9295_module_init(maxim4c_remote_t *max9295)
struct i2c_client *client = max9295->client;
int ret = 0;
ret = max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
ret = maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
@@ -263,47 +244,30 @@ static int max9295_parse_dt(maxim4c_remote_t *max9295)
return 0;
}
static int max9295_i2c_client_init(maxim4c_remote_t *max9295,
struct i2c_client *local_client)
{
struct device *dev = max9295->dev;
struct i2c_client *remote_client = NULL;
u16 remote_client_addr = 0;
if (max9295->ser_i2c_addr_map)
remote_client_addr = max9295->ser_i2c_addr_map;
else
remote_client_addr = max9295->ser_i2c_addr_def;
remote_client = devm_i2c_new_dummy_device(&local_client->dev,
local_client->adapter, remote_client_addr);
if (IS_ERR(remote_client)) {
dev_err(dev, "failed to alloc i2c client.\n");
return -PTR_ERR(remote_client);
}
remote_client->addr = max9295->ser_i2c_addr_def;
max9295->client = remote_client;
i2c_set_clientdata(remote_client, max9295);
dev_info(dev, "remote i2c client init, i2c_addr = 0x%x\n",
remote_client_addr);
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)
if (!max9295) {
dev_err(&pdev->dev, "max9295 probe no memory error\n");
return -ENOMEM;
}
max9295->dev = &pdev->dev;
max9295->remote_ops = &max9295_ops;
@@ -312,11 +276,22 @@ static int max9295_probe(struct platform_device *pdev)
max9295_parse_dt(max9295);
max9295_i2c_client_init(max9295, client);
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)
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max9295);
@@ -329,10 +304,21 @@ static int max9295_remove(struct platform_device *pdev)
}
static const struct of_device_id max9295_of_table[] = {
{ .compatible = "maxim4c,max9295", },
{
.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 = {

View File

@@ -34,43 +34,28 @@ static int __maybe_unused max96715_link_mode_select(maxim4c_remote_t *max96715,
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)
if (mode == LINK_MODE_CONFIG) {
reg_value = BIT(6);
else
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);
mdelay(5);
msleep(delay_ms);
return ret;
}
static int max96715_i2c_addr_select(maxim4c_remote_t *max96715, u32 i2c_id)
{
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
if (i2c_id == MAXIM4C_I2C_SER_DEF) {
client->addr = max96715->ser_i2c_addr_def;
dev_info(dev, "select default i2c addr = 0x%x\n", client->addr);
} else if (i2c_id == MAXIM4C_I2C_SER_MAP) {
client->addr = max96715->ser_i2c_addr_map;
dev_info(dev, "select mapping i2c addr = 0x%x\n", client->addr);
} else {
dev_err(dev, "i2c select id = %d error\n", i2c_id);
return -EINVAL;
}
return 0;
}
static int max96715_i2c_addr_remap(maxim4c_remote_t *max96715)
{
struct device *dev = max96715->dev;
@@ -81,7 +66,7 @@ static int max96715_i2c_addr_remap(maxim4c_remote_t *max96715)
if (max96715->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
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,
@@ -92,7 +77,7 @@ static int max96715_i2c_addr_remap(maxim4c_remote_t *max96715)
return ret;
}
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
}
if (max96715->cam_i2c_addr_map) {
@@ -130,7 +115,7 @@ static int max96715_i2c_addr_def(maxim4c_remote_t *max96715)
if (max96715->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
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,
@@ -141,7 +126,7 @@ static int max96715_i2c_addr_def(maxim4c_remote_t *max96715)
return ret;
}
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
}
return 0;
@@ -160,13 +145,13 @@ static int max96715_check_chipid(maxim4c_remote_t *max96715)
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
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);
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
@@ -175,13 +160,13 @@ static int max96715_check_chipid(maxim4c_remote_t *max96715)
}
if (chip_id != MAX96715_CHIP_ID) {
dev_err(dev, "Unexpected MAX96715 chip id(%02x)\n", chip_id);
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX96715 chipid: 0x%02x\n", chip_id);
dev_info(dev, "Detected MAX96715 chip id: 0x%02x\n", chip_id);
return ret;
return 0;
}
static int max96715_soft_power_down(maxim4c_remote_t *max96715)
@@ -208,7 +193,7 @@ static int max96715_module_init(maxim4c_remote_t *max96715)
struct maxim4c *maxim4c = max96715->local;
int ret = 0;
ret = max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
ret = maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
@@ -322,47 +307,30 @@ static int max96715_parse_dt(maxim4c_remote_t *max96715)
return 0;
}
static int max96715_i2c_client_init(maxim4c_remote_t *max96715,
struct i2c_client *local_client)
{
struct device *dev = max96715->dev;
struct i2c_client *remote_client = NULL;
u16 remote_client_addr = 0;
if (max96715->ser_i2c_addr_map)
remote_client_addr = max96715->ser_i2c_addr_map;
else
remote_client_addr = max96715->ser_i2c_addr_def;
remote_client = devm_i2c_new_dummy_device(&local_client->dev,
local_client->adapter, remote_client_addr);
if (IS_ERR(remote_client)) {
dev_err(dev, "failed to alloc i2c client.\n");
return -PTR_ERR(remote_client);
}
remote_client->addr = max96715->ser_i2c_addr_def;
max96715->client = remote_client;
i2c_set_clientdata(remote_client, max96715);
dev_info(dev, "remote i2c client init, i2c_addr = 0x%x\n",
remote_client_addr);
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)
if (!max96715) {
dev_err(&pdev->dev, "max96715 probe no memory error\n");
return -ENOMEM;
}
max96715->dev = &pdev->dev;
max96715->remote_ops = &max96715_ops;
@@ -371,11 +339,22 @@ static int max96715_probe(struct platform_device *pdev)
max96715_parse_dt(max96715);
max96715_i2c_client_init(max96715, client);
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)
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max96715);
@@ -388,10 +367,21 @@ static int max96715_remove(struct platform_device *pdev)
}
static const struct of_device_id max96715_of_table[] = {
{ .compatible = "maxim4c,max96715", },
{
.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 = {

View File

@@ -20,25 +20,6 @@
#define MAX96717_CHIP_ID 0xBF
#define MAX96717_REG_CHIP_ID 0x0D
static int max96717_i2c_addr_select(maxim4c_remote_t *max96717, u32 i2c_id)
{
struct device *dev = max96717->dev;
struct i2c_client *client = max96717->client;
if (i2c_id == MAXIM4C_I2C_SER_DEF) {
client->addr = max96717->ser_i2c_addr_def;
dev_info(dev, "select default i2c addr = 0x%x\n", client->addr);
} else if (i2c_id == MAXIM4C_I2C_SER_MAP) {
client->addr = max96717->ser_i2c_addr_map;
dev_info(dev, "select mapping i2c addr = 0x%x\n", client->addr);
} else {
dev_err(dev, "i2c select id = %d error\n", i2c_id);
return -EINVAL;
}
return 0;
}
static int max96717_i2c_addr_remap(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
@@ -49,7 +30,7 @@ static int max96717_i2c_addr_remap(maxim4c_remote_t *max96717)
if (max96717->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
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,
@@ -60,7 +41,7 @@ static int max96717_i2c_addr_remap(maxim4c_remote_t *max96717)
return ret;
}
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
}
if (max96717->cam_i2c_addr_map) {
@@ -98,7 +79,7 @@ static int max96717_i2c_addr_def(maxim4c_remote_t *max96717)
if (max96717->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
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,
@@ -109,7 +90,7 @@ static int max96717_i2c_addr_def(maxim4c_remote_t *max96717)
return ret;
}
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
}
return 0;
@@ -128,13 +109,13 @@ static int max96717_check_chipid(maxim4c_remote_t *max96717)
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
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);
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
@@ -143,27 +124,10 @@ static int max96717_check_chipid(maxim4c_remote_t *max96717)
}
if (chip_id != MAX96717_CHIP_ID) {
dev_err(dev, "Unexpected MAX96717 chip id(%02x)\n", chip_id);
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX96717 chipid: 0x%02x\n", chip_id);
return ret;
}
static int max96717_soft_power_down(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
struct i2c_client *client = max96717->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;
}
dev_info(dev, "Detected MAX96717 chip id: 0x%02x\n", chip_id);
return 0;
}
@@ -174,7 +138,7 @@ static int max96717_module_init(maxim4c_remote_t *max96717)
struct i2c_client *client = max96717->client;
int ret = 0;
ret = max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
ret = maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
@@ -201,10 +165,7 @@ static int max96717_module_deinit(maxim4c_remote_t *max96717)
{
int ret = 0;
#if 0
ret |= max96717_i2c_addr_def(max96717);
#endif
ret |= max96717_soft_power_down(max96717);
return ret;
}
@@ -262,47 +223,30 @@ static int max96717_parse_dt(maxim4c_remote_t *max96717)
return 0;
}
static int max96717_i2c_client_init(maxim4c_remote_t *max96717,
struct i2c_client *local_client)
{
struct device *dev = max96717->dev;
struct i2c_client *remote_client = NULL;
u16 remote_client_addr = 0;
if (max96717->ser_i2c_addr_map)
remote_client_addr = max96717->ser_i2c_addr_map;
else
remote_client_addr = max96717->ser_i2c_addr_def;
remote_client = devm_i2c_new_dummy_device(&local_client->dev,
local_client->adapter, remote_client_addr);
if (IS_ERR(remote_client)) {
dev_err(dev, "failed to alloc i2c client.\n");
return -PTR_ERR(remote_client);
}
remote_client->addr = max96717->ser_i2c_addr_def;
max96717->client = remote_client;
i2c_set_clientdata(remote_client, max96717);
dev_info(dev, "remote i2c client init, i2c_addr = 0x%x\n",
remote_client_addr);
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)
if (!max96717) {
dev_err(&pdev->dev, "max96717 probe no memory error\n");
return -ENOMEM;
}
max96717->dev = &pdev->dev;
max96717->remote_ops = &max96717_ops;
@@ -311,11 +255,22 @@ static int max96717_probe(struct platform_device *pdev)
max96717_parse_dt(max96717);
max96717_i2c_client_init(max96717, client);
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)
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max96717);
@@ -328,10 +283,21 @@ static int max96717_remove(struct platform_device *pdev)
}
static const struct of_device_id max96717_of_table[] = {
{ .compatible = "maxim4c,max96717", },
{
.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 = {