1 // SPDX-License-Identifier: GPL-2.0-only
3 * I2C slave mode testunit
5 * Copyright (C) 2020 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
6 * Copyright (C) 2020 by Renesas Electronics Corporation
9 #include <generated/utsrelease.h>
10 #include <linux/bitops.h>
11 #include <linux/completion.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/i2c.h>
14 #include <linux/init.h>
15 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */
20 #define TU_VERSION_MAX_LENGTH 128
23 TU_CMD_READ_BYTES
= 1, /* save 0 for ABORT, RESET or similar */
24 TU_CMD_SMBUS_HOST_NOTIFY
,
25 TU_CMD_SMBUS_BLOCK_PROC_CALL
,
26 TU_CMD_GET_VERSION_WITH_REP_START
,
27 TU_CMD_SMBUS_ALERT_REQUEST
,
43 struct testunit_data
{
48 struct i2c_client
*client
;
49 struct delayed_work worker
;
50 struct gpio_desc
*gpio
;
51 struct completion alert_done
;
54 static char tu_version_info
[] = "v" UTS_RELEASE
"\n\0";
56 static int i2c_slave_testunit_smbalert_cb(struct i2c_client
*client
,
57 enum i2c_slave_event event
, u8
*val
)
59 struct testunit_data
*tu
= i2c_get_clientdata(client
);
62 case I2C_SLAVE_READ_PROCESSED
:
63 gpiod_set_value(tu
->gpio
, 0);
65 case I2C_SLAVE_READ_REQUESTED
:
66 *val
= tu
->regs
[TU_REG_DATAL
];
70 complete(&tu
->alert_done
);
73 case I2C_SLAVE_WRITE_REQUESTED
:
74 case I2C_SLAVE_WRITE_RECEIVED
:
81 static int i2c_slave_testunit_slave_cb(struct i2c_client
*client
,
82 enum i2c_slave_event event
, u8
*val
)
84 struct testunit_data
*tu
= i2c_get_clientdata(client
);
85 bool is_proc_call
= tu
->reg_idx
== 3 && tu
->regs
[TU_REG_DATAL
] == 1 &&
86 tu
->regs
[TU_REG_CMD
] == TU_CMD_SMBUS_BLOCK_PROC_CALL
;
87 bool is_get_version
= tu
->reg_idx
== 3 &&
88 tu
->regs
[TU_REG_CMD
] == TU_CMD_GET_VERSION_WITH_REP_START
;
92 case I2C_SLAVE_WRITE_REQUESTED
:
93 if (test_bit(TU_FLAG_IN_PROCESS
, &tu
->flags
))
96 memset(tu
->regs
, 0, TU_NUM_REGS
);
101 case I2C_SLAVE_WRITE_RECEIVED
:
102 if (test_bit(TU_FLAG_IN_PROCESS
, &tu
->flags
))
105 if (tu
->reg_idx
< TU_NUM_REGS
)
106 tu
->regs
[tu
->reg_idx
] = *val
;
110 if (tu
->reg_idx
<= TU_NUM_REGS
)
113 /* TU_REG_CMD always written at this point */
114 if (tu
->regs
[TU_REG_CMD
] >= TU_NUM_CMDS
)
120 if (tu
->reg_idx
== TU_NUM_REGS
) {
121 set_bit(TU_FLAG_IN_PROCESS
, &tu
->flags
);
122 queue_delayed_work(system_long_wq
, &tu
->worker
,
123 msecs_to_jiffies(10 * tu
->regs
[TU_REG_DELAY
]));
127 * Reset reg_idx to avoid that work gets queued again in case of
128 * STOP after a following read message. But do not clear TU regs
129 * here because we still need them in the workqueue!
134 case I2C_SLAVE_READ_PROCESSED
:
135 /* Advance until we reach the NUL character */
136 if (is_get_version
&& tu_version_info
[tu
->read_idx
] != 0)
138 else if (is_proc_call
&& tu
->regs
[TU_REG_DATAH
])
139 tu
->regs
[TU_REG_DATAH
]--;
143 case I2C_SLAVE_READ_REQUESTED
:
145 *val
= tu_version_info
[tu
->read_idx
];
146 else if (is_proc_call
)
147 *val
= tu
->regs
[TU_REG_DATAH
];
149 *val
= test_bit(TU_FLAG_IN_PROCESS
, &tu
->flags
) ?
150 tu
->regs
[TU_REG_CMD
] : 0;
157 static void i2c_slave_testunit_work(struct work_struct
*work
)
159 struct testunit_data
*tu
= container_of(work
, struct testunit_data
, worker
.work
);
160 unsigned long time_left
;
166 msg
.addr
= I2C_CLIENT_END
;
169 switch (tu
->regs
[TU_REG_CMD
]) {
170 case TU_CMD_READ_BYTES
:
171 msg
.addr
= tu
->regs
[TU_REG_DATAL
];
172 msg
.flags
= I2C_M_RD
;
173 msg
.len
= tu
->regs
[TU_REG_DATAH
];
176 case TU_CMD_SMBUS_HOST_NOTIFY
:
180 msgbuf
[0] = tu
->client
->addr
;
181 msgbuf
[1] = tu
->regs
[TU_REG_DATAL
];
182 msgbuf
[2] = tu
->regs
[TU_REG_DATAH
];
185 case TU_CMD_SMBUS_ALERT_REQUEST
:
186 i2c_slave_unregister(tu
->client
);
187 orig_addr
= tu
->client
->addr
;
188 tu
->client
->addr
= 0x0c;
189 ret
= i2c_slave_register(tu
->client
, i2c_slave_testunit_smbalert_cb
);
193 reinit_completion(&tu
->alert_done
);
194 gpiod_set_value(tu
->gpio
, 1);
195 time_left
= wait_for_completion_timeout(&tu
->alert_done
, HZ
);
199 i2c_slave_unregister(tu
->client
);
201 tu
->client
->addr
= orig_addr
;
202 i2c_slave_register(tu
->client
, i2c_slave_testunit_slave_cb
);
209 if (msg
.addr
!= I2C_CLIENT_END
) {
210 ret
= i2c_transfer(tu
->client
->adapter
, &msg
, 1);
211 /* convert '0 msgs transferred' to errno */
212 ret
= (ret
== 0) ? -EIO
: ret
;
216 dev_err(&tu
->client
->dev
, "CMD%02X failed (%d)\n", tu
->regs
[TU_REG_CMD
], ret
);
218 clear_bit(TU_FLAG_IN_PROCESS
, &tu
->flags
);
221 static int i2c_slave_testunit_probe(struct i2c_client
*client
)
223 struct testunit_data
*tu
;
225 tu
= devm_kzalloc(&client
->dev
, sizeof(struct testunit_data
), GFP_KERNEL
);
230 i2c_set_clientdata(client
, tu
);
231 init_completion(&tu
->alert_done
);
232 INIT_DELAYED_WORK(&tu
->worker
, i2c_slave_testunit_work
);
234 tu
->gpio
= devm_gpiod_get_index_optional(&client
->dev
, NULL
, 0, GPIOD_OUT_LOW
);
235 if (gpiod_cansleep(tu
->gpio
)) {
236 dev_err(&client
->dev
, "GPIO access which may sleep is not allowed\n");
240 if (sizeof(tu_version_info
) > TU_VERSION_MAX_LENGTH
)
241 tu_version_info
[TU_VERSION_MAX_LENGTH
- 1] = 0;
243 return i2c_slave_register(client
, i2c_slave_testunit_slave_cb
);
246 static void i2c_slave_testunit_remove(struct i2c_client
*client
)
248 struct testunit_data
*tu
= i2c_get_clientdata(client
);
250 cancel_delayed_work_sync(&tu
->worker
);
251 i2c_slave_unregister(client
);
254 static const struct i2c_device_id i2c_slave_testunit_id
[] = {
255 { "slave-testunit" },
258 MODULE_DEVICE_TABLE(i2c
, i2c_slave_testunit_id
);
260 static struct i2c_driver i2c_slave_testunit_driver
= {
262 .name
= "i2c-slave-testunit",
264 .probe
= i2c_slave_testunit_probe
,
265 .remove
= i2c_slave_testunit_remove
,
266 .id_table
= i2c_slave_testunit_id
,
268 module_i2c_driver(i2c_slave_testunit_driver
);
270 MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
271 MODULE_DESCRIPTION("I2C slave mode test unit");
272 MODULE_LICENSE("GPL v2");