0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/bitops.h>
0010 #include <linux/i2c.h>
0011 #include <linux/init.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/slab.h>
0015 #include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */
0016
0017 #define TU_CUR_VERSION 0x01
0018
0019 enum testunit_cmds {
0020 TU_CMD_READ_BYTES = 1,
0021 TU_CMD_HOST_NOTIFY,
0022 TU_CMD_SMBUS_BLOCK_PROC_CALL,
0023 TU_NUM_CMDS
0024 };
0025
0026 enum testunit_regs {
0027 TU_REG_CMD,
0028 TU_REG_DATAL,
0029 TU_REG_DATAH,
0030 TU_REG_DELAY,
0031 TU_NUM_REGS
0032 };
0033
0034 enum testunit_flags {
0035 TU_FLAG_IN_PROCESS,
0036 };
0037
0038 struct testunit_data {
0039 unsigned long flags;
0040 u8 regs[TU_NUM_REGS];
0041 u8 reg_idx;
0042 struct i2c_client *client;
0043 struct delayed_work worker;
0044 };
0045
0046 static void i2c_slave_testunit_work(struct work_struct *work)
0047 {
0048 struct testunit_data *tu = container_of(work, struct testunit_data, worker.work);
0049 struct i2c_msg msg;
0050 u8 msgbuf[256];
0051 int ret = 0;
0052
0053 msg.addr = I2C_CLIENT_END;
0054 msg.buf = msgbuf;
0055
0056 switch (tu->regs[TU_REG_CMD]) {
0057 case TU_CMD_READ_BYTES:
0058 msg.addr = tu->regs[TU_REG_DATAL];
0059 msg.flags = I2C_M_RD;
0060 msg.len = tu->regs[TU_REG_DATAH];
0061 break;
0062
0063 case TU_CMD_HOST_NOTIFY:
0064 msg.addr = 0x08;
0065 msg.flags = 0;
0066 msg.len = 3;
0067 msgbuf[0] = tu->client->addr;
0068 msgbuf[1] = tu->regs[TU_REG_DATAL];
0069 msgbuf[2] = tu->regs[TU_REG_DATAH];
0070 break;
0071
0072 default:
0073 break;
0074 }
0075
0076 if (msg.addr != I2C_CLIENT_END) {
0077 ret = i2c_transfer(tu->client->adapter, &msg, 1);
0078
0079 ret = (ret == 0) ? -EIO : ret;
0080 }
0081
0082 if (ret < 0)
0083 dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret);
0084
0085 clear_bit(TU_FLAG_IN_PROCESS, &tu->flags);
0086 }
0087
0088 static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
0089 enum i2c_slave_event event, u8 *val)
0090 {
0091 struct testunit_data *tu = i2c_get_clientdata(client);
0092 bool is_proc_call = tu->reg_idx == 3 && tu->regs[TU_REG_DATAL] == 1 &&
0093 tu->regs[TU_REG_CMD] == TU_CMD_SMBUS_BLOCK_PROC_CALL;
0094 int ret = 0;
0095
0096 switch (event) {
0097 case I2C_SLAVE_WRITE_RECEIVED:
0098 if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
0099 return -EBUSY;
0100
0101 if (tu->reg_idx < TU_NUM_REGS)
0102 tu->regs[tu->reg_idx] = *val;
0103 else
0104 ret = -EMSGSIZE;
0105
0106 if (tu->reg_idx <= TU_NUM_REGS)
0107 tu->reg_idx++;
0108
0109
0110 if (tu->regs[TU_REG_CMD] >= TU_NUM_CMDS)
0111 ret = -EINVAL;
0112
0113 break;
0114
0115 case I2C_SLAVE_STOP:
0116 if (tu->reg_idx == TU_NUM_REGS) {
0117 set_bit(TU_FLAG_IN_PROCESS, &tu->flags);
0118 queue_delayed_work(system_long_wq, &tu->worker,
0119 msecs_to_jiffies(10 * tu->regs[TU_REG_DELAY]));
0120 }
0121 fallthrough;
0122
0123 case I2C_SLAVE_WRITE_REQUESTED:
0124 memset(tu->regs, 0, TU_NUM_REGS);
0125 tu->reg_idx = 0;
0126 break;
0127
0128 case I2C_SLAVE_READ_PROCESSED:
0129 if (is_proc_call && tu->regs[TU_REG_DATAH])
0130 tu->regs[TU_REG_DATAH]--;
0131 fallthrough;
0132
0133 case I2C_SLAVE_READ_REQUESTED:
0134 *val = is_proc_call ? tu->regs[TU_REG_DATAH] : TU_CUR_VERSION;
0135 break;
0136 }
0137
0138 return ret;
0139 }
0140
0141 static int i2c_slave_testunit_probe(struct i2c_client *client)
0142 {
0143 struct testunit_data *tu;
0144
0145 tu = devm_kzalloc(&client->dev, sizeof(struct testunit_data), GFP_KERNEL);
0146 if (!tu)
0147 return -ENOMEM;
0148
0149 tu->client = client;
0150 i2c_set_clientdata(client, tu);
0151 INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work);
0152
0153 return i2c_slave_register(client, i2c_slave_testunit_slave_cb);
0154 };
0155
0156 static int i2c_slave_testunit_remove(struct i2c_client *client)
0157 {
0158 struct testunit_data *tu = i2c_get_clientdata(client);
0159
0160 cancel_delayed_work_sync(&tu->worker);
0161 i2c_slave_unregister(client);
0162 return 0;
0163 }
0164
0165 static const struct i2c_device_id i2c_slave_testunit_id[] = {
0166 { "slave-testunit", 0 },
0167 { }
0168 };
0169 MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id);
0170
0171 static struct i2c_driver i2c_slave_testunit_driver = {
0172 .driver = {
0173 .name = "i2c-slave-testunit",
0174 },
0175 .probe_new = i2c_slave_testunit_probe,
0176 .remove = i2c_slave_testunit_remove,
0177 .id_table = i2c_slave_testunit_id,
0178 };
0179 module_i2c_driver(i2c_slave_testunit_driver);
0180
0181 MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
0182 MODULE_DESCRIPTION("I2C slave mode test unit");
0183 MODULE_LICENSE("GPL v2");