linux/drivers/i2c/i2c-slave-eeprom.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * I2C slave mode EEPROM simulator
   4 *
   5 * Copyright (C) 2014 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
   6 * Copyright (C) 2014 by Renesas Electronics Corporation
   7 *
   8 * Because most slave IP cores can only detect one I2C slave address anyhow,
   9 * this driver does not support simulating EEPROM types which take more than
  10 * one address.
  11 */
  12
  13/*
  14 * FIXME: What to do if only 8 bits of a 16 bit address are sent?
  15 * The ST-M24C64 sends only 0xff then. Needs verification with other
  16 * EEPROMs, though. We currently use the 8 bit as a valid address.
  17 */
  18
  19#include <linux/bitfield.h>
  20#include <linux/firmware.h>
  21#include <linux/i2c.h>
  22#include <linux/init.h>
  23#include <linux/module.h>
  24#include <linux/of.h>
  25#include <linux/slab.h>
  26#include <linux/spinlock.h>
  27#include <linux/sysfs.h>
  28
  29struct eeprom_data {
  30        struct bin_attribute bin;
  31        spinlock_t buffer_lock;
  32        u16 buffer_idx;
  33        u16 address_mask;
  34        u8 num_address_bytes;
  35        u8 idx_write_cnt;
  36        bool read_only;
  37        u8 buffer[];
  38};
  39
  40#define I2C_SLAVE_BYTELEN GENMASK(15, 0)
  41#define I2C_SLAVE_FLAG_ADDR16 BIT(16)
  42#define I2C_SLAVE_FLAG_RO BIT(17)
  43#define I2C_SLAVE_DEVICE_MAGIC(_len, _flags) ((_flags) | ((_len) - 1))
  44
  45static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
  46                                     enum i2c_slave_event event, u8 *val)
  47{
  48        struct eeprom_data *eeprom = i2c_get_clientdata(client);
  49
  50        switch (event) {
  51        case I2C_SLAVE_WRITE_RECEIVED:
  52                if (eeprom->idx_write_cnt < eeprom->num_address_bytes) {
  53                        if (eeprom->idx_write_cnt == 0)
  54                                eeprom->buffer_idx = 0;
  55                        eeprom->buffer_idx = *val | (eeprom->buffer_idx << 8);
  56                        eeprom->idx_write_cnt++;
  57                } else {
  58                        if (!eeprom->read_only) {
  59                                spin_lock(&eeprom->buffer_lock);
  60                                eeprom->buffer[eeprom->buffer_idx++ & eeprom->address_mask] = *val;
  61                                spin_unlock(&eeprom->buffer_lock);
  62                        }
  63                }
  64                break;
  65
  66        case I2C_SLAVE_READ_PROCESSED:
  67                /* The previous byte made it to the bus, get next one */
  68                eeprom->buffer_idx++;
  69                fallthrough;
  70        case I2C_SLAVE_READ_REQUESTED:
  71                spin_lock(&eeprom->buffer_lock);
  72                *val = eeprom->buffer[eeprom->buffer_idx & eeprom->address_mask];
  73                spin_unlock(&eeprom->buffer_lock);
  74                /*
  75                 * Do not increment buffer_idx here, because we don't know if
  76                 * this byte will be actually used. Read Linux I2C slave docs
  77                 * for details.
  78                 */
  79                break;
  80
  81        case I2C_SLAVE_STOP:
  82        case I2C_SLAVE_WRITE_REQUESTED:
  83                eeprom->idx_write_cnt = 0;
  84                break;
  85
  86        default:
  87                break;
  88        }
  89
  90        return 0;
  91}
  92
  93static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj,
  94                struct bin_attribute *attr, char *buf, loff_t off, size_t count)
  95{
  96        struct eeprom_data *eeprom;
  97        unsigned long flags;
  98
  99        eeprom = dev_get_drvdata(kobj_to_dev(kobj));
 100
 101        spin_lock_irqsave(&eeprom->buffer_lock, flags);
 102        memcpy(buf, &eeprom->buffer[off], count);
 103        spin_unlock_irqrestore(&eeprom->buffer_lock, flags);
 104
 105        return count;
 106}
 107
 108static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kobj,
 109                struct bin_attribute *attr, char *buf, loff_t off, size_t count)
 110{
 111        struct eeprom_data *eeprom;
 112        unsigned long flags;
 113
 114        eeprom = dev_get_drvdata(kobj_to_dev(kobj));
 115
 116        spin_lock_irqsave(&eeprom->buffer_lock, flags);
 117        memcpy(&eeprom->buffer[off], buf, count);
 118        spin_unlock_irqrestore(&eeprom->buffer_lock, flags);
 119
 120        return count;
 121}
 122
 123static int i2c_slave_init_eeprom_data(struct eeprom_data *eeprom, struct i2c_client *client,
 124                                      unsigned int size)
 125{
 126        const struct firmware *fw;
 127        const char *eeprom_data;
 128        int ret = device_property_read_string(&client->dev, "firmware-name", &eeprom_data);
 129
 130        if (!ret) {
 131                ret = request_firmware_into_buf(&fw, eeprom_data, &client->dev,
 132                                                eeprom->buffer, size);
 133                if (ret)
 134                        return ret;
 135                release_firmware(fw);
 136        } else {
 137                /* An empty eeprom typically has all bits set to 1 */
 138                memset(eeprom->buffer, 0xff, size);
 139        }
 140        return 0;
 141}
 142
 143static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id)
 144{
 145        struct eeprom_data *eeprom;
 146        int ret;
 147        unsigned int size = FIELD_GET(I2C_SLAVE_BYTELEN, id->driver_data) + 1;
 148        unsigned int flag_addr16 = FIELD_GET(I2C_SLAVE_FLAG_ADDR16, id->driver_data);
 149
 150        eeprom = devm_kzalloc(&client->dev, sizeof(struct eeprom_data) + size, GFP_KERNEL);
 151        if (!eeprom)
 152                return -ENOMEM;
 153
 154        eeprom->num_address_bytes = flag_addr16 ? 2 : 1;
 155        eeprom->address_mask = size - 1;
 156        eeprom->read_only = FIELD_GET(I2C_SLAVE_FLAG_RO, id->driver_data);
 157        spin_lock_init(&eeprom->buffer_lock);
 158        i2c_set_clientdata(client, eeprom);
 159
 160        ret = i2c_slave_init_eeprom_data(eeprom, client, size);
 161        if (ret)
 162                return ret;
 163
 164        sysfs_bin_attr_init(&eeprom->bin);
 165        eeprom->bin.attr.name = "slave-eeprom";
 166        eeprom->bin.attr.mode = S_IRUSR | S_IWUSR;
 167        eeprom->bin.read = i2c_slave_eeprom_bin_read;
 168        eeprom->bin.write = i2c_slave_eeprom_bin_write;
 169        eeprom->bin.size = size;
 170
 171        ret = sysfs_create_bin_file(&client->dev.kobj, &eeprom->bin);
 172        if (ret)
 173                return ret;
 174
 175        ret = i2c_slave_register(client, i2c_slave_eeprom_slave_cb);
 176        if (ret) {
 177                sysfs_remove_bin_file(&client->dev.kobj, &eeprom->bin);
 178                return ret;
 179        }
 180
 181        return 0;
 182};
 183
 184static int i2c_slave_eeprom_remove(struct i2c_client *client)
 185{
 186        struct eeprom_data *eeprom = i2c_get_clientdata(client);
 187
 188        i2c_slave_unregister(client);
 189        sysfs_remove_bin_file(&client->dev.kobj, &eeprom->bin);
 190
 191        return 0;
 192}
 193
 194static const struct i2c_device_id i2c_slave_eeprom_id[] = {
 195        { "slave-24c02", I2C_SLAVE_DEVICE_MAGIC(2048 / 8,  0) },
 196        { "slave-24c02ro", I2C_SLAVE_DEVICE_MAGIC(2048 / 8,  I2C_SLAVE_FLAG_RO) },
 197        { "slave-24c32", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
 198        { "slave-24c32ro", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
 199        { "slave-24c64", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
 200        { "slave-24c64ro", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
 201        { "slave-24c512", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16) },
 202        { "slave-24c512ro", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
 203        { }
 204};
 205MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
 206
 207static struct i2c_driver i2c_slave_eeprom_driver = {
 208        .driver = {
 209                .name = "i2c-slave-eeprom",
 210        },
 211        .probe = i2c_slave_eeprom_probe,
 212        .remove = i2c_slave_eeprom_remove,
 213        .id_table = i2c_slave_eeprom_id,
 214};
 215module_i2c_driver(i2c_slave_eeprom_driver);
 216
 217MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
 218MODULE_DESCRIPTION("I2C slave mode EEPROM simulator");
 219MODULE_LICENSE("GPL v2");
 220