Lines Matching +full:i2c +full:- +full:slave +full:- +full:addr
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>
13 #include <linux/i2c.h>
64 gpiod_set_value(tu->gpio, 0); in i2c_slave_testunit_smbalert_cb()
67 *val = tu->regs[TU_REG_DATAL]; in i2c_slave_testunit_smbalert_cb()
71 complete(&tu->alert_done); in i2c_slave_testunit_smbalert_cb()
76 return -EOPNOTSUPP; in i2c_slave_testunit_smbalert_cb()
86 bool is_proc_call = tu->reg_idx == 3 && tu->regs[TU_REG_DATAL] == 1 && in i2c_slave_testunit_slave_cb()
87 tu->regs[TU_REG_CMD] == TU_CMD_SMBUS_BLOCK_PROC_CALL; in i2c_slave_testunit_slave_cb()
88 bool is_get_version = tu->reg_idx == 3 && in i2c_slave_testunit_slave_cb()
89 tu->regs[TU_REG_CMD] == TU_CMD_GET_VERSION_WITH_REP_START; in i2c_slave_testunit_slave_cb()
94 if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) { in i2c_slave_testunit_slave_cb()
95 ret = -EBUSY; in i2c_slave_testunit_slave_cb()
99 memset(tu->regs, 0, TU_NUM_REGS); in i2c_slave_testunit_slave_cb()
100 tu->reg_idx = 0; in i2c_slave_testunit_slave_cb()
101 tu->read_idx = 0; in i2c_slave_testunit_slave_cb()
105 if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) { in i2c_slave_testunit_slave_cb()
106 ret = -EBUSY; in i2c_slave_testunit_slave_cb()
110 if (tu->reg_idx < TU_NUM_REGS) in i2c_slave_testunit_slave_cb()
111 tu->regs[tu->reg_idx] = *val; in i2c_slave_testunit_slave_cb()
113 ret = -EMSGSIZE; in i2c_slave_testunit_slave_cb()
115 if (tu->reg_idx <= TU_NUM_REGS) in i2c_slave_testunit_slave_cb()
116 tu->reg_idx++; in i2c_slave_testunit_slave_cb()
119 if (tu->regs[TU_REG_CMD] >= TU_NUM_CMDS) in i2c_slave_testunit_slave_cb()
120 ret = -EINVAL; in i2c_slave_testunit_slave_cb()
125 if (tu->reg_idx == TU_NUM_REGS) { in i2c_slave_testunit_slave_cb()
126 set_bit(TU_FLAG_IN_PROCESS, &tu->flags); in i2c_slave_testunit_slave_cb()
127 queue_delayed_work(system_long_wq, &tu->worker, in i2c_slave_testunit_slave_cb()
128 msecs_to_jiffies(10 * tu->regs[TU_REG_DELAY])); in i2c_slave_testunit_slave_cb()
136 tu->reg_idx = 0; in i2c_slave_testunit_slave_cb()
138 clear_bit(TU_FLAG_NACK, &tu->flags); in i2c_slave_testunit_slave_cb()
143 if (is_get_version && tu_version_info[tu->read_idx] != 0) in i2c_slave_testunit_slave_cb()
144 tu->read_idx++; in i2c_slave_testunit_slave_cb()
145 else if (is_proc_call && tu->regs[TU_REG_DATAH]) in i2c_slave_testunit_slave_cb()
146 tu->regs[TU_REG_DATAH]--; in i2c_slave_testunit_slave_cb()
152 *val = tu_version_info[tu->read_idx]; in i2c_slave_testunit_slave_cb()
154 *val = tu->regs[TU_REG_DATAH]; in i2c_slave_testunit_slave_cb()
156 *val = test_bit(TU_FLAG_IN_PROCESS, &tu->flags) ? in i2c_slave_testunit_slave_cb()
157 tu->regs[TU_REG_CMD] : 0; in i2c_slave_testunit_slave_cb()
163 set_bit(TU_FLAG_NACK, &tu->flags); in i2c_slave_testunit_slave_cb()
177 msg.addr = I2C_CLIENT_END; in i2c_slave_testunit_work()
180 switch (tu->regs[TU_REG_CMD]) { in i2c_slave_testunit_work()
182 msg.addr = tu->regs[TU_REG_DATAL]; in i2c_slave_testunit_work()
184 msg.len = tu->regs[TU_REG_DATAH]; in i2c_slave_testunit_work()
188 msg.addr = 0x08; in i2c_slave_testunit_work()
191 msgbuf[0] = tu->client->addr; in i2c_slave_testunit_work()
192 msgbuf[1] = tu->regs[TU_REG_DATAL]; in i2c_slave_testunit_work()
193 msgbuf[2] = tu->regs[TU_REG_DATAH]; in i2c_slave_testunit_work()
197 if (!tu->gpio) { in i2c_slave_testunit_work()
198 ret = -ENOENT; in i2c_slave_testunit_work()
201 i2c_slave_unregister(tu->client); in i2c_slave_testunit_work()
202 orig_addr = tu->client->addr; in i2c_slave_testunit_work()
203 tu->client->addr = 0x0c; in i2c_slave_testunit_work()
204 ret = i2c_slave_register(tu->client, i2c_slave_testunit_smbalert_cb); in i2c_slave_testunit_work()
208 reinit_completion(&tu->alert_done); in i2c_slave_testunit_work()
209 gpiod_set_value(tu->gpio, 1); in i2c_slave_testunit_work()
210 time_left = wait_for_completion_timeout(&tu->alert_done, HZ); in i2c_slave_testunit_work()
212 ret = -ETIMEDOUT; in i2c_slave_testunit_work()
214 i2c_slave_unregister(tu->client); in i2c_slave_testunit_work()
216 tu->client->addr = orig_addr; in i2c_slave_testunit_work()
217 i2c_slave_register(tu->client, i2c_slave_testunit_slave_cb); in i2c_slave_testunit_work()
224 if (msg.addr != I2C_CLIENT_END) { in i2c_slave_testunit_work()
225 ret = i2c_transfer(tu->client->adapter, &msg, 1); in i2c_slave_testunit_work()
227 ret = (ret == 0) ? -EIO : ret; in i2c_slave_testunit_work()
231 dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret); in i2c_slave_testunit_work()
233 clear_bit(TU_FLAG_IN_PROCESS, &tu->flags); in i2c_slave_testunit_work()
240 tu = devm_kzalloc(&client->dev, sizeof(struct testunit_data), GFP_KERNEL); in i2c_slave_testunit_probe()
242 return -ENOMEM; in i2c_slave_testunit_probe()
244 tu->client = client; in i2c_slave_testunit_probe()
246 init_completion(&tu->alert_done); in i2c_slave_testunit_probe()
247 INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work); in i2c_slave_testunit_probe()
249 tu->gpio = devm_gpiod_get_index_optional(&client->dev, NULL, 0, GPIOD_OUT_LOW); in i2c_slave_testunit_probe()
250 if (IS_ERR(tu->gpio)) in i2c_slave_testunit_probe()
251 return PTR_ERR(tu->gpio); in i2c_slave_testunit_probe()
253 if (gpiod_cansleep(tu->gpio)) { in i2c_slave_testunit_probe()
254 dev_err(&client->dev, "GPIO access which may sleep is not allowed\n"); in i2c_slave_testunit_probe()
255 return -EDEADLK; in i2c_slave_testunit_probe()
259 tu_version_info[TU_VERSION_MAX_LENGTH - 1] = 0; in i2c_slave_testunit_probe()
268 cancel_delayed_work_sync(&tu->worker); in i2c_slave_testunit_remove()
273 { "slave-testunit" },
276 MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id);
280 .name = "i2c-slave-testunit",
288 MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
289 MODULE_DESCRIPTION("I2C slave mode test unit");