// SPDX-License-Identifier: GPL-2.0
/*
* ns6601 HSMT to CSI-2 Deserializer driver
*
* Copyright (C) 2024 Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X00 first version.
* V1.0X00.0X00 Support New Driver Framework.
* V1.0X01.0X00 serdes read /write api depend on i2c id index.
*
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/compat.h>
#include <linux/rk-camera-module.h>
#include <linux/of_graph.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include "ns6601_config.h"
#define DRIVER_VERSION KERNEL_VERSION(1, 0x01, 0x00)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
#define NS6601_LINK_FREQ_MHZ(x) ((x) * 1000000UL)
#define NS6601_XVCLK_FREQ 25000000
#define NS6601_NAME "ns6601"
struct ns6601_mode {
u32 width;
u32 height;
struct v4l2_fract max_fps;
u32 hts_def;
u32 vts_def;
u32 exp_def;
u32 link_freq_idx;
u32 bus_fmt;
u32 bpp;
u32 vc[PAD_MAX];
};
struct ns6601_hot_plug_work {
struct workqueue_struct *state_check_wq;
struct delayed_work state_d_work;
u32 hot_plug_state;
};
struct ns6601 {
struct i2c_client *client;
u16 i2c_addr;
struct clk *xvclk;
struct gpio_desc *power_gpio;
struct gpio_desc *reset_gpio;
struct gpio_desc *pwdn_gpio;
struct gpio_desc *pocen_gpio;
struct gpio_desc *lock_gpio;
struct gpio_desc *errb_gpio;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_sleep;
struct v4l2_subdev subdev;
struct media_pad pad;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *exposure;
struct v4l2_ctrl *anal_gain;
struct v4l2_ctrl *digi_gain;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *link_freq;
struct v4l2_ctrl *test_pattern;
struct v4l2_fwnode_endpoint bus_cfg;
struct mutex mutex;
bool streaming;
bool power_on;
bool hot_plug;
u8 is_reset;
int hot_plug_irq;
u32 link_mask;
struct ns6601_hot_plug_work hot_plug_work;
struct ns6601_mode supported_modes;
const struct ns6601_mode *cur_mode;
u32 cfg_modes_num;
u32 module_index;
u32 auto_init_deskew_mask;
u32 frame_sync_period;
const char *module_facing;
const char *module_name;
const char *len_name;
struct regmap *regmap;
};
static const struct regmap_config ns6601_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x1FFF,
};
static struct rkmodule_csi_dphy_param rk3588_dcphy_param = {
.vendor = PHY_VENDOR_SAMSUNG,
.lp_vol_ref = 3,
.lp_hys_sw = {3, 0, 0, 0},
.lp_escclk_pol_sel = {1, 0, 0, 0},
.skew_data_cal_clk = {0, 0, 0, 0},
.clk_hs_term_sel = 2,
.data_hs_term_sel = {2, 2, 2, 2},
.reserved = {0},
};
static const struct ns6601_mode ns6601_def_mode[] = {
{
.width = 1600,
.height = 1080,
.max_fps = {
.numerator = 10000,
.denominator = 300000,
},
.link_freq_idx = 15,// to do 750M
.bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8,
.bpp = 16,
.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
.vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1,
.vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_2,
.vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_3,
},
};
/* link freq = index * NS6601_LINK_FREQ_MHZ(50) */
static const s64 link_freq_items[] = {
NS6601_LINK_FREQ_MHZ(0),
NS6601_LINK_FREQ_MHZ(50),
NS6601_LINK_FREQ_MHZ(100),
NS6601_LINK_FREQ_MHZ(150),
NS6601_LINK_FREQ_MHZ(200),
NS6601_LINK_FREQ_MHZ(250),
NS6601_LINK_FREQ_MHZ(300),
NS6601_LINK_FREQ_MHZ(350),
NS6601_LINK_FREQ_MHZ(400),
NS6601_LINK_FREQ_MHZ(450),
NS6601_LINK_FREQ_MHZ(500),
NS6601_LINK_FREQ_MHZ(550),
NS6601_LINK_FREQ_MHZ(600),
NS6601_LINK_FREQ_MHZ(650),
NS6601_LINK_FREQ_MHZ(700),
NS6601_LINK_FREQ_MHZ(750),
NS6601_LINK_FREQ_MHZ(800),
NS6601_LINK_FREQ_MHZ(850),
NS6601_LINK_FREQ_MHZ(900),
NS6601_LINK_FREQ_MHZ(950),
NS6601_LINK_FREQ_MHZ(1000),
NS6601_LINK_FREQ_MHZ(1050),
NS6601_LINK_FREQ_MHZ(1100),
NS6601_LINK_FREQ_MHZ(1150),
NS6601_LINK_FREQ_MHZ(1200),
NS6601_LINK_FREQ_MHZ(1250),
};
static int ns6601_write_reg(struct ns6601 *ns6601,u16 val_len, u8* val)
{
struct i2c_client *client = ns6601->client;
u16 client_addr = ns6601->i2c_addr;
dev_dbg(&client->dev, "addr(0x%02x) write reg(0x%04x, %d, 0x%02x)\n",
client_addr, val[0], val_len, val[1]);
client->addr = client_addr;
if (i2c_master_send(client, val, val_len) != val_len) {
dev_err(&client->dev,
"%s: writing register 0x%04x from 0x%02x failed\n",
__func__, val[0], client->addr);
return -EIO;
}
return 0;
}
static int ns6601_read_reg(struct ns6601 *ns6601,u16 val_len, u8 *val)
{
struct i2c_client *client = ns6601->client;
u16 client_addr = ns6601->i2c_addr;
struct i2c_msg msgs[1];
int ret;
client->addr = client_addr;
/* Read data from register */
msgs[0].addr = client->addr;
msgs[0].flags = I2C_M_RD;
msgs[0].len = val_len;
msgs[0].buf = val;
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs)) {
dev_err(&client->dev,
"%s: reading register from 0x%x failed\n",
__func__, client->addr);
return -EIO;
}
#if 0
dev_info(&client->dev, "addr(0x%02x) read reg(0x%04x, %d, 0x%02x)\n",
client_addr, reg, reg_len, *val);
#endif
return 0;
}
static int ns6601_mipi_enable(struct ns6601 *ns6601, bool enable)
{
int ret = 0;
u8 mipi1_enable[] = {0x74, 0x88, 0x9e, 0x00, 0xff, 0xff, 0x00, 0x18, 0x5b, 0x82};
u8 mipi2_enable[] = {0x74, 0x88, 0x8e, 0x00, 0xff, 0xff, 0x00, 0x18, 0x19, 0x32};
u8 buf_enable[] = {0x74, 0x48, 0x1d, 0x00, 0xe0, 0x01, 0xe0, 0x01, 0x9a, 0xe8};
if (enable) {
ns6601_write_reg(ns6601,sizeof(mipi1_enable),mipi1_enable);
ns6601_write_reg(ns6601,sizeof(mipi2_enable),mipi2_enable);
ns6601_write_reg(ns6601,sizeof(buf_enable),buf_enable);
}else{
}
return ret;
}
static int ns6601_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct ns6601 *ns6601 = v4l2_get_subdevdata(sd);
const struct ns6601_mode *mode;
u64 pixel_rate = 0;
u8 data_lanes;
mutex_lock(&ns6601->mutex);
mode = &ns6601->supported_modes;
fmt->format.code = mode->bus_fmt;
fmt->format.width = mode->width;
fmt->format.height = mode->height;
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
#else
mutex_unlock(&ns6601->mutex);
return -ENOTTY;
#endif
} else {
if (ns6601->streaming) {
mutex_unlock(&ns6601->mutex);
return -EBUSY;
}
ns6601->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ns6601->link_freq, mode->link_freq_idx);
/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
data_lanes = ns6601->bus_cfg.bus.mipi_csi2.num_data_lanes;
pixel_rate = (u32)link_freq_items[mode->link_freq_idx] / mode->bpp * 2 * data_lanes;
__v4l2_ctrl_s_ctrl_int64(ns6601->pixel_rate, pixel_rate);
dev_info(&ns6601->client->dev, "mipi_freq_idx = %d, mipi_link_freq = %lld\n",
mode->link_freq_idx, link_freq_items[mode->link_freq_idx]);
dev_info(&ns6601->client->dev, "pixel_rate = %lld, bpp = %d\n",
pixel_rate, mode->bpp);
}
mutex_unlock(&ns6601->mutex);
return 0;
}
static int ns6601_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct ns6601 *ns6601 = v4l2_get_subdevdata(sd);
const struct ns6601_mode *mode = ns6601->cur_mode;
mutex_lock(&ns6601->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
#else
mutex_u