From 455bfe848175dfd82501b190db9b8fae81f785b7 Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Thu, 28 Dec 2023 10:08:48 +0800 Subject: [PATCH] media: i2c: maxim: remote: serializer driver version v3.00.00 1. remote serializer support max9295/max96715/max96717 2. remote serializer provide APIs for remote camera calls Signed-off-by: Cai Wenzhong Change-Id: Ib9f5fbefdded0f40a9b06f3c490713c4f0a20dfd --- drivers/media/i2c/maxim/Kconfig | 1 + drivers/media/i2c/maxim/Makefile | 2 +- drivers/media/i2c/maxim/remote/Kconfig | 36 ++ drivers/media/i2c/maxim/remote/Makefile | 5 + drivers/media/i2c/maxim/remote/max9295.c | 558 +++++++++++++++++ drivers/media/i2c/maxim/remote/max96715.c | 559 ++++++++++++++++++ drivers/media/i2c/maxim/remote/max96717.c | 508 ++++++++++++++++ drivers/media/i2c/maxim/remote/maxim_remote.h | 313 ++++++++++ 8 files changed, 1981 insertions(+), 1 deletion(-) create mode 100644 drivers/media/i2c/maxim/remote/Kconfig create mode 100644 drivers/media/i2c/maxim/remote/Makefile create mode 100644 drivers/media/i2c/maxim/remote/max9295.c create mode 100644 drivers/media/i2c/maxim/remote/max96715.c create mode 100644 drivers/media/i2c/maxim/remote/max96717.c create mode 100644 drivers/media/i2c/maxim/remote/maxim_remote.h diff --git a/drivers/media/i2c/maxim/Kconfig b/drivers/media/i2c/maxim/Kconfig index 8fac5a7b9f4c..ac5a41680f74 100644 --- a/drivers/media/i2c/maxim/Kconfig +++ b/drivers/media/i2c/maxim/Kconfig @@ -14,3 +14,4 @@ config VIDEO_MAXIM_SERDES module will be called maxim. source "drivers/media/i2c/maxim/local/Kconfig" +source "drivers/media/i2c/maxim/remote/Kconfig" diff --git a/drivers/media/i2c/maxim/Makefile b/drivers/media/i2c/maxim/Makefile index 16c2466d7f73..ffe2bcfe1945 100644 --- a/drivers/media/i2c/maxim/Makefile +++ b/drivers/media/i2c/maxim/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_MAXIM_SERDES) += local/ +obj-$(CONFIG_VIDEO_MAXIM_SERDES) += local/ remote/ diff --git a/drivers/media/i2c/maxim/remote/Kconfig b/drivers/media/i2c/maxim/remote/Kconfig new file mode 100644 index 000000000000..6d8cb89a8dfe --- /dev/null +++ b/drivers/media/i2c/maxim/remote/Kconfig @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Maxim GMSL serializer devices +# + +menu "Maxim GMSL Remote Serializer devices support" + visible if VIDEO_MAXIM_SERDES + +config VIDEO_MAXIM_SER_MAX9295 + tristate "Maxim GMSL2 serializer max9295 support" + depends on VIDEO_MAXIM_SERDES + help + This driver supports the Maxim GMSL2 max9295 serializer. + + To compile this driver as a module, choose M here: the + module will be called max9295. + +config VIDEO_MAXIM_SER_MAX96715 + tristate "Maxim GMSL1 Serializer max96715 support" + depends on VIDEO_MAXIM_SERDES + help + This driver supports the Maxim GMSL1 max96715 serializer. + + To compile this driver as a module, choose M here: the + module will be called max96715. + +config VIDEO_MAXIM_SER_MAX96717 + tristate "Maxim GMSL2 Serializer max96717 support" + depends on VIDEO_MAXIM_SERDES + help + This driver supports the Maxim GMSL2 max96717 serializer. + + To compile this driver as a module, choose M here: the + module will be called max96717. + +endmenu diff --git a/drivers/media/i2c/maxim/remote/Makefile b/drivers/media/i2c/maxim/remote/Makefile new file mode 100644 index 000000000000..a8b550852f3a --- /dev/null +++ b/drivers/media/i2c/maxim/remote/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_VIDEO_MAXIM_SER_MAX9295) += max9295.o +obj-$(CONFIG_VIDEO_MAXIM_SER_MAX96715) += max96715.o +obj-$(CONFIG_VIDEO_MAXIM_SER_MAX96717) += max96717.o diff --git a/drivers/media/i2c/maxim/remote/max9295.c b/drivers/media/i2c/maxim/remote/max9295.c new file mode 100644 index 000000000000..f688ddbd29a3 --- /dev/null +++ b/drivers/media/i2c/maxim/remote/max9295.c @@ -0,0 +1,558 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Maxim Max9295 GMSL2/GMSL1 Serializer driver + * + * Copyright (C) 2023 Rockchip Electronics Co., Ltd. + * + * Author: Cai Wenzhong + * + */ +#include +#include +#include +#include +#include +#include + +#include "maxim_remote.h" + +#define DRIVER_VERSION KERNEL_VERSION(3, 0x00, 0x00) + +#define MAX9295_NAME "max9295" + +#define MAX9295_I2C_ADDR_DEF 0x40 + +#define MAX9295_CHIP_ID 0x91 +#define MAX9295_REG_CHIP_ID 0x0D + +/* register address: 16bit */ +#define MAX9295_I2C_REG_ADDR_16BITS 2 + +/* register value: 8bit */ +#define MAX9295_I2C_REG_VALUE_08BITS 1 + +/* Write registers up to 4 at a time */ +static int max9295_i2c_write(struct i2c_client *client, + u16 reg_addr, u16 reg_len, u32 val_len, u32 reg_val) +{ + u32 buf_i, val_i; + u8 buf[6]; + u8 *val_p; + __be32 val_be; + + dev_info(&client->dev, "i2c addr(0x%02x) write: 0x%04x (%d) = 0x%08x (%d)\n", + client->addr, reg_addr, reg_len, reg_val, val_len); + + if (val_len > 4) + return -EINVAL; + + if (reg_len == 2) { + buf[0] = reg_addr >> 8; + buf[1] = reg_addr & 0xff; + + buf_i = 2; + } else { + buf[0] = reg_addr & 0xff; + + buf_i = 1; + } + + val_be = cpu_to_be32(reg_val); + val_p = (u8 *)&val_be; + val_i = 4 - val_len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, (val_len + reg_len)) != (val_len + reg_len)) { + dev_err(&client->dev, + "%s: writing register 0x%04x from 0x%02x failed\n", + __func__, reg_addr, client->addr); + return -EIO; + } + + return 0; +} + +/* Read registers up to 4 at a time */ +static int max9295_i2c_read(struct i2c_client *client, + u16 reg_addr, u16 reg_len, u32 val_len, u32 *reg_val) +{ + struct i2c_msg msgs[2]; + u8 *data_be_p; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg_addr); + u8 *reg_be_p; + int ret; + + if (val_len > 4 || !val_len) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + reg_be_p = (u8 *)®_addr_be; + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = reg_len; + msgs[0].buf = ®_be_p[2 - reg_len]; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = val_len; + msgs[1].buf = &data_be_p[4 - val_len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + dev_err(&client->dev, + "%s: reading register 0x%04x from 0x%02x failed\n", + __func__, reg_addr, client->addr); + return -EIO; + } + + *reg_val = be32_to_cpu(data_be); + +#if 0 + dev_info(&client->dev, "i2c addr(0x%02x) read: 0x%04x (%d) = 0x%08x (%d)\n", + client->addr, reg_addr, reg_len, *reg_val, val_len); +#endif + + return 0; +} + +/* Update registers up to 4 at a time */ +static int max9295_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 = max9295_i2c_read(client, reg_addr, reg_len, val_len, &value); + if (ret) + return ret; + + value &= ~val_mask; + value |= (reg_val & val_mask); + ret = max9295_i2c_write(client, reg_addr, reg_len, val_len, value); + + return ret; +} + +static int max9295_write_reg(struct i2c_client *client, + u16 reg_addr, u8 reg_val) +{ + int ret = 0; + + ret = max9295_i2c_write(client, + reg_addr, MAX9295_I2C_REG_ADDR_16BITS, + MAX9295_I2C_REG_VALUE_08BITS, reg_val); + + return ret; +} + +static int max9295_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 = max9295_i2c_read(client, + reg_addr, MAX9295_I2C_REG_ADDR_16BITS, + MAX9295_I2C_REG_VALUE_08BITS, &value); + + *reg_val = *value_be_p; + + return ret; +} + +static int __maybe_unused max9295_update_reg(struct i2c_client *client, + u16 reg_addr, u8 val_mask, u8 reg_val) +{ + u8 value; + int ret; + + ret = max9295_read_reg(client, reg_addr, &value); + if (ret) + return ret; + + value &= ~val_mask; + value |= (reg_val & val_mask); + ret = max9295_write_reg(client, reg_addr, value); + + return ret; +} + +static int max9295_i2c_write_array(struct i2c_client *client, + const struct maxim_remote_regval *regs) +{ + u32 i = 0; + int ret = 0; + + for (i = 0; (ret == 0) && (regs[i].reg_addr != MAXIM_REMOTE_REG_NULL); i++) { + if (regs[i].val_mask != 0) + ret = max9295_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 = max9295_i2c_write(client, + regs[i].reg_addr, regs[i].reg_len, + regs[i].val_len, regs[i].reg_val); + + if (regs[i].delay != 0) + usleep_range(regs[i].delay * 1000, regs[i].delay * 1000 + 100); + } + + return ret; +} + +static int max9295_run_ser_init_seq(struct i2c_client *client, + struct maxim_remote_init_seq *init_seq) +{ + int ret = 0; + + if ((init_seq == NULL) || (init_seq->reg_init_seq == NULL)) + return 0; + + ret = max9295_i2c_write_array(client, + init_seq->reg_init_seq); + + return ret; +} + +static int max9295_load_ser_init_seq(maxim_remote_ser_t *max9295) +{ + struct device *dev = &max9295->client->dev; + struct device_node *node = NULL; + int ret = 0; + + node = of_get_child_by_name(dev->of_node, "ser-init-sequence"); + if (!IS_ERR_OR_NULL(node)) { + dev_info(dev, "load ser-init-sequence\n"); + + ret = maxim_remote_load_init_seq(dev, node, + &max9295->ser_init_seq); + + of_node_put(node); + return ret; + } + + return 0; +} + +static int max9295_i2c_addr_remap(maxim_remote_ser_t *max9295) +{ + struct i2c_client *client = max9295->client; + struct device *dev = &client->dev; + u16 i2c_8bit_addr = 0; + int ret = 0; + + // Serializer i2c address map + if (max9295->ser_i2c_addr_map != max9295->ser_i2c_addr_def) { + dev_info(dev, "Serializer i2c address remap\n"); + + maxim_remote_ser_i2c_addr_select(max9295, MAXIM_REMOTE_I2C_SER_DEF); + + i2c_8bit_addr = (max9295->ser_i2c_addr_map << 1); + ret = max9295_write_reg(client, 0x0000, i2c_8bit_addr); + if (ret) { + dev_err(dev, "ser i2c address map setting error!\n"); + return ret; + } + + maxim_remote_ser_i2c_addr_select(max9295, MAXIM_REMOTE_I2C_SER_MAP); + } + + // Camera i2c address map + if (max9295->cam_i2c_addr_map != max9295->cam_i2c_addr_def) { + dev_info(dev, "Camera i2c address remap\n"); + + i2c_8bit_addr = (max9295->cam_i2c_addr_map << 1); + ret = max9295_write_reg(client, 0x0042, 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 = max9295_write_reg(client, 0x0043, 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(maxim_remote_ser_t *max9295) +{ + struct i2c_client *client = max9295->client; + struct device *dev = &client->dev; + u16 i2c_8bit_addr = 0; + int ret = 0; + + if (max9295->ser_i2c_addr_map) { + dev_info(dev, "Serializer i2c address def\n"); + + maxim_remote_ser_i2c_addr_select(max9295, MAXIM_REMOTE_I2C_SER_MAP); + + i2c_8bit_addr = (max9295->ser_i2c_addr_def << 1); + ret = max9295_write_reg(client, 0x0000, i2c_8bit_addr); + if (ret) { + dev_err(dev, "ser i2c address def setting error!\n"); + return ret; + } + + maxim_remote_ser_i2c_addr_select(max9295, MAXIM_REMOTE_I2C_SER_DEF); + } + + return 0; +} + +static int max9295_check_chipid(maxim_remote_ser_t *max9295) +{ + struct i2c_client *client = max9295->client; + struct device *dev = &client->dev; + u8 chip_id; + int ret = 0; + + // max9295 + ret = max9295_read_reg(client, MAX9295_REG_CHIP_ID, &chip_id); + if (ret != 0) { + dev_info(dev, "Retry check chipid using map address\n"); + maxim_remote_ser_i2c_addr_select(max9295, MAXIM_REMOTE_I2C_SER_MAP); + ret = max9295_read_reg(client, MAX9295_REG_CHIP_ID, &chip_id); + if (ret != 0) { + dev_err(dev, "MAX9295 detect error, ret(%d)\n", ret); + maxim_remote_ser_i2c_addr_select(max9295, MAXIM_REMOTE_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; +} + +/* + * max9295_pclk_detect() - Detect valid pixel clock from image sensor + * + * Wait up to 500ms for a valid pixel clock. + * + * Returns 0 for success, < 0 for pixel clock not properly detected + */ +static int max9295_pclk_detect(maxim_remote_ser_t *max9295) +{ + struct i2c_client *client = max9295->client; + struct device *dev = &client->dev; + u8 vid_tx_en_mask = 0, pclk_det = 0; + unsigned int i; + int ret = 0; + + ret = max9295_read_reg(client, 0x0002, &vid_tx_en_mask); + if (ret == 0) { + vid_tx_en_mask = vid_tx_en_mask & 0xF0; + dev_info(dev, "VID_TX_EN = 0x%x\n", vid_tx_en_mask); + if (vid_tx_en_mask == 0) + dev_err(dev, "VID_TX_EN config error\n"); + } else { + dev_err(dev, "Detect PCLK error\n"); + return ret; + } + + for (i = 0; i < 500; i++) { + // VID TX: X + if (vid_tx_en_mask & BIT(4)) { + ret = max9295_read_reg(client, 0x0102, &pclk_det); + + if ((ret == 0) && (pclk_det & BIT(7))) { + dev_info(dev, "VID_TX_X detect valid PCLK (%d)\n", i); + return 0; + } + } + + // VID TX: Y + if (vid_tx_en_mask & BIT(5)) { + ret = max9295_read_reg(client, 0x010A, &pclk_det); + + if ((ret == 0) && (pclk_det & BIT(7))) { + dev_info(dev, "VID_TX_Y detect valid PCLK (%d)\n", i); + return 0; + } + } + + // VID TX: Z + if (vid_tx_en_mask & BIT(6)) { + ret = max9295_read_reg(client, 0x0112, &pclk_det); + + if ((ret == 0) && (pclk_det & BIT(7))) { + dev_info(dev, "VID_TX_Z detect valid PCLK (%d)\n", i); + return 0; + } + } + + // VID TX: U + if (vid_tx_en_mask & BIT(6)) { + ret = max9295_read_reg(client, 0x011A, &pclk_det); + + if ((ret == 0) && (pclk_det & BIT(7))) { + dev_info(dev, "VID_TX_U detect valid PCLK (%d)\n", i); + return 0; + } + } + + usleep_range(1000, 1100); + } + + dev_err(dev, "Unable to detect valid PCLK, timeout\n"); + + return -EIO; +} + +static int max9295_soft_power_down(maxim_remote_ser_t *max9295) +{ + struct i2c_client *client = max9295->client; + struct device *dev = &client->dev; + int ret = 0; + + ret = max9295_write_reg(client, 0x10, BIT(7)); + if (ret) { + dev_err(dev, "soft power down setting error!\n"); + return ret; + } + + return 0; +} + +static int max9295_module_init(maxim_remote_ser_t *max9295) +{ + struct i2c_client *client = max9295->client; + int ret = 0; + + ret = maxim_remote_ser_i2c_addr_select(max9295, MAXIM_REMOTE_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 = max9295_run_ser_init_seq(client, &max9295->ser_init_seq); + if (ret) { + dev_err(&client->dev, "run ser init sequence error\n"); + return ret; + } + + return 0; +} + +static int max9295_module_deinit(maxim_remote_ser_t *max9295) +{ + int ret = 0; + +#if 0 + ret |= max9295_i2c_addr_def(max9295); +#endif + ret |= max9295_soft_power_down(max9295); + + return ret; +} + +static struct maxim_remote_ser_ops max9295_ser_ops = { + .ser_module_init = max9295_module_init, + .ser_module_deinit = max9295_module_deinit, + .ser_pclk_detect = max9295_pclk_detect, +}; + +static int max9295_parse_dt(maxim_remote_ser_t *max9295) +{ + struct device *dev = &max9295->client->dev; + struct device_node *of_node = dev->of_node; + u32 value = 0; + int ret = 0; + + dev_info(dev, "=== max9295 parse dt ===\n"); + + 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; + } + + return 0; +} + +static int max9295_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + maxim_remote_ser_t *max9295 = NULL; + + dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff); + + max9295 = devm_kzalloc(dev, sizeof(*max9295), GFP_KERNEL); + if (!max9295) { + dev_err(dev, "max9295 probe no memory error\n"); + return -ENOMEM; + } + + max9295->client = client; + max9295->ser_i2c_addr_map = client->addr; + max9295->ser_ops = &max9295_ser_ops; + + i2c_set_clientdata(client, max9295); + + mutex_init(&max9295->mutex); + + max9295_parse_dt(max9295); + + max9295_load_ser_init_seq(max9295); + + return 0; +} + +static int max9295_remove(struct i2c_client *client) +{ + maxim_remote_ser_t *max9295 = i2c_get_clientdata(client); + + mutex_destroy(&max9295->mutex); + + return 0; +} + +static const struct of_device_id max9295_of_match[] = { + { .compatible = "maxim,ser,max9295" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, max9295_of_match); + +static struct i2c_driver max9295_i2c_driver = { + .driver = { + .name = MAX9295_NAME, + .of_match_table = of_match_ptr(max9295_of_match), + }, + .probe = &max9295_probe, + .remove = &max9295_remove, +}; + +module_i2c_driver(max9295_i2c_driver); + +MODULE_AUTHOR("Cai Wenzhong "); +MODULE_DESCRIPTION("Maxim MAX9295 Serializer Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/maxim/remote/max96715.c b/drivers/media/i2c/maxim/remote/max96715.c new file mode 100644 index 000000000000..d468d2947983 --- /dev/null +++ b/drivers/media/i2c/maxim/remote/max96715.c @@ -0,0 +1,559 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Maxim Max96715 GMSL1 Serializer driver + * + * Copyright (C) 2023 Rockchip Electronics Co., Ltd. + * + * Author: Cai Wenzhong + * + */ +#include +#include +#include +#include +#include +#include + +#include "maxim_remote.h" + +#define DRIVER_VERSION KERNEL_VERSION(3, 0x00, 0x00) + +#define MAX96715_NAME "max96715" + +#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, +}; + +/* register address: 8bit */ +#define MAX96715_I2C_REG_ADDR_08BITS 1 + +/* register value: 8bit */ +#define MAX96715_I2C_REG_VALUE_08BITS 1 + +/* Write registers up to 4 at a time */ +static int max96715_i2c_write(struct i2c_client *client, + u16 reg_addr, u16 reg_len, u32 val_len, u32 reg_val) +{ + u32 buf_i, val_i; + u8 buf[6]; + u8 *val_p; + __be32 val_be; + + dev_info(&client->dev, "i2c addr(0x%02x) write: 0x%04x (%d) = 0x%08x (%d)\n", + client->addr, reg_addr, reg_len, reg_val, val_len); + + if (val_len > 4) + return -EINVAL; + + if (reg_len == 2) { + buf[0] = reg_addr >> 8; + buf[1] = reg_addr & 0xff; + + buf_i = 2; + } else { + buf[0] = reg_addr & 0xff; + + buf_i = 1; + } + + val_be = cpu_to_be32(reg_val); + val_p = (u8 *)&val_be; + val_i = 4 - val_len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, (val_len + reg_len)) != (val_len + reg_len)) { + dev_err(&client->dev, + "%s: writing register 0x%04x from 0x%02x failed\n", + __func__, reg_addr, client->addr); + return -EIO; + } + + return 0; +} + +/* Read registers up to 4 at a time */ +static int max96715_i2c_read(struct i2c_client *client, + u16 reg_addr, u16 reg_len, u32 val_len, u32 *reg_val) +{ + struct i2c_msg msgs[2]; + u8 *data_be_p; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg_addr); + u8 *reg_be_p; + int ret; + + if (val_len > 4 || !val_len) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + reg_be_p = (u8 *)®_addr_be; + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = reg_len; + msgs[0].buf = ®_be_p[2 - reg_len]; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = val_len; + msgs[1].buf = &data_be_p[4 - val_len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + dev_err(&client->dev, + "%s: reading register 0x%04x from 0x%02x failed\n", + __func__, reg_addr, client->addr); + return -EIO; + } + + *reg_val = be32_to_cpu(data_be); + +#if 0 + dev_info(&client->dev, "i2c addr(0x%02x) read: 0x%04x (%d) = 0x%08x (%d)\n", + client->addr, reg_addr, reg_len, *reg_val, val_len); +#endif + + return 0; +} + +/* Update registers up to 4 at a time */ +static int max96715_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 = max96715_i2c_read(client, reg_addr, reg_len, val_len, &value); + if (ret) + return ret; + + value &= ~val_mask; + value |= (reg_val & val_mask); + ret = max96715_i2c_write(client, reg_addr, reg_len, val_len, value); + + return ret; +} + +static int max96715_write_reg(struct i2c_client *client, + u16 reg_addr, u8 reg_val) +{ + int ret = 0; + + ret = max96715_i2c_write(client, + reg_addr, MAX96715_I2C_REG_ADDR_08BITS, + MAX96715_I2C_REG_VALUE_08BITS, reg_val); + + return ret; +} + +static int max96715_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 = max96715_i2c_read(client, + reg_addr, MAX96715_I2C_REG_ADDR_08BITS, + MAX96715_I2C_REG_VALUE_08BITS, &value); + + *reg_val = *value_be_p; + + return ret; +} + +static int __maybe_unused max96715_update_reg(struct i2c_client *client, + u16 reg_addr, u8 val_mask, u8 reg_val) +{ + u8 value; + int ret; + + ret = max96715_read_reg(client, reg_addr, &value); + if (ret) + return ret; + + value &= ~val_mask; + value |= (reg_val & val_mask); + ret = max96715_write_reg(client, reg_addr, value); + + return ret; +} + +static int max96715_i2c_write_array(struct i2c_client *client, + const struct maxim_remote_regval *regs) +{ + u32 i = 0; + int ret = 0; + + for (i = 0; (ret == 0) && (regs[i].reg_addr != MAXIM_REMOTE_REG_NULL); i++) { + if (regs[i].val_mask != 0) + ret = max96715_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 = max96715_i2c_write(client, + regs[i].reg_addr, regs[i].reg_len, + regs[i].val_len, regs[i].reg_val); + + if (regs[i].delay != 0) + usleep_range(regs[i].delay * 1000, regs[i].delay * 1000 + 100); + } + + return ret; +} + +static int max96715_run_ser_init_seq(struct i2c_client *client, + struct maxim_remote_init_seq *init_seq) +{ + int ret = 0; + + if ((init_seq == NULL) || (init_seq->reg_init_seq == NULL)) + return 0; + + ret = max96715_i2c_write_array(client, + init_seq->reg_init_seq); + + return ret; +} + +static int max96715_load_ser_init_seq(maxim_remote_ser_t *max96715) +{ + struct device *dev = &max96715->client->dev; + struct device_node *node = NULL; + int ret = 0; + + node = of_get_child_by_name(dev->of_node, "ser-init-sequence"); + if (!IS_ERR_OR_NULL(node)) { + dev_info(dev, "load ser-init-sequence\n"); + + ret = maxim_remote_load_init_seq(dev, node, + &max96715->ser_init_seq); + + of_node_put(node); + return ret; + } + + return 0; +} + +static int __maybe_unused max96715_link_mode_select(maxim_remote_ser_t *max96715, u32 mode) +{ + struct i2c_client *client = max96715->client; + struct device *dev = &client->dev; + 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 |= max96715_update_reg(client, 0x04, reg_mask, reg_value); + + msleep(delay_ms); + + return ret; +} + +static int max96715_i2c_addr_remap(maxim_remote_ser_t *max96715) +{ + struct i2c_client *client = max96715->client; + struct device *dev = &client->dev; + u16 i2c_8bit_addr = 0; + int ret = 0; + + // Serializer i2c address map + if (max96715->ser_i2c_addr_map != max96715->ser_i2c_addr_def) { + dev_info(dev, "Serializer i2c address remap\n"); + + maxim_remote_ser_i2c_addr_select(max96715, MAXIM_REMOTE_I2C_SER_DEF); + + i2c_8bit_addr = (max96715->ser_i2c_addr_map << 1); + ret = max96715_write_reg(client, 0x00, i2c_8bit_addr); + if (ret) { + dev_err(dev, "ser i2c address map setting error!\n"); + return ret; + } + + maxim_remote_ser_i2c_addr_select(max96715, MAXIM_REMOTE_I2C_SER_MAP); + } + + // Camera i2c address map + if (max96715->cam_i2c_addr_map != max96715->cam_i2c_addr_def) { + dev_info(dev, "Camera i2c address remap\n"); + + i2c_8bit_addr = (max96715->cam_i2c_addr_map << 1); + ret = max96715_write_reg(client, 0x09, 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 = max96715_write_reg(client, 0x0A, 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(maxim_remote_ser_t *max96715) +{ + struct i2c_client *client = max96715->client; + struct device *dev = &client->dev; + u16 i2c_8bit_addr = 0; + int ret = 0; + + if (max96715->ser_i2c_addr_map) { + dev_info(dev, "Serializer i2c address def\n"); + + maxim_remote_ser_i2c_addr_select(max96715, MAXIM_REMOTE_I2C_SER_MAP); + + i2c_8bit_addr = (max96715->ser_i2c_addr_def << 1); + ret = max96715_write_reg(client, 0x00, i2c_8bit_addr); + if (ret) { + dev_err(dev, "ser i2c address def setting error!\n"); + return ret; + } + + maxim_remote_ser_i2c_addr_select(max96715, MAXIM_REMOTE_I2C_SER_DEF); + } + + return 0; +} + +static int max96715_check_chipid(maxim_remote_ser_t *max96715) +{ + struct i2c_client *client = max96715->client; + struct device *dev = &client->dev; + u8 chip_id; + int ret = 0; + + // max96715 + ret = max96715_read_reg(client, MAX96715_REG_CHIP_ID, &chip_id); + if (ret != 0) { + dev_info(dev, "Retry check chipid using map address\n"); + maxim_remote_ser_i2c_addr_select(max96715, MAXIM_REMOTE_I2C_SER_MAP); + ret = max96715_read_reg(client, MAX96715_REG_CHIP_ID, &chip_id); + if (ret != 0) { + dev_err(dev, "MAX96715 detect error, ret(%d)\n", ret); + maxim_remote_ser_i2c_addr_select(max96715, MAXIM_REMOTE_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; +} + +/* + * max96715_pclk_detect() - Detect valid pixel clock from image sensor + * + * Wait up to 500ms for a valid pixel clock. + * + * Returns 0 for success, < 0 for pixel clock not properly detected + */ +static int max96715_pclk_detect(maxim_remote_ser_t *max96715) +{ + struct i2c_client *client = max96715->client; + struct device *dev = &client->dev; + u8 pclk_det = 0; + unsigned int i; + int ret = 0; + + for (i = 0; i < 500; i++) { + ret = max96715_read_reg(client, 0x15, &pclk_det); + + if ((ret == 0) && (pclk_det & BIT(0))) { + dev_info(dev, "Detect valid PCLK (%d)\n", i); + return 0; + } + + usleep_range(1000, 1100); + } + + dev_err(dev, "Unable to detect valid PCLK, timeout\n"); + + return -EIO; +} + +static int max96715_soft_power_down(maxim_remote_ser_t *max96715) +{ + struct i2c_client *client = max96715->client; + struct device *dev = &client->dev; + int ret = 0; + + ret = max96715_write_reg(client, 0x13, BIT(7)); + if (ret) { + dev_err(dev, "soft power down setting error!\n"); + return ret; + } + + return 0; +} + +static int max96715_module_init(maxim_remote_ser_t *max96715) +{ + struct i2c_client *client = max96715->client; + int ret = 0; + + ret = maxim_remote_ser_i2c_addr_select(max96715, MAXIM_REMOTE_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 = max96715_run_ser_init_seq(client, &max96715->ser_init_seq); + if (ret) { + dev_err(&client->dev, "run ser init sequence error\n"); + 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(maxim_remote_ser_t *max96715) +{ + int ret = 0; + +#if 0 + ret |= max96715_i2c_addr_def(max96715); +#endif + ret |= max96715_soft_power_down(max96715); + + return ret; +} + +static struct maxim_remote_ser_ops max96715_ser_ops = { + .ser_module_init = max96715_module_init, + .ser_module_deinit = max96715_module_deinit, + .ser_pclk_detect = max96715_pclk_detect, +}; + +static int max96715_parse_dt(maxim_remote_ser_t *max96715) +{ + struct device *dev = &max96715->client->dev; + struct device_node *of_node = dev->of_node; + u32 value = 0; + int ret = 0; + + dev_info(dev, "=== max96715 parse dt ===\n"); + + 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; + } + + return 0; +} + +static int max96715_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + maxim_remote_ser_t *max96715 = NULL; + + dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff); + + max96715 = devm_kzalloc(dev, sizeof(*max96715), GFP_KERNEL); + if (!max96715) { + dev_err(dev, "max96715 probe no memory error\n"); + return -ENOMEM; + } + + max96715->client = client; + max96715->ser_i2c_addr_map = client->addr; + max96715->ser_ops = &max96715_ser_ops; + + i2c_set_clientdata(client, max96715); + + mutex_init(&max96715->mutex); + + max96715_parse_dt(max96715); + + max96715_load_ser_init_seq(max96715); + + return 0; +} + +static int max96715_remove(struct i2c_client *client) +{ + maxim_remote_ser_t *max96715 = i2c_get_clientdata(client); + + mutex_destroy(&max96715->mutex); + + return 0; +} + +static const struct of_device_id max96715_of_match[] = { + { .compatible = "maxim,ser,max96715" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, max96715_of_match); + +static struct i2c_driver max96715_i2c_driver = { + .driver = { + .name = MAX96715_NAME, + .of_match_table = of_match_ptr(max96715_of_match), + }, + .probe = &max96715_probe, + .remove = &max96715_remove, +}; + +module_i2c_driver(max96715_i2c_driver); + +MODULE_AUTHOR("Cai Wenzhong "); +MODULE_DESCRIPTION("Maxim MAX96715 Serializer Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/maxim/remote/max96717.c b/drivers/media/i2c/maxim/remote/max96717.c new file mode 100644 index 000000000000..d45e2b0acbc9 --- /dev/null +++ b/drivers/media/i2c/maxim/remote/max96717.c @@ -0,0 +1,508 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Maxim Max96717 GMSL2/GMSL1 Serializer driver + * + * Copyright (C) 2023 Rockchip Electronics Co., Ltd. + * + * Author: Cai Wenzhong + * + */ +#include +#include +#include +#include +#include +#include + +#include "maxim_remote.h" + +#define DRIVER_VERSION KERNEL_VERSION(3, 0x00, 0x00) + +#define MAX96717_NAME "maxim-max96717" + +#define MAX96717_I2C_ADDR_DEF 0x40 + +#define MAX96717_CHIP_ID 0xBF +#define MAX96717_REG_CHIP_ID 0x0D + +/* register address: 16bit */ +#define MAX96717_I2C_REG_ADDR_16BITS 2 + +/* register value: 8bit */ +#define MAX96717_I2C_REG_VALUE_08BITS 1 + +/* Write registers up to 4 at a time */ +static int max96717_i2c_write(struct i2c_client *client, + u16 reg_addr, u16 reg_len, u32 val_len, u32 reg_val) +{ + u32 buf_i, val_i; + u8 buf[6]; + u8 *val_p; + __be32 val_be; + + dev_info(&client->dev, "i2c addr(0x%02x) write: 0x%04x (%d) = 0x%08x (%d)\n", + client->addr, reg_addr, reg_len, reg_val, val_len); + + if (val_len > 4) + return -EINVAL; + + if (reg_len == 2) { + buf[0] = reg_addr >> 8; + buf[1] = reg_addr & 0xff; + + buf_i = 2; + } else { + buf[0] = reg_addr & 0xff; + + buf_i = 1; + } + + val_be = cpu_to_be32(reg_val); + val_p = (u8 *)&val_be; + val_i = 4 - val_len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, (val_len + reg_len)) != (val_len + reg_len)) { + dev_err(&client->dev, + "%s: writing register 0x%04x from 0x%02x failed\n", + __func__, reg_addr, client->addr); + return -EIO; + } + + return 0; +} + +/* Read registers up to 4 at a time */ +static int max96717_i2c_read(struct i2c_client *client, + u16 reg_addr, u16 reg_len, u32 val_len, u32 *reg_val) +{ + struct i2c_msg msgs[2]; + u8 *data_be_p; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg_addr); + u8 *reg_be_p; + int ret; + + if (val_len > 4 || !val_len) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + reg_be_p = (u8 *)®_addr_be; + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = reg_len; + msgs[0].buf = ®_be_p[2 - reg_len]; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = val_len; + msgs[1].buf = &data_be_p[4 - val_len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + dev_err(&client->dev, + "%s: reading register 0x%04x from 0x%02x failed\n", + __func__, reg_addr, client->addr); + return -EIO; + } + + *reg_val = be32_to_cpu(data_be); + +#if 0 + dev_info(&client->dev, "i2c addr(0x%02x) read: 0x%04x (%d) = 0x%08x (%d)\n", + client->addr, reg_addr, reg_len, *reg_val, val_len); +#endif + + return 0; +} + +/* Update registers up to 4 at a time */ +static int max96717_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 = max96717_i2c_read(client, reg_addr, reg_len, val_len, &value); + if (ret) + return ret; + + value &= ~val_mask; + value |= (reg_val & val_mask); + ret = max96717_i2c_write(client, reg_addr, reg_len, val_len, value); + + return ret; +} + +static int max96717_write_reg(struct i2c_client *client, + u16 reg_addr, u8 reg_val) +{ + int ret = 0; + + ret = max96717_i2c_write(client, + reg_addr, MAX96717_I2C_REG_ADDR_16BITS, + MAX96717_I2C_REG_VALUE_08BITS, reg_val); + + return ret; +} + +static int max96717_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 = max96717_i2c_read(client, + reg_addr, MAX96717_I2C_REG_ADDR_16BITS, + MAX96717_I2C_REG_VALUE_08BITS, &value); + + *reg_val = *value_be_p; + + return ret; +} + +static int __maybe_unused max96717_update_reg(struct i2c_client *client, + u16 reg_addr, u8 val_mask, u8 reg_val) +{ + u8 value; + int ret; + + ret = max96717_read_reg(client, reg_addr, &value); + if (ret) + return ret; + + value &= ~val_mask; + value |= (reg_val & val_mask); + ret = max96717_write_reg(client, reg_addr, value); + + return ret; +} + +static int max96717_i2c_write_array(struct i2c_client *client, + const struct maxim_remote_regval *regs) +{ + u32 i = 0; + int ret = 0; + + for (i = 0; (ret == 0) && (regs[i].reg_addr != MAXIM_REMOTE_REG_NULL); i++) { + if (regs[i].val_mask != 0) + ret = max96717_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 = max96717_i2c_write(client, + regs[i].reg_addr, regs[i].reg_len, + regs[i].val_len, regs[i].reg_val); + + if (regs[i].delay != 0) + usleep_range(regs[i].delay * 1000, regs[i].delay * 1000 + 100); + } + + return ret; +} + +static int max96717_run_ser_init_seq(struct i2c_client *client, + struct maxim_remote_init_seq *init_seq) +{ + int ret = 0; + + if ((init_seq == NULL) || (init_seq->reg_init_seq == NULL)) + return 0; + + ret = max96717_i2c_write_array(client, + init_seq->reg_init_seq); + + return ret; +} + +static int max96717_load_ser_init_seq(maxim_remote_ser_t *max96717) +{ + struct device *dev = &max96717->client->dev; + struct device_node *node = NULL; + int ret = 0; + + node = of_get_child_by_name(dev->of_node, "ser-init-sequence"); + if (!IS_ERR_OR_NULL(node)) { + dev_info(dev, "load ser-init-sequence\n"); + + ret = maxim_remote_load_init_seq(dev, node, + &max96717->ser_init_seq); + + of_node_put(node); + return ret; + } + + return 0; +} + +static int max96717_i2c_addr_remap(maxim_remote_ser_t *max96717) +{ + struct i2c_client *client = max96717->client; + struct device *dev = &client->dev; + u16 i2c_8bit_addr = 0; + int ret = 0; + + // Serializer i2c address map + if (max96717->ser_i2c_addr_map != max96717->ser_i2c_addr_def) { + dev_info(dev, "Serializer i2c address remap\n"); + + maxim_remote_ser_i2c_addr_select(max96717, MAXIM_REMOTE_I2C_SER_DEF); + + i2c_8bit_addr = (max96717->ser_i2c_addr_map << 1); + ret = max96717_write_reg(client, 0x0000, i2c_8bit_addr); + if (ret) { + dev_err(dev, "ser i2c address map setting error!\n"); + return ret; + } + + maxim_remote_ser_i2c_addr_select(max96717, MAXIM_REMOTE_I2C_SER_MAP); + } + + // Camera i2c address map + if (max96717->cam_i2c_addr_map != max96717->cam_i2c_addr_def) { + dev_info(dev, "Camera i2c address remap\n"); + + i2c_8bit_addr = (max96717->cam_i2c_addr_map << 1); + ret = max96717_write_reg(client, 0x0042, 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 = max96717_write_reg(client, 0x0043, 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(maxim_remote_ser_t *max96717) +{ + struct i2c_client *client = max96717->client; + struct device *dev = &client->dev; + u16 i2c_8bit_addr = 0; + int ret = 0; + + if (max96717->ser_i2c_addr_map) { + dev_info(dev, "Serializer i2c address def\n"); + + maxim_remote_ser_i2c_addr_select(max96717, MAXIM_REMOTE_I2C_SER_MAP); + + i2c_8bit_addr = (max96717->ser_i2c_addr_def << 1); + ret = max96717_write_reg(client, 0x0000, i2c_8bit_addr); + if (ret) { + dev_err(dev, "ser i2c address def setting error!\n"); + return ret; + } + + maxim_remote_ser_i2c_addr_select(max96717, MAXIM_REMOTE_I2C_SER_DEF); + } + + return 0; +} + +static int max96717_check_chipid(maxim_remote_ser_t *max96717) +{ + struct i2c_client *client = max96717->client; + struct device *dev = &client->dev; + u8 chip_id; + int ret = 0; + + // max96717 + ret = max96717_read_reg(client, MAX96717_REG_CHIP_ID, &chip_id); + if (ret != 0) { + dev_info(dev, "Retry check chipid using map address\n"); + maxim_remote_ser_i2c_addr_select(max96717, MAXIM_REMOTE_I2C_SER_MAP); + ret = max96717_read_reg(client, MAX96717_REG_CHIP_ID, &chip_id); + if (ret != 0) { + dev_err(dev, "MAX96717 detect error, ret(%d)\n", ret); + maxim_remote_ser_i2c_addr_select(max96717, MAXIM_REMOTE_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; +} + +/* + * max96717_pclk_detect() - Detect valid pixel clock from image sensor + * + * Wait up to 500ms for a valid pixel clock. + * + * Returns 0 for success, < 0 for pixel clock not properly detected + */ +static int max96717_pclk_detect(maxim_remote_ser_t *max96717) +{ + struct i2c_client *client = max96717->client; + struct device *dev = &client->dev; + u8 vid_tx_en_mask = 0, pclk_det = 0; + unsigned int i; + int ret = 0; + + ret = max96717_read_reg(client, 0x0002, &vid_tx_en_mask); + if (ret == 0) { + vid_tx_en_mask = vid_tx_en_mask & BIT(6); + dev_info(dev, "VID_TX_EN = 0x%x\n", vid_tx_en_mask); + if (vid_tx_en_mask == 0) + dev_err(dev, "VID_TX_EN config error\n"); + } else { + dev_err(dev, "Detect PCLK error\n"); + return ret; + } + + for (i = 0; i < 500; i++) { + // VID TX: Z + ret = max96717_read_reg(client, 0x0112, &pclk_det); + + if ((ret == 0) && (pclk_det & BIT(7))) { + dev_info(dev, "VID_TX_Z detect valid PCLK (%d)\n", i); + return 0; + } + + usleep_range(1000, 1100); + } + + dev_err(dev, "Unable to detect valid PCLK, timeout\n"); + + return -EIO; +} + +static int max96717_module_init(maxim_remote_ser_t *max96717) +{ + struct i2c_client *client = max96717->client; + int ret = 0; + + ret = maxim_remote_ser_i2c_addr_select(max96717, MAXIM_REMOTE_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 = max96717_run_ser_init_seq(client, &max96717->ser_init_seq); + if (ret) { + dev_err(&client->dev, "run ser init sequence error\n"); + return ret; + } + + return 0; +} + +static int max96717_module_deinit(maxim_remote_ser_t *max96717) +{ + int ret = 0; + + ret |= max96717_i2c_addr_def(max96717); + + return ret; +} + +static struct maxim_remote_ser_ops max96717_ser_ops = { + .ser_module_init = max96717_module_init, + .ser_module_deinit = max96717_module_deinit, + .ser_pclk_detect = max96717_pclk_detect, +}; + +static int max96717_parse_dt(maxim_remote_ser_t *max96717) +{ + struct device *dev = &max96717->client->dev; + struct device_node *of_node = dev->of_node; + u32 value = 0; + int ret = 0; + + dev_info(dev, "=== max96717 parse dt ===\n"); + + 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; + } + + return 0; +} + +static int max96717_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + maxim_remote_ser_t *max96717 = NULL; + + dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff); + + max96717 = devm_kzalloc(dev, sizeof(*max96717), GFP_KERNEL); + if (!max96717) { + dev_err(dev, "max96717 probe no memory error\n"); + return -ENOMEM; + } + + max96717->client = client; + max96717->ser_i2c_addr_map = client->addr; + max96717->ser_ops = &max96717_ser_ops; + + i2c_set_clientdata(client, max96717); + + mutex_init(&max96717->mutex); + + max96717_parse_dt(max96717); + + max96717_load_ser_init_seq(max96717); + + return 0; +} + +static int max96717_remove(struct i2c_client *client) +{ + maxim_remote_ser_t *max96717 = i2c_get_clientdata(client); + + mutex_destroy(&max96717->mutex); + + return 0; +} + +static const struct of_device_id max96717_of_match[] = { + { .compatible = "maxim,ser,max96717" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, max96717_of_match); + +static struct i2c_driver max96717_i2c_driver = { + .driver = { + .name = MAX96717_NAME, + .of_match_table = of_match_ptr(max96717_of_match), + }, + .probe = &max96717_probe, + .remove = &max96717_remove, +}; + +module_i2c_driver(max96717_i2c_driver); + +MODULE_AUTHOR("Cai Wenzhong "); +MODULE_DESCRIPTION("Maxim MAX96717 Serializer Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/maxim/remote/maxim_remote.h b/drivers/media/i2c/maxim/remote/maxim_remote.h new file mode 100644 index 000000000000..0fa29acf9f00 --- /dev/null +++ b/drivers/media/i2c/maxim/remote/maxim_remote.h @@ -0,0 +1,313 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +#ifndef __MAXIM_REMOTE_H__ +#define __MAXIM_REMOTE_H__ + +#include +#include + +/* I2C Device ID */ +enum { + MAXIM_REMOTE_I2C_SER_DEF, /* Serializer I2C address: Default */ + MAXIM_REMOTE_I2C_SER_MAP, /* Serializer I2C address: Mapping */ + + MAXIM_REMOTE_I2C_CAM_DEF, /* Camera I2C address: Default */ + MAXIM_REMOTE_I2C_CAM_MAP, /* Camera I2C address: Mapping */ + + MAXIM_REMOTE_I2C_DEV_MAX, +}; + +/* i2c register array end */ +#define MAXIM_REMOTE_REG_NULL 0xFFFF + +struct maxim_remote_regval { + u16 reg_len; + u16 reg_addr; + u32 val_len; + u32 reg_val; + u32 val_mask; + u8 delay; +}; + +/* seq_item_size = reg_len + val_len * 2 + 1 */ +struct maxim_remote_init_seq { + struct maxim_remote_regval *reg_init_seq; + u32 reg_seq_size; + u32 seq_item_size; + u32 reg_len; + u32 val_len; +}; + +struct maxim_remote_ser; + +struct maxim_remote_ser_ops { + int (*ser_module_init)(struct maxim_remote_ser *remote_ser); + int (*ser_module_deinit)(struct maxim_remote_ser *remote_ser); + int (*ser_pclk_detect)(struct maxim_remote_ser *remote_ser); +}; + +typedef struct maxim_remote_ser { + struct i2c_client *client; + + struct mutex mutex; + + u8 ser_i2c_addr_def; + u8 ser_i2c_addr_map; + + u8 cam_i2c_addr_def; + u8 cam_i2c_addr_map; + + struct maxim_remote_init_seq ser_init_seq; + const struct maxim_remote_ser_ops *ser_ops; +} maxim_remote_ser_t; + +static inline int maxim_remote_parse_init_seq(struct device *dev, + const u8 *seq_data, int data_len, struct maxim_remote_init_seq *init_seq) +{ + struct maxim_remote_regval *reg_val = NULL; + u8 *data_buf = NULL, *d8 = NULL; + u32 i = 0; + + if ((seq_data == NULL) || (init_seq == NULL)) { + dev_err(dev, "%s: input parameter = NULL\n", __func__); + return -EINVAL; + } + + if ((init_seq->seq_item_size == 0) + || (data_len == 0) + || (init_seq->reg_len == 0) + || (init_seq->val_len == 0)) { + dev_err(dev, "%s: input parameter size zero\n", __func__); + return -EINVAL; + } + + // data_len = seq_item_size * N + if (data_len % init_seq->seq_item_size) { + dev_err(dev, "%s: data_len or seq_item_size error\n", __func__); + return -EINVAL; + } + + // seq_item_size = reg_len + val_len * 2 + 1 + if (init_seq->seq_item_size != + (init_seq->reg_len + init_seq->val_len * 2 + 1)) { + dev_err(dev, "%s: seq_item_size or reg_len or val_len error\n", __func__); + return -EINVAL; + } + + data_buf = devm_kmemdup(dev, seq_data, data_len, GFP_KERNEL); + if (!data_buf) { + dev_err(dev, "%s data buf error\n", __func__); + return -ENOMEM; + } + + d8 = data_buf; + + init_seq->reg_seq_size = data_len / init_seq->seq_item_size; + init_seq->reg_seq_size += 1; // add 1 for end register setting + + init_seq->reg_init_seq = devm_kcalloc(dev, init_seq->reg_seq_size, + sizeof(struct maxim_remote_regval), GFP_KERNEL); + if (!init_seq->reg_init_seq) { + dev_err(dev, "%s init seq buffer error\n", __func__); + return -ENOMEM; + } + + for (i = 0; i < init_seq->reg_seq_size - 1; i++) { + reg_val = &init_seq->reg_init_seq[i]; + + reg_val->reg_len = init_seq->reg_len; + reg_val->val_len = init_seq->val_len; + + reg_val->reg_addr = 0; + switch (init_seq->reg_len) { + case 4: + reg_val->reg_addr |= (*d8 << 24); + d8 += 1; + fallthrough; + case 3: + reg_val->reg_addr |= (*d8 << 16); + d8 += 1; + fallthrough; + case 2: + reg_val->reg_addr |= (*d8 << 8); + d8 += 1; + fallthrough; + case 1: + reg_val->reg_addr |= (*d8 << 0); + d8 += 1; + break; + } + + reg_val->reg_val = 0; + switch (init_seq->val_len) { + case 4: + reg_val->reg_val |= (*d8 << 24); + d8 += 1; + fallthrough; + case 3: + reg_val->reg_val |= (*d8 << 16); + d8 += 1; + fallthrough; + case 2: + reg_val->reg_val |= (*d8 << 8); + d8 += 1; + fallthrough; + case 1: + reg_val->reg_val |= (*d8 << 0); + d8 += 1; + break; + } + + reg_val->val_mask = 0; + switch (init_seq->val_len) { + case 4: + reg_val->val_mask |= (*d8 << 24); + d8 += 1; + fallthrough; + case 3: + reg_val->val_mask |= (*d8 << 16); + d8 += 1; + fallthrough; + case 2: + reg_val->val_mask |= (*d8 << 8); + d8 += 1; + fallthrough; + case 1: + reg_val->val_mask |= (*d8 << 0); + d8 += 1; + break; + } + + reg_val->delay = *d8; + d8 += 1; + } + + // End register setting + init_seq->reg_init_seq[init_seq->reg_seq_size - 1].reg_len = init_seq->reg_len; + init_seq->reg_init_seq[init_seq->reg_seq_size - 1].reg_addr = MAXIM_REMOTE_REG_NULL; + + return 0; +} + +static inline int maxim_remote_load_init_seq(struct device *dev, + struct device_node *node, struct maxim_remote_init_seq *init_seq) +{ + const void *init_seq_data = NULL; + u32 seq_data_len = 0, value = 0; + int ret = 0; + + if ((node == NULL) || (init_seq == NULL)) { + dev_err(dev, "%s input parameter error\n", __func__); + return -EINVAL; + } + + init_seq->reg_init_seq = NULL; + init_seq->reg_seq_size = 0; + + if (!of_device_is_available(node)) { + dev_info(dev, "%pOF is disabled\n", node); + + return 0; + } + + init_seq_data = of_get_property(node, "init-sequence", &seq_data_len); + if (!init_seq_data) { + dev_err(dev, "failed to get property init-sequence\n"); + return -EINVAL; + } + if (seq_data_len == 0) { + dev_err(dev, "init-sequence date is empty\n"); + return -EINVAL; + } + + ret = of_property_read_u32(node, "seq-item-size", &value); + if (ret) { + dev_err(dev, "failed to get property seq-item-size\n"); + return -EINVAL; + } else { + dev_info(dev, "seq-item-size property: %d", value); + init_seq->seq_item_size = value; + } + + ret = of_property_read_u32(node, "reg-addr-len", &value); + if (ret) { + dev_err(dev, "failed to get property reg-addr-len\n"); + return -EINVAL; + } else { + dev_info(dev, "reg-addr-len property: %d", value); + init_seq->reg_len = value; + } + + ret = of_property_read_u32(node, "reg-val-len", &value); + if (ret) { + dev_err(dev, "failed to get property reg-val-len\n"); + return -EINVAL; + } else { + dev_info(dev, "reg-val-len property: %d", value); + init_seq->val_len = value; + } + + ret = maxim_remote_parse_init_seq(dev, + init_seq_data, seq_data_len, init_seq); + if (ret) { + dev_err(dev, "failed to parse init-sequence\n"); + return ret; + } + + return 0; +} + +static inline int maxim_remote_ser_i2c_addr_select(maxim_remote_ser_t *remote_ser, u32 i2c_id) +{ + struct i2c_client *ser_client = remote_ser->client; + struct device *dev = &ser_client->dev; + + if (i2c_id == MAXIM_REMOTE_I2C_SER_DEF) { + ser_client->addr = remote_ser->ser_i2c_addr_def; + dev_info(dev, "ser select default i2c addr = 0x%02x\n", ser_client->addr); + } else if (i2c_id == MAXIM_REMOTE_I2C_SER_MAP) { + ser_client->addr = remote_ser->ser_i2c_addr_map; + dev_info(dev, "ser select mapping i2c addr = 0x%02x\n", ser_client->addr); + } else { + dev_err(dev, "i2c select id = %d error\n", i2c_id); + return -EINVAL; + } + + return 0; +} + +static inline struct maxim_remote_ser *maxim_remote_cam_bind_ser(struct device *cam_dev) +{ + struct i2c_client *ser_client = NULL; + struct device_node *ser_node = NULL; + maxim_remote_ser_t *remote_ser = NULL; + + /* camera get remote serializer node */ + ser_node = of_parse_phandle(cam_dev->of_node, "cam-remote-ser", 0); + if (!IS_ERR_OR_NULL(ser_node)) { + dev_info(cam_dev, "remote serializer node: %pOF\n", ser_node); + + ser_client = of_find_i2c_device_by_node(ser_node); + of_node_put(ser_node); + if (!IS_ERR_OR_NULL(ser_client)) { + remote_ser = i2c_get_clientdata(ser_client); + if (!IS_ERR_OR_NULL(remote_ser)) + return remote_ser; + else + return NULL; + } else { + dev_err(cam_dev, "camera find remote serializer client error\n"); + + return NULL; + } + } else { + dev_warn(cam_dev, "cam-remote-ser node isn't exist\n"); + return NULL; + } +} + +#endif /* __MAXIM_REMOTE_H__ */