summaryrefslogtreecommitdiff
path: root/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.c
blob: 20969c76db46371d14b0a3a182b6536e7b7a4c98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// SPDX-License-Identifier: GPL-2.0

/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
 *
 * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
 */

#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/seq_file.h>

#include "mcp25xxfd_cmd.h"
#include "mcp25xxfd_debugfs.h"
#include "mcp25xxfd_priv.h"

static int mcp25xxfd_debugfs_dump_regs_range(struct seq_file *file,
					     u32 start, u32 end)
{
	struct spi_device *spi = file->private;
	u32 data[32];
	int bytes = end - start + sizeof(*data);
	int i, l, count, ret;

	for (count =  bytes / sizeof(*data); count > 0; count -= 32) {
		/* read up to 32 registers in one go */
		l = min(count, 32);
		ret = mcp25xxfd_cmd_read_regs(spi, start,
					      data, l * sizeof(*data));
		if (ret)
			return ret;
		/* dump those read registers */
		for (i = 0; i < l; i++, start += sizeof(*data))
			seq_printf(file, "Reg 0x%03x = 0x%08x\n",
				   start, data[i]);
	}

	return 0;
}

static int mcp25xxfd_debugfs_dump_regs(struct seq_file *file, void *offset)
{
	return mcp25xxfd_debugfs_dump_regs_range(file, MCP25XXFD_OSC,
						 MCP25XXFD_DEVID);
}

static int mcp25xxfd_debugfs_dump_can_regs(struct seq_file *file,
					   void *offset)
{
	return mcp25xxfd_debugfs_dump_regs_range(file, MCP25XXFD_CAN_CON,
						 MCP25XXFD_CAN_TXQUA);
}

static int mcp25xxfd_debugfs_dump_can_all_regs(struct seq_file *file,
					       void *offset)
{
	return mcp25xxfd_debugfs_dump_regs_range(file, MCP25XXFD_CAN_CON,
						 MCP25XXFD_CAN_FLTMASK(31));
}

static void mcp25xxfd_debugfs_mod_setup(struct mcp25xxfd_priv *priv)
{
	struct dentry *root, *regs;

	/* the base directory */
	priv->debugfs_dir = debugfs_create_dir(priv->device_name, NULL);
	root = priv->debugfs_dir;

	/* expose some parameters related to clocks */
	debugfs_create_u32("spi_setup_speed_hz", 0644, root,
			   &priv->spi_setup_speed_hz);
	debugfs_create_u32("spi_normal_speed_hz", 0644, root,
			   &priv->spi_normal_speed_hz);
	debugfs_create_u32("spi_use_speed_hz", 0644, root,
			   &priv->spi_use_speed_hz);
	debugfs_create_u32("clk_user_mask", 0444, root, &priv->clk_user_mask);

	/* some statistics */
	debugfs_create_u64("spi_crc_read", 0444, root,
			   &priv->stats.spi_crc_read);
	debugfs_create_u64("spi_crc_read_split", 0444, root,
			   &priv->stats.spi_crc_read_split);

	/* expose the system registers */
	priv->debugfs_regs_dir = debugfs_create_dir("regs", root);
	regs = priv->debugfs_regs_dir;
	debugfs_create_x32("osc", 0444, regs, &priv->regs.osc);
	debugfs_create_x32("iocon", 0444, regs, &priv->regs.iocon);
	debugfs_create_x32("crc", 0444, regs, &priv->regs.crc);
	debugfs_create_x32("ecccon", 0444, regs, &priv->regs.ecccon);

	/* dump the controller registers themselves */
	debugfs_create_devm_seqfile(&priv->spi->dev, "regs_live_dump",
				    root, mcp25xxfd_debugfs_dump_regs);
	/* and the essential can registers */
	debugfs_create_devm_seqfile(&priv->spi->dev, "can_regs_live_dump",
				    root, mcp25xxfd_debugfs_dump_can_regs);
	/* and the complete can registers */
	debugfs_create_devm_seqfile(&priv->spi->dev,
				    "can_regs_all_live_dump", root,
				    mcp25xxfd_debugfs_dump_can_all_regs);
}

void mcp25xxfd_debugfs_setup(struct mcp25xxfd_priv *priv)
{
	mcp25xxfd_debugfs_mod_setup(priv);
}

void mcp25xxfd_debugfs_remove(struct mcp25xxfd_priv *priv)
{
	debugfs_remove_recursive(priv->debugfs_dir);
	priv->debugfs_dir = NULL;
}