mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
media: i2c: maxim4c: Add debugfs entry to change MIPI timing
Change-Id: I3e215583975e7272ca1c655dc61a59abc6c07d4e Signed-off-by: Cody Xie <cody.xie@rock-chips.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
60
drivers/media/i2c/maxim4c/maxim4c_debugfs.c
Normal file
60
drivers/media/i2c/maxim4c/maxim4c_debugfs.c
Normal file
@@ -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 <cwz@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#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);
|
||||
@@ -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 <linux/clk.h>
|
||||
@@ -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);
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user