1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * I2C slave mode testunit 4 * 5 * Copyright (C) 2020 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com> 6 * Copyright (C) 2020 by Renesas Electronics Corporation 7 */ 8 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> 16 #include <linux/of.h> 17 #include <linux/slab.h> 18 #include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */ 19 20 #define TU_VERSION_MAX_LENGTH 128 21 22 enum testunit_cmds { 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, 28 TU_NUM_CMDS 29 }; 30 31 enum testunit_regs { 32 TU_REG_CMD, 33 TU_REG_DATAL, 34 TU_REG_DATAH, 35 TU_REG_DELAY, 36 TU_NUM_REGS 37 }; 38 39 enum testunit_flags { 40 TU_FLAG_IN_PROCESS, 41 }; 42 43 struct testunit_data { 44 unsigned long flags; 45 u8 regs[TU_NUM_REGS]; 46 u8 reg_idx; 47 u8 read_idx; 48 struct i2c_client *client; 49 struct delayed_work worker; 50 struct gpio_desc *gpio; 51 struct completion alert_done; 52 }; 53 54 static char tu_version_info[] = "v" UTS_RELEASE "\n\0"; 55 56 static int i2c_slave_testunit_smbalert_cb(struct i2c_client *client, 57 enum i2c_slave_event event, u8 *val) 58 { 59 struct testunit_data *tu = i2c_get_clientdata(client); 60 61 switch (event) { 62 case I2C_SLAVE_READ_PROCESSED: 63 gpiod_set_value(tu->gpio, 0); 64 fallthrough; 65 case I2C_SLAVE_READ_REQUESTED: 66 *val = tu->regs[TU_REG_DATAL]; 67 break; 68 69 case I2C_SLAVE_STOP: 70 complete(&tu->alert_done); 71 break; 72 73 case I2C_SLAVE_WRITE_REQUESTED: 74 case I2C_SLAVE_WRITE_RECEIVED: 75 return -EOPNOTSUPP; 76 } 77 78 return 0; 79 } 80 81 static int i2c_slave_testunit_slave_cb(struct i2c_client *client, 82 enum i2c_slave_event event, u8 *val) 83 { 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; 89 int ret = 0; 90 91 switch (event) { 92 case I2C_SLAVE_WRITE_REQUESTED: 93 if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags)) 94 return -EBUSY; 95 96 memset(tu->regs, 0, TU_NUM_REGS); 97 tu->reg_idx = 0; 98 tu->read_idx = 0; 99 break; 100 101 case I2C_SLAVE_WRITE_RECEIVED: 102 if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags)) 103 return -EBUSY; 104 105 if (tu->reg_idx < TU_NUM_REGS) 106 tu->regs[tu->reg_idx] = *val; 107 else 108 ret = -EMSGSIZE; 109 110 if (tu->reg_idx <= TU_NUM_REGS) 111 tu->reg_idx++; 112 113 /* TU_REG_CMD always written at this point */ 114 if (tu->regs[TU_REG_CMD] >= TU_NUM_CMDS) 115 ret = -EINVAL; 116 117 break; 118 119 case I2C_SLAVE_STOP: 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])); 124 } 125 126 /* 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! 130 */ 131 tu->reg_idx = 0; 132 break; 133 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) 137 tu->read_idx++; 138 else if (is_proc_call && tu->regs[TU_REG_DATAH]) 139 tu->regs[TU_REG_DATAH]--; 140 141 fallthrough; 142 143 case I2C_SLAVE_READ_REQUESTED: 144 if (is_get_version) 145 *val = tu_version_info[tu->read_idx]; 146 else if (is_proc_call) 147 *val = tu->regs[TU_REG_DATAH]; 148 else 149 *val = test_bit(TU_FLAG_IN_PROCESS, &tu->flags) ? 150 tu->regs[TU_REG_CMD] : 0; 151 break; 152 } 153 154 return ret; 155 } 156 157 static void i2c_slave_testunit_work(struct work_struct *work) 158 { 159 struct testunit_data *tu = container_of(work, struct testunit_data, worker.work); 160 unsigned long time_left; 161 struct i2c_msg msg; 162 u8 msgbuf[256]; 163 u16 orig_addr; 164 int ret = 0; 165 166 msg.addr = I2C_CLIENT_END; 167 msg.buf = msgbuf; 168 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]; 174 break; 175 176 case TU_CMD_SMBUS_HOST_NOTIFY: 177 msg.addr = 0x08; 178 msg.flags = 0; 179 msg.len = 3; 180 msgbuf[0] = tu->client->addr; 181 msgbuf[1] = tu->regs[TU_REG_DATAL]; 182 msgbuf[2] = tu->regs[TU_REG_DATAH]; 183 break; 184 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); 190 if (ret) 191 goto out_smbalert; 192 193 reinit_completion(&tu->alert_done); 194 gpiod_set_value(tu->gpio, 1); 195 time_left = wait_for_completion_timeout(&tu->alert_done, HZ); 196 if (!time_left) 197 ret = -ETIMEDOUT; 198 199 i2c_slave_unregister(tu->client); 200 out_smbalert: 201 tu->client->addr = orig_addr; 202 i2c_slave_register(tu->client, i2c_slave_testunit_slave_cb); 203 break; 204 205 default: 206 break; 207 } 208 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; 213 } 214 215 if (ret < 0) 216 dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret); 217 218 clear_bit(TU_FLAG_IN_PROCESS, &tu->flags); 219 } 220 221 static int i2c_slave_testunit_probe(struct i2c_client *client) 222 { 223 struct testunit_data *tu; 224 225 tu = devm_kzalloc(&client->dev, sizeof(struct testunit_data), GFP_KERNEL); 226 if (!tu) 227 return -ENOMEM; 228 229 tu->client = client; 230 i2c_set_clientdata(client, tu); 231 init_completion(&tu->alert_done); 232 INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work); 233 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"); 237 return -EDEADLK; 238 } 239 240 if (sizeof(tu_version_info) > TU_VERSION_MAX_LENGTH) 241 tu_version_info[TU_VERSION_MAX_LENGTH - 1] = 0; 242 243 return i2c_slave_register(client, i2c_slave_testunit_slave_cb); 244 }; 245 246 static void i2c_slave_testunit_remove(struct i2c_client *client) 247 { 248 struct testunit_data *tu = i2c_get_clientdata(client); 249 250 cancel_delayed_work_sync(&tu->worker); 251 i2c_slave_unregister(client); 252 } 253 254 static const struct i2c_device_id i2c_slave_testunit_id[] = { 255 { "slave-testunit" }, 256 { } 257 }; 258 MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id); 259 260 static struct i2c_driver i2c_slave_testunit_driver = { 261 .driver = { 262 .name = "i2c-slave-testunit", 263 }, 264 .probe = i2c_slave_testunit_probe, 265 .remove = i2c_slave_testunit_remove, 266 .id_table = i2c_slave_testunit_id, 267 }; 268 module_i2c_driver(i2c_slave_testunit_driver); 269 270 MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>"); 271 MODULE_DESCRIPTION("I2C slave mode test unit"); 272 MODULE_LICENSE("GPL v2"); 273