mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
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 <cwz@rock-chips.com> Change-Id: Ib9f5fbefdded0f40a9b06f3c490713c4f0a20dfd
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_VIDEO_MAXIM_SERDES) += local/
|
||||
obj-$(CONFIG_VIDEO_MAXIM_SERDES) += local/ remote/
|
||||
|
||||
36
drivers/media/i2c/maxim/remote/Kconfig
Normal file
36
drivers/media/i2c/maxim/remote/Kconfig
Normal file
@@ -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
|
||||
5
drivers/media/i2c/maxim/remote/Makefile
Normal file
5
drivers/media/i2c/maxim/remote/Makefile
Normal file
@@ -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
|
||||
558
drivers/media/i2c/maxim/remote/max9295.c
Normal file
558
drivers/media/i2c/maxim/remote/max9295.c
Normal file
@@ -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 <cwz@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#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 <cwz@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Maxim MAX9295 Serializer Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
559
drivers/media/i2c/maxim/remote/max96715.c
Normal file
559
drivers/media/i2c/maxim/remote/max96715.c
Normal file
@@ -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 <cwz@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#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 <cwz@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Maxim MAX96715 Serializer Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
508
drivers/media/i2c/maxim/remote/max96717.c
Normal file
508
drivers/media/i2c/maxim/remote/max96717.c
Normal file
@@ -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 <cwz@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#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 <cwz@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Maxim MAX96717 Serializer Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
313
drivers/media/i2c/maxim/remote/maxim_remote.h
Normal file
313
drivers/media/i2c/maxim/remote/maxim_remote.h
Normal file
@@ -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 <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/* 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__ */
|
||||
Reference in New Issue
Block a user