Skip to content

Commit 0595d86

Browse files
notropopcornmix
authored andcommitted
i2c: bcm2835: Add debug support
This adds a debug module parameter to aid in debugging transfer issues by printing info to the kernel log. When enabled, status values are collected in the interrupt routine and msg info in bcm2835_i2c_start_transfer(). This is done in a way that tries to avoid affecting timing. Having printk in the isr can mask issues. debug values (additive): 1: Print info on error 2: Print info on all transfers 3: Print messages before transfer is started The value can be changed at runtime: /sys/module/i2c_bcm2835/parameters/debug Example output, debug=3: [ 747.114448] bcm2835_i2c_xfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1] [ 747.114463] bcm2835_i2c_xfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1] [ 747.117809] start_transfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1] [ 747.117825] isr: remain=2, status=0x30000055 : TA TXW TXD TXE [i2c1] [ 747.117839] start_transfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1] [ 747.117849] isr: remain=32, status=0xd0000039 : TA RXR TXD RXD [i2c1] [ 747.117861] isr: remain=20, status=0xd0000039 : TA RXR TXD RXD [i2c1] [ 747.117870] isr: remain=8, status=0x32 : DONE TXD RXD [i2c1] Signed-off-by: Noralf Trønnes <[email protected]>
1 parent 01c1789 commit 0595d86

File tree

1 file changed

+98
-1
lines changed

1 file changed

+98
-1
lines changed

drivers/i2c/busses/i2c-bcm2835.c

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@
5353
#define BCM2835_I2C_CDIV_MIN 0x0002
5454
#define BCM2835_I2C_CDIV_MAX 0xFFFE
5555

56+
static unsigned int debug;
57+
module_param(debug, uint, 0644);
58+
MODULE_PARM_DESC(debug, "1=err, 2=isr, 3=xfer");
59+
60+
#define BCM2835_DEBUG_MAX 512
61+
struct bcm2835_debug {
62+
struct i2c_msg *msg;
63+
int msg_idx;
64+
size_t remain;
65+
u32 status;
66+
};
67+
5668
struct bcm2835_i2c_dev {
5769
struct device *dev;
5870
void __iomem *regs;
@@ -66,8 +78,78 @@ struct bcm2835_i2c_dev {
6678
u32 msg_err;
6779
u8 *msg_buf;
6880
size_t msg_buf_remaining;
81+
struct bcm2835_debug debug[BCM2835_DEBUG_MAX];
82+
unsigned int debug_num;
83+
unsigned int debug_num_msgs;
6984
};
7085

86+
static inline void bcm2835_debug_add(struct bcm2835_i2c_dev *i2c_dev, u32 s)
87+
{
88+
if (!i2c_dev->debug_num_msgs || i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
89+
return;
90+
91+
i2c_dev->debug[i2c_dev->debug_num].msg = i2c_dev->curr_msg;
92+
i2c_dev->debug[i2c_dev->debug_num].msg_idx =
93+
i2c_dev->debug_num_msgs - i2c_dev->num_msgs;
94+
i2c_dev->debug[i2c_dev->debug_num].remain = i2c_dev->msg_buf_remaining;
95+
i2c_dev->debug[i2c_dev->debug_num].status = s;
96+
i2c_dev->debug_num++;
97+
}
98+
99+
static void bcm2835_debug_print_status(struct bcm2835_i2c_dev *i2c_dev,
100+
struct bcm2835_debug *d)
101+
{
102+
u32 s = d->status;
103+
104+
pr_info("isr: remain=%zu, status=0x%x : %s%s%s%s%s%s%s%s%s%s [i2c%d]\n",
105+
d->remain, s,
106+
s & BCM2835_I2C_S_TA ? "TA " : "",
107+
s & BCM2835_I2C_S_DONE ? "DONE " : "",
108+
s & BCM2835_I2C_S_TXW ? "TXW " : "",
109+
s & BCM2835_I2C_S_RXR ? "RXR " : "",
110+
s & BCM2835_I2C_S_TXD ? "TXD " : "",
111+
s & BCM2835_I2C_S_RXD ? "RXD " : "",
112+
s & BCM2835_I2C_S_TXE ? "TXE " : "",
113+
s & BCM2835_I2C_S_RXF ? "RXF " : "",
114+
s & BCM2835_I2C_S_ERR ? "ERR " : "",
115+
s & BCM2835_I2C_S_CLKT ? "CLKT " : "",
116+
i2c_dev->adapter.nr);
117+
}
118+
119+
static void bcm2835_debug_print_msg(struct bcm2835_i2c_dev *i2c_dev,
120+
struct i2c_msg *msg, int i, int total,
121+
const char *fname)
122+
{
123+
pr_info("%s: msg(%d/%d) %s addr=0x%02x, len=%u flags=%s%s%s%s%s%s%s [i2c%d]\n",
124+
fname, i, total,
125+
msg->flags & I2C_M_RD ? "read" : "write", msg->addr, msg->len,
126+
msg->flags & I2C_M_TEN ? "TEN" : "",
127+
msg->flags & I2C_M_RECV_LEN ? "RECV_LEN" : "",
128+
msg->flags & I2C_M_NO_RD_ACK ? "NO_RD_ACK" : "",
129+
msg->flags & I2C_M_IGNORE_NAK ? "IGNORE_NAK" : "",
130+
msg->flags & I2C_M_REV_DIR_ADDR ? "REV_DIR_ADDR" : "",
131+
msg->flags & I2C_M_NOSTART ? "NOSTART" : "",
132+
msg->flags & I2C_M_STOP ? "STOP" : "",
133+
i2c_dev->adapter.nr);
134+
}
135+
136+
static void bcm2835_debug_print(struct bcm2835_i2c_dev *i2c_dev)
137+
{
138+
struct bcm2835_debug *d;
139+
unsigned int i;
140+
141+
for (i = 0; i < i2c_dev->debug_num; i++) {
142+
d = &i2c_dev->debug[i];
143+
if (d->status == ~0)
144+
bcm2835_debug_print_msg(i2c_dev, d->msg, d->msg_idx,
145+
i2c_dev->debug_num_msgs, "start_transfer");
146+
else
147+
bcm2835_debug_print_status(i2c_dev, d);
148+
}
149+
if (i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
150+
pr_info("BCM2835_DEBUG_MAX reached\n");
151+
}
152+
71153
static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev,
72154
u32 reg, u32 val)
73155
{
@@ -170,6 +252,7 @@ static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev)
170252
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
171253
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
172254
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
255+
bcm2835_debug_add(i2c_dev, ~0);
173256
}
174257

175258
/*
@@ -187,6 +270,7 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
187270
u32 val, err;
188271

189272
val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
273+
bcm2835_debug_add(i2c_dev, val);
190274

191275
err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
192276
if (err) {
@@ -251,6 +335,13 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
251335
unsigned long time_left;
252336
int i, ret;
253337

338+
if (debug)
339+
i2c_dev->debug_num_msgs = num;
340+
341+
if (debug > 2)
342+
for (i = 0; i < num; i++)
343+
bcm2835_debug_print_msg(i2c_dev, &msgs[i], i + 1, num, __func__);
344+
254345
for (i = 0; i < (num - 1); i++)
255346
if (msgs[i].flags & I2C_M_RD) {
256347
dev_warn_once(i2c_dev->dev,
@@ -270,6 +361,10 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
270361

271362
time_left = wait_for_completion_timeout(&i2c_dev->completion,
272363
adap->timeout);
364+
if (debug > 1 || (debug && (!time_left || i2c_dev->msg_err)))
365+
bcm2835_debug_print(i2c_dev);
366+
i2c_dev->debug_num_msgs = 0;
367+
i2c_dev->debug_num = 0;
273368
if (!time_left) {
274369
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
275370
BCM2835_I2C_C_CLEAR);
@@ -280,7 +375,9 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
280375
if (!i2c_dev->msg_err)
281376
return num;
282377

283-
dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
378+
if (debug)
379+
dev_err(i2c_dev->dev, "i2c transfer failed: %x\n",
380+
i2c_dev->msg_err);
284381

285382
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
286383
return -EREMOTEIO;

0 commit comments

Comments
 (0)