0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <linux/bitfield.h>
0020 #include <linux/firmware.h>
0021 #include <linux/i2c.h>
0022 #include <linux/init.h>
0023 #include <linux/module.h>
0024 #include <linux/of.h>
0025 #include <linux/slab.h>
0026 #include <linux/spinlock.h>
0027 #include <linux/sysfs.h>
0028
0029 struct eeprom_data {
0030 struct bin_attribute bin;
0031 spinlock_t buffer_lock;
0032 u16 buffer_idx;
0033 u16 address_mask;
0034 u8 num_address_bytes;
0035 u8 idx_write_cnt;
0036 bool read_only;
0037 u8 buffer[];
0038 };
0039
0040 #define I2C_SLAVE_BYTELEN GENMASK(15, 0)
0041 #define I2C_SLAVE_FLAG_ADDR16 BIT(16)
0042 #define I2C_SLAVE_FLAG_RO BIT(17)
0043 #define I2C_SLAVE_DEVICE_MAGIC(_len, _flags) ((_flags) | ((_len) - 1))
0044
0045 static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
0046 enum i2c_slave_event event, u8 *val)
0047 {
0048 struct eeprom_data *eeprom = i2c_get_clientdata(client);
0049
0050 switch (event) {
0051 case I2C_SLAVE_WRITE_RECEIVED:
0052 if (eeprom->idx_write_cnt < eeprom->num_address_bytes) {
0053 if (eeprom->idx_write_cnt == 0)
0054 eeprom->buffer_idx = 0;
0055 eeprom->buffer_idx = *val | (eeprom->buffer_idx << 8);
0056 eeprom->idx_write_cnt++;
0057 } else {
0058 if (!eeprom->read_only) {
0059 spin_lock(&eeprom->buffer_lock);
0060 eeprom->buffer[eeprom->buffer_idx++ & eeprom->address_mask] = *val;
0061 spin_unlock(&eeprom->buffer_lock);
0062 }
0063 }
0064 break;
0065
0066 case I2C_SLAVE_READ_PROCESSED:
0067
0068 eeprom->buffer_idx++;
0069 fallthrough;
0070 case I2C_SLAVE_READ_REQUESTED:
0071 spin_lock(&eeprom->buffer_lock);
0072 *val = eeprom->buffer[eeprom->buffer_idx & eeprom->address_mask];
0073 spin_unlock(&eeprom->buffer_lock);
0074
0075
0076
0077
0078
0079 break;
0080
0081 case I2C_SLAVE_STOP:
0082 case I2C_SLAVE_WRITE_REQUESTED:
0083 eeprom->idx_write_cnt = 0;
0084 break;
0085
0086 default:
0087 break;
0088 }
0089
0090 return 0;
0091 }
0092
0093 static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj,
0094 struct bin_attribute *attr, char *buf, loff_t off, size_t count)
0095 {
0096 struct eeprom_data *eeprom;
0097 unsigned long flags;
0098
0099 eeprom = dev_get_drvdata(kobj_to_dev(kobj));
0100
0101 spin_lock_irqsave(&eeprom->buffer_lock, flags);
0102 memcpy(buf, &eeprom->buffer[off], count);
0103 spin_unlock_irqrestore(&eeprom->buffer_lock, flags);
0104
0105 return count;
0106 }
0107
0108 static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kobj,
0109 struct bin_attribute *attr, char *buf, loff_t off, size_t count)
0110 {
0111 struct eeprom_data *eeprom;
0112 unsigned long flags;
0113
0114 eeprom = dev_get_drvdata(kobj_to_dev(kobj));
0115
0116 spin_lock_irqsave(&eeprom->buffer_lock, flags);
0117 memcpy(&eeprom->buffer[off], buf, count);
0118 spin_unlock_irqrestore(&eeprom->buffer_lock, flags);
0119
0120 return count;
0121 }
0122
0123 static int i2c_slave_init_eeprom_data(struct eeprom_data *eeprom, struct i2c_client *client,
0124 unsigned int size)
0125 {
0126 const struct firmware *fw;
0127 const char *eeprom_data;
0128 int ret = device_property_read_string(&client->dev, "firmware-name", &eeprom_data);
0129
0130 if (!ret) {
0131 ret = request_firmware_into_buf(&fw, eeprom_data, &client->dev,
0132 eeprom->buffer, size);
0133 if (ret)
0134 return ret;
0135 release_firmware(fw);
0136 } else {
0137
0138 memset(eeprom->buffer, 0xff, size);
0139 }
0140 return 0;
0141 }
0142
0143 static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id)
0144 {
0145 struct eeprom_data *eeprom;
0146 int ret;
0147 unsigned int size = FIELD_GET(I2C_SLAVE_BYTELEN, id->driver_data) + 1;
0148 unsigned int flag_addr16 = FIELD_GET(I2C_SLAVE_FLAG_ADDR16, id->driver_data);
0149
0150 eeprom = devm_kzalloc(&client->dev, sizeof(struct eeprom_data) + size, GFP_KERNEL);
0151 if (!eeprom)
0152 return -ENOMEM;
0153
0154 eeprom->num_address_bytes = flag_addr16 ? 2 : 1;
0155 eeprom->address_mask = size - 1;
0156 eeprom->read_only = FIELD_GET(I2C_SLAVE_FLAG_RO, id->driver_data);
0157 spin_lock_init(&eeprom->buffer_lock);
0158 i2c_set_clientdata(client, eeprom);
0159
0160 ret = i2c_slave_init_eeprom_data(eeprom, client, size);
0161 if (ret)
0162 return ret;
0163
0164 sysfs_bin_attr_init(&eeprom->bin);
0165 eeprom->bin.attr.name = "slave-eeprom";
0166 eeprom->bin.attr.mode = S_IRUSR | S_IWUSR;
0167 eeprom->bin.read = i2c_slave_eeprom_bin_read;
0168 eeprom->bin.write = i2c_slave_eeprom_bin_write;
0169 eeprom->bin.size = size;
0170
0171 ret = sysfs_create_bin_file(&client->dev.kobj, &eeprom->bin);
0172 if (ret)
0173 return ret;
0174
0175 ret = i2c_slave_register(client, i2c_slave_eeprom_slave_cb);
0176 if (ret) {
0177 sysfs_remove_bin_file(&client->dev.kobj, &eeprom->bin);
0178 return ret;
0179 }
0180
0181 return 0;
0182 };
0183
0184 static int i2c_slave_eeprom_remove(struct i2c_client *client)
0185 {
0186 struct eeprom_data *eeprom = i2c_get_clientdata(client);
0187
0188 i2c_slave_unregister(client);
0189 sysfs_remove_bin_file(&client->dev.kobj, &eeprom->bin);
0190
0191 return 0;
0192 }
0193
0194 static const struct i2c_device_id i2c_slave_eeprom_id[] = {
0195 { "slave-24c02", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, 0) },
0196 { "slave-24c02ro", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, I2C_SLAVE_FLAG_RO) },
0197 { "slave-24c32", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
0198 { "slave-24c32ro", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
0199 { "slave-24c64", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
0200 { "slave-24c64ro", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
0201 { "slave-24c512", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16) },
0202 { "slave-24c512ro", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
0203 { }
0204 };
0205 MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
0206
0207 static struct i2c_driver i2c_slave_eeprom_driver = {
0208 .driver = {
0209 .name = "i2c-slave-eeprom",
0210 },
0211 .probe = i2c_slave_eeprom_probe,
0212 .remove = i2c_slave_eeprom_remove,
0213 .id_table = i2c_slave_eeprom_id,
0214 };
0215 module_i2c_driver(i2c_slave_eeprom_driver);
0216
0217 MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
0218 MODULE_DESCRIPTION("I2C slave mode EEPROM simulator");
0219 MODULE_LICENSE("GPL v2");