From e5ab4cbe7f5312a3a5edbfd1bdacbd8390667752 Mon Sep 17 00:00:00 2001 From: Cody Xie Date: Sun, 8 Oct 2023 10:42:05 +0800 Subject: [PATCH] media: i2c: maxim4c: Add debugfs entry to change MIPI timing Change-Id: I3e215583975e7272ca1c655dc61a59abc6c07d4e Signed-off-by: Cody Xie --- drivers/media/i2c/maxim4c/Makefile | 3 +- drivers/media/i2c/maxim4c/maxim4c_api.h | 3 + drivers/media/i2c/maxim4c/maxim4c_debugfs.c | 60 +++++++++++++ drivers/media/i2c/maxim4c/maxim4c_drv.c | 17 +++- drivers/media/i2c/maxim4c/maxim4c_drv.h | 2 + .../media/i2c/maxim4c/maxim4c_mipi_txphy.c | 84 +++++++++++++++++++ .../media/i2c/maxim4c/maxim4c_mipi_txphy.h | 34 ++++++++ 7 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 drivers/media/i2c/maxim4c/maxim4c_debugfs.c diff --git a/drivers/media/i2c/maxim4c/Makefile b/drivers/media/i2c/maxim4c/Makefile index f1ee630c6c35..665a8669d041 100644 --- a/drivers/media/i2c/maxim4c/Makefile +++ b/drivers/media/i2c/maxim4c/Makefile @@ -7,7 +7,8 @@ maxim4c-objs += maxim4c_i2c.o \ maxim4c_remote.o \ maxim4c_pattern.o \ maxim4c_v4l2.o \ - maxim4c_drv.o + maxim4c_drv.o \ + maxim4c_debugfs.o obj-$(CONFIG_MAXIM4C_SER_MAX9295) += remote_max9295.o obj-$(CONFIG_MAXIM4C_SER_MAX96715) += remote_max96715.o diff --git a/drivers/media/i2c/maxim4c/maxim4c_api.h b/drivers/media/i2c/maxim4c/maxim4c_api.h index 6dd3bbca17d7..25f261c84a44 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_api.h +++ b/drivers/media/i2c/maxim4c/maxim4c_api.h @@ -98,4 +98,7 @@ int maxim4c_pattern_support_mode_init(maxim4c_t *maxim4c); int maxim4c_pattern_data_init(maxim4c_t *maxim4c); int maxim4c_pattern_enable(maxim4c_t *maxim4c, bool enable); +int maxim4c_dbgfs_init(maxim4c_t *maxim4c); +void maxim4c_dbgfs_deinit(maxim4c_t *maxim4c); + #endif /* __MAXIM4C_API_H__ */ diff --git a/drivers/media/i2c/maxim4c/maxim4c_debugfs.c b/drivers/media/i2c/maxim4c/maxim4c_debugfs.c new file mode 100644 index 000000000000..75dddd7114e8 --- /dev/null +++ b/drivers/media/i2c/maxim4c/maxim4c_debugfs.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Maxim Quad GMSL Deserializer debugfs helper functions + * + * Copyright (C) 2023 Rockchip Electronics Co., Ltd. + * + * Author: Cai Wenzhong + * + */ +#include +#include + +#include "maxim4c_api.h" + +int maxim4c_dbgfs_init(maxim4c_t *maxim4c) +{ + struct dentry *entry; + + entry = debugfs_create_dir("maxim4c", NULL); + + debugfs_create_u8("timing_override_en", 0600, entry, + &maxim4c->mipi_txphy.timing_override_en); + + debugfs_create_u8("t_hs_przero", 0600, entry, + &maxim4c->mipi_txphy.timing.t_hs_przero); + debugfs_create_u8("t_hs_prep", 0600, entry, + &maxim4c->mipi_txphy.timing.t_hs_prep); + debugfs_create_u8("t_clk_trail", 0600, entry, + &maxim4c->mipi_txphy.timing.t_clk_trail); + debugfs_create_u8("t_clk_przero", 0600, entry, + &maxim4c->mipi_txphy.timing.t_clk_przero); + debugfs_create_u8("t_lpx", 0600, entry, &maxim4c->mipi_txphy.timing.t_lpx); + debugfs_create_u8("t_hs_trail", 0600, entry, + &maxim4c->mipi_txphy.timing.t_hs_trail); + + debugfs_create_u8("t_clk_prep", 0600, entry, + &maxim4c->mipi_txphy.timing.t_clk_prep); + debugfs_create_u8("t_lpxesc", 0600, entry, + &maxim4c->mipi_txphy.timing.t_lpxesc); + + debugfs_create_u8("csi2_t_pre", 0600, entry, + &maxim4c->mipi_txphy.timing.csi2_t_pre); + debugfs_create_u8("csi2_t_post", 0600, entry, + &maxim4c->mipi_txphy.timing.csi2_t_post); + debugfs_create_u8("csi2_tx_gap", 0600, entry, + &maxim4c->mipi_txphy.timing.csi2_tx_gap); + debugfs_create_u32("csi2_twakeup", 0600, entry, + &maxim4c->mipi_txphy.timing.csi2_twakeup); + + maxim4c->dbgfs_root = entry; + + return 0; +} +EXPORT_SYMBOL(maxim4c_dbgfs_init); + +void maxim4c_dbgfs_deinit(maxim4c_t *maxim4c) +{ + debugfs_remove_recursive(maxim4c->dbgfs_root); +} +EXPORT_SYMBOL(maxim4c_dbgfs_deinit); diff --git a/drivers/media/i2c/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim4c/maxim4c_drv.c index 49b612ba16ca..16d11afb4828 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim4c/maxim4c_drv.c @@ -29,9 +29,10 @@ * V2.03.00 * 1. remote device add the maxim4c prefix to driver name. * - * V2.04.01 + * V2.04.02 * 1. Add regulator supplier dependencies. * 2. Add config ssc-ratio property + * 3. Add debugfs entry to change MIPI timing * */ #include @@ -62,7 +63,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x01) +#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x02) #define MAXIM4C_XVCLK_FREQ 25000000 @@ -713,15 +714,19 @@ static int maxim4c_probe(struct i2c_client *client, maxim4c_module_data_init(maxim4c); maxim4c_module_parse_dt(maxim4c); + ret = maxim4c_dbgfs_init(maxim4c); + if (ret) + goto err_subdev_deinit; + #if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0) ret = maxim4c_module_hw_init(maxim4c); if (ret) - goto err_subdev_deinit; + goto err_dbgfs_deinit; #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ ret = maxim4c_remote_mfd_add_devices(maxim4c); if (ret) - goto err_subdev_deinit; + goto err_dbgfs_deinit; maxim4c_lock_irq_init(maxim4c); maxim4c_lock_state_work_init(maxim4c); @@ -732,6 +737,8 @@ static int maxim4c_probe(struct i2c_client *client, return 0; +err_dbgfs_deinit: + maxim4c_dbgfs_deinit(maxim4c); err_subdev_deinit: maxim4c_v4l2_subdev_deinit(maxim4c); err_power_off: @@ -748,6 +755,8 @@ static int maxim4c_remove(struct i2c_client *client) maxim4c_lock_state_work_deinit(maxim4c); + maxim4c_dbgfs_deinit(maxim4c); + maxim4c_v4l2_subdev_deinit(maxim4c); mutex_destroy(&maxim4c->mutex); diff --git a/drivers/media/i2c/maxim4c/maxim4c_drv.h b/drivers/media/i2c/maxim4c/maxim4c_drv.h index 7ba49d42af4d..d4542e15eeb2 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_drv.h +++ b/drivers/media/i2c/maxim4c/maxim4c_drv.h @@ -108,6 +108,8 @@ typedef struct maxim4c { struct mfd_cell remote_mfd_devs[MAXIM4C_LINK_ID_MAX]; maxim4c_remote_t *remote_device[MAXIM4C_LINK_ID_MAX]; + + struct dentry *dbgfs_root; } maxim4c_t; #endif /* __MAXIM4C_DRV_H__ */ diff --git a/drivers/media/i2c/maxim4c/maxim4c_mipi_txphy.c b/drivers/media/i2c/maxim4c/maxim4c_mipi_txphy.c index af5071a6b586..8776401149fb 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_mipi_txphy.c +++ b/drivers/media/i2c/maxim4c/maxim4c_mipi_txphy.c @@ -11,6 +11,82 @@ #include "maxim4c_api.h" +static int maxim4c_txphy_init_timing(maxim4c_t *maxim4c) +{ + struct i2c_client *client = maxim4c->client; + int ret = 0; + u16 reg_addr = 0; + u8 reg_mask; + u8 timing; + u8 phy_idx = 0; + + if (!maxim4c->mipi_txphy.timing_override_en) + return 0; + + timing = ((maxim4c->mipi_txphy.timing.t_hs_przero & 0x3) << 6 | + (maxim4c->mipi_txphy.timing.t_hs_prep & 0x3) << 4 | + (maxim4c->mipi_txphy.timing.t_clk_trail & 0x3) << 2 | + (maxim4c->mipi_txphy.timing.t_clk_przero & 0x3) << 0); + + ret |= maxim4c_i2c_write_byte(client, 0x08A1, + MAXIM4C_I2C_REG_ADDR_16BITS, timing); + + reg_mask = 0x0F; + timing = ((maxim4c->mipi_txphy.timing.t_lpx & 0x3) << 2 | + (maxim4c->mipi_txphy.timing.t_hs_trail & 0x3) << 0); + + ret |= maxim4c_i2c_update_byte( + client, 0x08A2, MAXIM4C_I2C_REG_ADDR_16BITS, reg_mask, timing); + + reg_mask = (0x3 << 6); + timing = (maxim4c->mipi_txphy.timing.t_lpxesc & 0x3) << 6; + ret |= maxim4c_i2c_update_byte( + client, 0x08A5, MAXIM4C_I2C_REG_ADDR_16BITS, reg_mask, timing); + + reg_mask = (0x7 << 5); + timing = (maxim4c->mipi_txphy.timing.t_lpxesc & 0x7) << 5; + ret |= maxim4c_i2c_update_byte( + client, 0x08A8, MAXIM4C_I2C_REG_ADDR_16BITS, reg_mask, timing); + + for (phy_idx = 0; phy_idx < MAXIM4C_TXPHY_ID_MAX; phy_idx++) { + reg_mask = 0xFF; + reg_addr = 0x0905 + 0x40 * phy_idx; + timing = maxim4c->mipi_txphy.timing.csi2_t_pre; + ret |= maxim4c_i2c_update_byte(client, reg_addr, + MAXIM4C_I2C_REG_ADDR_16BITS, + reg_mask, timing); + + reg_addr = 0x0906 + 0x40 * phy_idx; + timing = maxim4c->mipi_txphy.timing.csi2_t_post; + ret |= maxim4c_i2c_update_byte(client, reg_addr, + MAXIM4C_I2C_REG_ADDR_16BITS, + reg_mask, timing); + + reg_addr = 0x0907 + 0x40 * phy_idx; + timing = maxim4c->mipi_txphy.timing.csi2_tx_gap; + ret |= maxim4c_i2c_update_byte(client, reg_addr, + MAXIM4C_I2C_REG_ADDR_16BITS, + reg_mask, timing); + + reg_addr = 0x0908 + 0x40 * phy_idx; + timing = maxim4c->mipi_txphy.timing.csi2_twakeup & 0xFF; + ret |= maxim4c_i2c_update_byte(client, reg_addr, + MAXIM4C_I2C_REG_ADDR_16BITS, + reg_mask, timing); + timing = (maxim4c->mipi_txphy.timing.csi2_twakeup >> 8) & 0xFF; + ret |= maxim4c_i2c_update_byte(client, reg_addr + 1, + MAXIM4C_I2C_REG_ADDR_16BITS, + reg_mask, timing); + reg_mask = 0x7; + timing = (maxim4c->mipi_txphy.timing.csi2_twakeup >> 16) & 0x7; + ret |= maxim4c_i2c_update_byte(client, reg_addr + 2, + MAXIM4C_I2C_REG_ADDR_16BITS, + reg_mask, timing); + } + + return ret; +} + static int maxim4c_txphy_auto_init_deskew(maxim4c_t *maxim4c) { struct i2c_client *client = maxim4c->client; @@ -521,6 +597,9 @@ int maxim4c_mipi_txphy_hw_init(maxim4c_t *maxim4c) // mipi txphy auto init deskew ret |= maxim4c_txphy_auto_init_deskew(maxim4c); + // mipi txphy timing init + ret |= maxim4c_txphy_init_timing(maxim4c); + if (ret) { dev_err(dev, "%s: txphy hw init error\n", __func__); return ret; @@ -540,6 +619,11 @@ void maxim4c_mipi_txphy_data_init(maxim4c_t *maxim4c) mipi_txphy->force_clock_out_en = 1; mipi_txphy->force_clk0_en = 0; mipi_txphy->force_clk3_en = 0; + mipi_txphy->timing.t_lpx = 1; + mipi_txphy->timing.csi2_t_pre = 0x71; + mipi_txphy->timing.csi2_t_post = 0x19; + mipi_txphy->timing.csi2_tx_gap = 0x1C; + mipi_txphy->timing.csi2_twakeup = 0x100; for (i = 0; i < MAXIM4C_TXPHY_ID_MAX; i++) { phy_cfg = &mipi_txphy->phy_cfg[i]; diff --git a/drivers/media/i2c/maxim4c/maxim4c_mipi_txphy.h b/drivers/media/i2c/maxim4c/maxim4c_mipi_txphy.h index 901d0aa66c86..29416be78a82 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_mipi_txphy.h +++ b/drivers/media/i2c/maxim4c/maxim4c_mipi_txphy.h @@ -56,12 +56,46 @@ struct maxim4c_txphy_cfg { u8 ssc_ratio; }; +struct maxim4c_txphy_timing { + /* 0x8A1 */ + u8 t_hs_przero; + u8 t_hs_prep; + u8 t_clk_trail; + u8 t_clk_przero; + + /* 0x8A2 */ + u8 t_lpx; + u8 t_hs_trail; + + /* 0x8A5 */ + u8 t_clk_prep; + + /* 0x8A8 */ + u8 t_lpxesc; + + /* 0x8AE */ + u8 t_t3_post; + u8 t_t3_prep; + + /* 0x905 */ + u8 csi2_t_pre; + /* 0x906 */ + u8 csi2_t_post; + /* 0x907 */ + u8 csi2_tx_gap; + /* 0x908,0x909,0x90A */ + u32 csi2_twakeup; +}; + typedef struct maxim4c_mipi_txphy { u8 phy_mode; /* mipi txphy mode */ u8 force_clock_out_en; /* Force all MIPI clocks running */ u8 force_clk0_en; /* DPHY0 enabled as clock */ u8 force_clk3_en; /* DPHY3 enabled as clock */ + u8 timing_override_en; + struct maxim4c_txphy_timing timing; + struct maxim4c_txphy_cfg phy_cfg[MAXIM4C_TXPHY_ID_MAX]; } maxim4c_mipi_txphy_t;