From f6920cb1efa85caa917fa7a8433c87ed9defc8a0 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Tue, 19 Dec 2023 17:32:35 +0800 Subject: [PATCH] misc: rk628: add register debugfs node This patch adds support for register debugfs nodes to allow access to the registers without modifying the regmap subsystem configuration. An example output is as follows: $ ls /d/rk628/2-0050/registers adapter combtxphy csi dsi1 gpio0 gpio2 grf hdmi combrxphy cru dsi0 efuse gpio1 gpio3 gvi hdmirx dump register: $ cat cru write to register: $ echo addr val > cru Additionally, incorrect GVI regmap_range was fixed. Because `GVI_COLOR_BAR_VTIMING1` is already defined as `GVI_BASE + 0x7C` Change-Id: I3f19d02b5119958fe2dafd04dff5efcc4d28d6d0 Signed-off-by: Chaoyi Chen --- drivers/misc/rk628/rk628.c | 126 ++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/drivers/misc/rk628/rk628.c b/drivers/misc/rk628/rk628.c index 5125b98f4a53..7c7e7176e3e6 100644 --- a/drivers/misc/rk628/rk628.c +++ b/drivers/misc/rk628/rk628.c @@ -151,7 +151,7 @@ static const struct regmap_access_table rk628_dsi1_readable_table = { }; static const struct regmap_range rk628_gvi_readable_ranges[] = { - regmap_reg_range(GVI_BASE, GVI_BASE + GVI_COLOR_BAR_VTIMING1), + regmap_reg_range(GVI_BASE, GVI_COLOR_BAR_VTIMING1), }; static const struct regmap_access_table rk628_gvi_readable_table = { @@ -1246,6 +1246,128 @@ static int rk628_version_info(struct rk628 *rk628) return ret; } +static int rk628_reg_show(struct seq_file *s, void *v) +{ + const struct regmap_config *reg; + struct rk628 *rk628 = s->private; + unsigned int i, j; + u32 val; + + seq_printf(s, "rk628_%s:\n", file_dentry(s->file)->d_iname); + + for (i = 0; i < ARRAY_SIZE(rk628_regmap_config); i++) { + reg = &rk628_regmap_config[i]; + if (!reg->name) + continue; + if (!strcmp(reg->name, file_dentry(s->file)->d_iname)) + break; + } + + if (i == ARRAY_SIZE(rk628_regmap_config)) + return -ENODEV; + + /* grf */ + if (!reg->rd_table) { + for (i = 0; i <= reg->max_register; i += 4) { + rk628_i2c_read(rk628, i, &val); + if (i % 16 == 0) + seq_printf(s, "\n0x%04x:", i); + seq_printf(s, " %08x", val); + } + } else { + const struct regmap_range *range_list = reg->rd_table->yes_ranges; + const struct regmap_range *range; + int range_list_len = reg->rd_table->n_yes_ranges; + + for (i = 0; i < range_list_len; i++) { + range = &range_list[i]; + for (j = range->range_min; j <= range->range_max; j += 4) { + rk628_i2c_read(rk628, j, &val); + if (j % 16 == 0 || j == range->range_min) + seq_printf(s, "\n0x%04x:", j); + seq_printf(s, " %08x", val); + } + } + + seq_puts(s, "\n"); + } + + return 0; +} + +static ssize_t rk628_reg_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + const struct regmap_config *reg; + struct rk628 *rk628 = file->f_path.dentry->d_inode->i_private; + int i; + u32 addr; + u32 val; + char kbuf[25]; + int ret; + + if (count >= sizeof(kbuf)) + return -ENOSPC; + + if (copy_from_user(kbuf, buf, count)) + return -EFAULT; + + kbuf[count] = '\0'; + + ret = sscanf(kbuf, "%x%x", &addr, &val); + if (ret != 2) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(rk628_regmap_config); i++) { + reg = &rk628_regmap_config[i]; + if (!reg->name) + continue; + if (!strcmp(reg->name, file_dentry(file)->d_iname)) + break; + } + + if (i == ARRAY_SIZE(rk628_regmap_config)) + return -ENODEV; + + rk628_i2c_write(rk628, addr, val); + + return count; +} + +static int rk628_reg_open(struct inode *inode, struct file *file) +{ + struct rk628 *rk628 = inode->i_private; + + return single_open(file, rk628_reg_show, rk628); +} + +static const struct file_operations rk628_reg_fops = { + .owner = THIS_MODULE, + .open = rk628_reg_open, + .read = seq_read, + .write = rk628_reg_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static void rk628_debugfs_register_create(struct rk628 *rk628) +{ + const struct regmap_config *reg; + struct dentry *dir; + int i; + + dir = debugfs_create_dir("registers", rk628->debug_dir); + if (IS_ERR(dir)) + return; + + for (i = 0; i < ARRAY_SIZE(rk628_regmap_config); i++) { + reg = &rk628_regmap_config[i]; + if (!reg->name) + continue; + debugfs_create_file(reg->name, 0600, dir, rk628, &rk628_reg_fops); + } +} + static void rk628_debugfs_create(struct rk628 *rk628) { rk628->debug_dir = debugfs_create_dir(dev_name(rk628->dev), debugfs_lookup("rk628", NULL)); @@ -1256,6 +1378,8 @@ static void rk628_debugfs_create(struct rk628 *rk628) debugfs_create_file("summary", 0400, rk628->debug_dir, rk628, &rk628_debugfs_summary_fops); + rk628_debugfs_register_create(rk628); + rk628_rgb_decoder_create_debugfs_file(rk628); rk628_post_process_create_debugfs_file(rk628); rk628_mipi_dsi_create_debugfs_file(rk628);