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;
}
|