File indexing completed on 2025-05-11 08:24:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifdef HAVE_CONFIG_H
0018 #include "config.h"
0019 #endif
0020
0021 #include <dev/i2c/eeprom.h>
0022
0023 #include <string.h>
0024
0025 #define EEPROM_MAX_ADDRESS_BYTES 4
0026
0027 #define EEPROM_MAX_PAGE_SIZE 128
0028
0029 typedef struct {
0030 i2c_dev base;
0031 uint16_t address_bytes;
0032 uint16_t page_size;
0033 uint32_t size;
0034 uint16_t i2c_address_mask;
0035 uint16_t i2c_address_shift;
0036 rtems_interval program_timeout_in_ticks;
0037 } eeprom;
0038
0039 static uint16_t eeprom_i2c_addr(eeprom *dev, uint32_t off)
0040 {
0041 return dev->base.address
0042 | ((off >> dev->i2c_address_shift) & dev->i2c_address_mask);
0043 }
0044
0045 static void eeprom_set_addr(
0046 const eeprom *dev,
0047 uint32_t off,
0048 uint8_t addr[EEPROM_MAX_ADDRESS_BYTES]
0049 )
0050 {
0051 int shift = 24 - (4 - dev->address_bytes) * 8;
0052
0053 addr[0] = (uint8_t) (off >> shift);
0054 shift -= 8;
0055 addr[1] = (uint8_t) (off >> shift);
0056 shift -= 8;
0057 addr[2] = (uint8_t) (off >> shift);
0058 shift -= 8;
0059 addr[3] = (uint8_t) (off >> shift);
0060 }
0061
0062 static ssize_t eeprom_read(
0063 i2c_dev *base,
0064 void *buf,
0065 size_t n,
0066 off_t offset
0067 )
0068 {
0069 eeprom *dev = (eeprom *) base;
0070 off_t avail = dev->size - offset;
0071 uint32_t off = (uint32_t) offset;
0072 uint8_t *in = buf;
0073 size_t todo;
0074
0075 if (avail <= 0) {
0076 return 0;
0077 }
0078
0079 if (n > avail) {
0080 n = (size_t) avail;
0081 }
0082
0083 todo = n;
0084
0085 while (todo > 0) {
0086 uint16_t i2c_addr = eeprom_i2c_addr(dev, off);
0087
0088
0089
0090
0091
0092 uint16_t cur = (uint16_t) (todo < 255 ? todo : 255);
0093
0094 uint8_t addr[EEPROM_MAX_ADDRESS_BYTES];
0095 i2c_msg msgs[2] = {
0096 {
0097 .addr = i2c_addr,
0098 .flags = 0,
0099 .len = dev->address_bytes,
0100 .buf = &addr[0]
0101 }, {
0102 .addr = i2c_addr,
0103 .flags = I2C_M_RD,
0104 .buf = in,
0105 .len = cur
0106 }
0107 };
0108 int err;
0109
0110 eeprom_set_addr(dev, off, addr);
0111 err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
0112 if (err != 0) {
0113 return err;
0114 }
0115
0116 todo -= cur;
0117 off += cur;
0118 in += cur;
0119 }
0120
0121 return (ssize_t) n;
0122 }
0123
0124 static ssize_t eeprom_write(
0125 i2c_dev *base,
0126 const void *buf,
0127 size_t n,
0128 off_t offset
0129 )
0130 {
0131 eeprom *dev = (eeprom *) base;
0132 off_t avail = dev->size - offset;
0133 uint32_t off = (uint32_t) offset;
0134 const uint8_t *out = buf;
0135 size_t todo;
0136
0137 if (avail <= 0) {
0138 return 0;
0139 }
0140
0141 if (n > avail) {
0142 n = (size_t) avail;
0143 }
0144
0145 todo = n;
0146
0147 while (todo > 0) {
0148 uint16_t i2c_addr = eeprom_i2c_addr(dev, off);
0149 uint16_t rem = dev->page_size - (off & (dev->page_size - 1));
0150 uint16_t cur = (uint16_t) (todo < rem ? todo : rem);
0151 uint8_t addr[EEPROM_MAX_ADDRESS_BYTES];
0152 i2c_msg msgs[2] = {
0153 {
0154 .addr = i2c_addr,
0155 .flags = 0,
0156 .len = dev->address_bytes,
0157 .buf = &addr[0]
0158 }, {
0159 .addr = i2c_addr,
0160 .flags = I2C_M_NOSTART,
0161 .buf = RTEMS_DECONST(uint8_t *, out),
0162 .len = cur
0163 }
0164 };
0165 uint8_t in[EEPROM_MAX_PAGE_SIZE];
0166 int err;
0167 ssize_t m;
0168 rtems_interval timeout;
0169 bool before;
0170
0171 eeprom_set_addr(dev, off, addr);
0172 err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
0173 if (err != 0) {
0174 return err;
0175 }
0176
0177 timeout = rtems_clock_tick_later(dev->program_timeout_in_ticks);
0178
0179 do {
0180 before = rtems_clock_tick_before(timeout);
0181
0182 m = eeprom_read(&dev->base, &in[0], cur, off);
0183 if (m == cur) {
0184 break;
0185 }
0186 } while (before);
0187
0188 if (m != cur) {
0189 return -ETIMEDOUT;
0190 }
0191
0192 if (memcmp(&in[0], &out[0], cur) != 0) {
0193 return -EIO;
0194 }
0195
0196 todo -= cur;
0197 off += cur;
0198 out += cur;
0199 }
0200
0201 return (ssize_t) n;
0202 }
0203
0204 static off_t eeprom_get_size(i2c_dev *base)
0205 {
0206 eeprom *dev = (eeprom *) base;
0207
0208 return dev->size;
0209 }
0210
0211 static blksize_t eeprom_get_block_size(i2c_dev *base)
0212 {
0213 eeprom *dev = (eeprom *) base;
0214
0215 return dev->page_size;
0216 }
0217
0218 int i2c_dev_register_eeprom(
0219 const char *bus_path,
0220 const char *dev_path,
0221 uint16_t i2c_address,
0222 uint16_t address_bytes,
0223 uint16_t page_size_in_bytes,
0224 uint32_t size_in_bytes,
0225 uint32_t program_timeout_in_ms
0226 )
0227 {
0228 uint32_t extra_address;
0229 uint32_t ms_per_tick;
0230 eeprom *dev;
0231
0232 if (address_bytes > EEPROM_MAX_ADDRESS_BYTES) {
0233 rtems_set_errno_and_return_minus_one(ERANGE);
0234 } else if (address_bytes == EEPROM_MAX_ADDRESS_BYTES) {
0235 extra_address = 0;
0236 } else {
0237 extra_address = size_in_bytes >> (8 * address_bytes);
0238 }
0239
0240 if (extra_address != 0 && (extra_address & (extra_address - 1)) != 0) {
0241 rtems_set_errno_and_return_minus_one(EINVAL);
0242 }
0243
0244 if (page_size_in_bytes > EEPROM_MAX_PAGE_SIZE) {
0245 page_size_in_bytes = EEPROM_MAX_PAGE_SIZE;
0246 }
0247
0248 if (program_timeout_in_ms == 0) {
0249 program_timeout_in_ms = 1000;
0250 }
0251
0252 dev = (eeprom *)
0253 i2c_dev_alloc_and_init(sizeof(*dev), bus_path, i2c_address);
0254 if (dev == NULL) {
0255 return -1;
0256 }
0257
0258 dev->base.read = eeprom_read;
0259 dev->base.write = eeprom_write;
0260 dev->base.get_size = eeprom_get_size;
0261 dev->base.get_block_size = eeprom_get_block_size;
0262 dev->address_bytes = address_bytes;
0263 dev->page_size = page_size_in_bytes;
0264 dev->size = size_in_bytes;
0265 ms_per_tick = rtems_configuration_get_milliseconds_per_tick();
0266 dev->program_timeout_in_ticks = (program_timeout_in_ms + ms_per_tick - 1)
0267 / ms_per_tick + 1;
0268
0269 if (extra_address != 0) {
0270 dev->i2c_address_mask = extra_address - 1;
0271 dev->i2c_address_shift = (uint16_t) (8 * address_bytes);
0272 }
0273
0274 return i2c_dev_register(&dev->base, dev_path);
0275 }