12e192b24SSimon Glass /* 22e192b24SSimon Glass * (C) Copyright 2000, 2001 32e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 42e192b24SSimon Glass * 52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 62e192b24SSimon Glass */ 72e192b24SSimon Glass 82e192b24SSimon Glass /* 92e192b24SSimon Glass * Support for read and write access to EEPROM like memory devices. This 102e192b24SSimon Glass * includes regular EEPROM as well as FRAM (ferroelectic nonvolaile RAM). 112e192b24SSimon Glass * FRAM devices read and write data at bus speed. In particular, there is no 122e192b24SSimon Glass * write delay. Also, there is no limit imposed on the number of bytes that can 132e192b24SSimon Glass * be transferred with a single read or write. 142e192b24SSimon Glass * 152e192b24SSimon Glass * Use the following configuration options to ensure no unneeded performance 162e192b24SSimon Glass * degradation (typical for EEPROM) is incured for FRAM memory: 172e192b24SSimon Glass * 182e192b24SSimon Glass * #define CONFIG_SYS_I2C_FRAM 192e192b24SSimon Glass * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 202e192b24SSimon Glass * 212e192b24SSimon Glass */ 222e192b24SSimon Glass 232e192b24SSimon Glass #include <common.h> 242e192b24SSimon Glass #include <config.h> 252e192b24SSimon Glass #include <command.h> 262e192b24SSimon Glass #include <i2c.h> 27e7c2729bSNikita Kiryanov #include <eeprom_layout.h> 282e192b24SSimon Glass 292e192b24SSimon Glass #ifndef CONFIG_SYS_I2C_SPEED 302e192b24SSimon Glass #define CONFIG_SYS_I2C_SPEED 50000 312e192b24SSimon Glass #endif 322e192b24SSimon Glass 332e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 342e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 0 352e192b24SSimon Glass #endif 362e192b24SSimon Glass 372e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 382e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 8 392e192b24SSimon Glass #endif 402e192b24SSimon Glass 41a6e7b774SMario Six #ifndef I2C_RXTX_LEN 42a6e7b774SMario Six #define I2C_RXTX_LEN 128 43a6e7b774SMario Six #endif 44a6e7b774SMario Six 452e192b24SSimon Glass #define EEPROM_PAGE_SIZE (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS) 462e192b24SSimon Glass #define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1)) 472e192b24SSimon Glass 482e192b24SSimon Glass /* 492e192b24SSimon Glass * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is 502e192b24SSimon Glass * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM. 512e192b24SSimon Glass * 522e192b24SSimon Glass * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is 532e192b24SSimon Glass * 0x00000nxx for EEPROM address selectors and page number at n. 542e192b24SSimon Glass */ 552e192b24SSimon Glass #if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 562e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \ 572e192b24SSimon Glass (CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \ 582e192b24SSimon Glass (CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2) 592e192b24SSimon Glass #error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2 602e192b24SSimon Glass #endif 612e192b24SSimon Glass #endif 622e192b24SSimon Glass 632e192b24SSimon Glass __weak int eeprom_write_enable(unsigned dev_addr, int state) 642e192b24SSimon Glass { 652e192b24SSimon Glass return 0; 662e192b24SSimon Glass } 672e192b24SSimon Glass 682e192b24SSimon Glass void eeprom_init(int bus) 692e192b24SSimon Glass { 702e192b24SSimon Glass /* SPI EEPROM */ 712e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 722e192b24SSimon Glass spi_init_f(); 732e192b24SSimon Glass #endif 742e192b24SSimon Glass 752e192b24SSimon Glass /* I2C EEPROM */ 762636ac65SNikita Kiryanov #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C) 772e192b24SSimon Glass #if defined(CONFIG_SYS_I2C) 782e192b24SSimon Glass if (bus >= 0) 792e192b24SSimon Glass i2c_set_bus_num(bus); 802e192b24SSimon Glass #endif 812e192b24SSimon Glass i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); 822e192b24SSimon Glass #endif 832e192b24SSimon Glass } 842e192b24SSimon Glass 852e192b24SSimon Glass static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr) 862e192b24SSimon Glass { 872e192b24SSimon Glass unsigned blk_off; 882e192b24SSimon Glass int alen; 892e192b24SSimon Glass 902e192b24SSimon Glass blk_off = offset & 0xff; /* block offset */ 912e192b24SSimon Glass #if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 922e192b24SSimon Glass addr[0] = offset >> 8; /* block number */ 932e192b24SSimon Glass addr[1] = blk_off; /* block offset */ 942e192b24SSimon Glass alen = 2; 952e192b24SSimon Glass #else 962e192b24SSimon Glass addr[0] = offset >> 16; /* block number */ 972e192b24SSimon Glass addr[1] = offset >> 8; /* upper address octet */ 982e192b24SSimon Glass addr[2] = blk_off; /* lower address octet */ 992e192b24SSimon Glass alen = 3; 1002e192b24SSimon Glass #endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */ 1012e192b24SSimon Glass 1022e192b24SSimon Glass addr[0] |= dev_addr; /* insert device address */ 1032e192b24SSimon Glass 1042e192b24SSimon Glass return alen; 1052e192b24SSimon Glass } 1062e192b24SSimon Glass 1072e192b24SSimon Glass static int eeprom_len(unsigned offset, unsigned end) 1082e192b24SSimon Glass { 1092e192b24SSimon Glass unsigned len = end - offset; 1102e192b24SSimon Glass 1112e192b24SSimon Glass /* 1122e192b24SSimon Glass * For a FRAM device there is no limit on the number of the 1132e192b24SSimon Glass * bytes that can be ccessed with the single read or write 1142e192b24SSimon Glass * operation. 1152e192b24SSimon Glass */ 1162e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_FRAM) 1172e192b24SSimon Glass unsigned blk_off = offset & 0xff; 1182e192b24SSimon Glass unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off); 1192e192b24SSimon Glass 1202e192b24SSimon Glass if (maxlen > I2C_RXTX_LEN) 1212e192b24SSimon Glass maxlen = I2C_RXTX_LEN; 1222e192b24SSimon Glass 1232e192b24SSimon Glass if (len > maxlen) 1242e192b24SSimon Glass len = maxlen; 1252e192b24SSimon Glass #endif 1262e192b24SSimon Glass 1272e192b24SSimon Glass return len; 1282e192b24SSimon Glass } 1292e192b24SSimon Glass 1302e192b24SSimon Glass static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen, 1312e192b24SSimon Glass uchar *buffer, unsigned len, bool read) 1322e192b24SSimon Glass { 1332e192b24SSimon Glass int ret = 0; 1342e192b24SSimon Glass 1352e192b24SSimon Glass /* SPI */ 1362e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 1372e192b24SSimon Glass if (read) 1382e192b24SSimon Glass spi_read(addr, alen, buffer, len); 1392e192b24SSimon Glass else 1402e192b24SSimon Glass spi_write(addr, alen, buffer, len); 1412e192b24SSimon Glass #else /* I2C */ 1422e192b24SSimon Glass 1432e192b24SSimon Glass #if defined(CONFIG_SYS_I2C_EEPROM_BUS) 1442e192b24SSimon Glass i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS); 1452e192b24SSimon Glass #endif 1462e192b24SSimon Glass 1472e192b24SSimon Glass if (read) 1482e192b24SSimon Glass ret = i2c_read(addr[0], offset, alen - 1, buffer, len); 1492e192b24SSimon Glass else 1502e192b24SSimon Glass ret = i2c_write(addr[0], offset, alen - 1, buffer, len); 1512e192b24SSimon Glass 1522e192b24SSimon Glass if (ret) 1532e192b24SSimon Glass ret = 1; 1542e192b24SSimon Glass #endif 1552e192b24SSimon Glass return ret; 1562e192b24SSimon Glass } 1572e192b24SSimon Glass 1582e192b24SSimon Glass static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer, 1592e192b24SSimon Glass unsigned cnt, bool read) 1602e192b24SSimon Glass { 1612e192b24SSimon Glass unsigned end = offset + cnt; 1622e192b24SSimon Glass unsigned alen, len; 1632e192b24SSimon Glass int rcode = 0; 1642e192b24SSimon Glass uchar addr[3]; 1652e192b24SSimon Glass 1662e192b24SSimon Glass while (offset < end) { 1672e192b24SSimon Glass alen = eeprom_addr(dev_addr, offset, addr); 1682e192b24SSimon Glass 1692e192b24SSimon Glass len = eeprom_len(offset, end); 1702e192b24SSimon Glass 1712e192b24SSimon Glass rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read); 1722e192b24SSimon Glass 1732e192b24SSimon Glass buffer += len; 1742e192b24SSimon Glass offset += len; 1752e192b24SSimon Glass 1762e192b24SSimon Glass if (!read) 1772e192b24SSimon Glass udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000); 1782e192b24SSimon Glass } 1792e192b24SSimon Glass 1802e192b24SSimon Glass return rcode; 1812e192b24SSimon Glass } 1822e192b24SSimon Glass 1832e192b24SSimon Glass int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) 1842e192b24SSimon Glass { 1852e192b24SSimon Glass /* 1862e192b24SSimon Glass * Read data until done or would cross a page boundary. 1872e192b24SSimon Glass * We must write the address again when changing pages 1882e192b24SSimon Glass * because the next page may be in a different device. 1892e192b24SSimon Glass */ 1902e192b24SSimon Glass return eeprom_rw(dev_addr, offset, buffer, cnt, 1); 1912e192b24SSimon Glass } 1922e192b24SSimon Glass 1932e192b24SSimon Glass int eeprom_write(unsigned dev_addr, unsigned offset, 1942e192b24SSimon Glass uchar *buffer, unsigned cnt) 1952e192b24SSimon Glass { 1962e192b24SSimon Glass int ret; 1972e192b24SSimon Glass 1982e192b24SSimon Glass eeprom_write_enable(dev_addr, 1); 1992e192b24SSimon Glass 2002e192b24SSimon Glass /* 2012e192b24SSimon Glass * Write data until done or would cross a write page boundary. 2022e192b24SSimon Glass * We must write the address again when changing pages 2032e192b24SSimon Glass * because the address counter only increments within a page. 2042e192b24SSimon Glass */ 2052e192b24SSimon Glass ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0); 2062e192b24SSimon Glass 2072e192b24SSimon Glass eeprom_write_enable(dev_addr, 0); 2082e192b24SSimon Glass return ret; 2092e192b24SSimon Glass } 2102e192b24SSimon Glass 211c40f0372SNikita Kiryanov static int parse_numeric_param(char *str) 212c40f0372SNikita Kiryanov { 213c40f0372SNikita Kiryanov char *endptr; 214c40f0372SNikita Kiryanov int value = simple_strtol(str, &endptr, 16); 215c40f0372SNikita Kiryanov 216c40f0372SNikita Kiryanov return (*endptr != '\0') ? -1 : value; 217c40f0372SNikita Kiryanov } 218c40f0372SNikita Kiryanov 219c40f0372SNikita Kiryanov /** 220c40f0372SNikita Kiryanov * parse_i2c_bus_addr - parse the i2c bus and i2c devaddr parameters 221c40f0372SNikita Kiryanov * 222c40f0372SNikita Kiryanov * @i2c_bus: address to store the i2c bus 223c40f0372SNikita Kiryanov * @i2c_addr: address to store the device i2c address 224c40f0372SNikita Kiryanov * @argc: count of command line arguments left to parse 225c40f0372SNikita Kiryanov * @argv: command line arguments left to parse 226c40f0372SNikita Kiryanov * @argc_no_bus_addr: argc value we expect to see when bus & addr aren't given 227c40f0372SNikita Kiryanov * 228c40f0372SNikita Kiryanov * @returns: number of arguments parsed or CMD_RET_USAGE if error 229c40f0372SNikita Kiryanov */ 230c40f0372SNikita Kiryanov static int parse_i2c_bus_addr(int *i2c_bus, ulong *i2c_addr, int argc, 231c40f0372SNikita Kiryanov char * const argv[], int argc_no_bus_addr) 232c40f0372SNikita Kiryanov { 233c40f0372SNikita Kiryanov int argc_no_bus = argc_no_bus_addr + 1; 234c40f0372SNikita Kiryanov int argc_bus_addr = argc_no_bus_addr + 2; 235c40f0372SNikita Kiryanov 236c40f0372SNikita Kiryanov #ifdef CONFIG_SYS_DEF_EEPROM_ADDR 237c40f0372SNikita Kiryanov if (argc == argc_no_bus_addr) { 238c40f0372SNikita Kiryanov *i2c_bus = -1; 239c40f0372SNikita Kiryanov *i2c_addr = CONFIG_SYS_DEF_EEPROM_ADDR; 240c40f0372SNikita Kiryanov 241c40f0372SNikita Kiryanov return 0; 242c40f0372SNikita Kiryanov } 243c40f0372SNikita Kiryanov #endif 244c40f0372SNikita Kiryanov if (argc == argc_no_bus) { 245c40f0372SNikita Kiryanov *i2c_bus = -1; 246c40f0372SNikita Kiryanov *i2c_addr = parse_numeric_param(argv[0]); 247c40f0372SNikita Kiryanov 248c40f0372SNikita Kiryanov return 1; 249c40f0372SNikita Kiryanov } 250c40f0372SNikita Kiryanov 251c40f0372SNikita Kiryanov if (argc == argc_bus_addr) { 252c40f0372SNikita Kiryanov *i2c_bus = parse_numeric_param(argv[0]); 253c40f0372SNikita Kiryanov *i2c_addr = parse_numeric_param(argv[1]); 254c40f0372SNikita Kiryanov 255c40f0372SNikita Kiryanov return 2; 256c40f0372SNikita Kiryanov } 257c40f0372SNikita Kiryanov 258c40f0372SNikita Kiryanov return CMD_RET_USAGE; 259c40f0372SNikita Kiryanov } 260c40f0372SNikita Kiryanov 261aa9e6044SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 262aa9e6044SNikita Kiryanov 263aa9e6044SNikita Kiryanov __weak int eeprom_parse_layout_version(char *str) 264aa9e6044SNikita Kiryanov { 265aa9e6044SNikita Kiryanov return LAYOUT_VERSION_UNRECOGNIZED; 266aa9e6044SNikita Kiryanov } 267aa9e6044SNikita Kiryanov 268aa9e6044SNikita Kiryanov static unsigned char eeprom_buf[CONFIG_SYS_EEPROM_SIZE]; 269aa9e6044SNikita Kiryanov 270aa9e6044SNikita Kiryanov #ifndef CONFIG_EEPROM_LAYOUT_HELP_STRING 271aa9e6044SNikita Kiryanov #define CONFIG_EEPROM_LAYOUT_HELP_STRING "<not defined>" 272aa9e6044SNikita Kiryanov #endif 273aa9e6044SNikita Kiryanov 274e7c2729bSNikita Kiryanov #endif 275e7c2729bSNikita Kiryanov 276aa9e6044SNikita Kiryanov enum eeprom_action { 277e7c2729bSNikita Kiryanov EEPROM_READ, 278e7c2729bSNikita Kiryanov EEPROM_WRITE, 279aa9e6044SNikita Kiryanov EEPROM_PRINT, 280aa9e6044SNikita Kiryanov EEPROM_UPDATE, 281aa9e6044SNikita Kiryanov EEPROM_ACTION_INVALID, 282aa9e6044SNikita Kiryanov }; 283aa9e6044SNikita Kiryanov 284aa9e6044SNikita Kiryanov static enum eeprom_action parse_action(char *cmd) 285aa9e6044SNikita Kiryanov { 286*3dc9be82SNikita Kiryanov if (!strncmp(cmd, "read", 4)) 287*3dc9be82SNikita Kiryanov return EEPROM_READ; 288*3dc9be82SNikita Kiryanov if (!strncmp(cmd, "write", 5)) 289*3dc9be82SNikita Kiryanov return EEPROM_WRITE; 290*3dc9be82SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 291aa9e6044SNikita Kiryanov if (!strncmp(cmd, "print", 5)) 292aa9e6044SNikita Kiryanov return EEPROM_PRINT; 293aa9e6044SNikita Kiryanov if (!strncmp(cmd, "update", 6)) 294aa9e6044SNikita Kiryanov return EEPROM_UPDATE; 295*3dc9be82SNikita Kiryanov #endif 296aa9e6044SNikita Kiryanov 297aa9e6044SNikita Kiryanov return EEPROM_ACTION_INVALID; 298aa9e6044SNikita Kiryanov } 299aa9e6044SNikita Kiryanov 300aa9e6044SNikita Kiryanov static int eeprom_execute_command(enum eeprom_action action, int i2c_bus, 301e7c2729bSNikita Kiryanov ulong i2c_addr, int layout_ver, char *key, 302e7c2729bSNikita Kiryanov char *value, ulong addr, ulong off, ulong cnt) 303aa9e6044SNikita Kiryanov { 304e7c2729bSNikita Kiryanov int rcode = 0; 305e7c2729bSNikita Kiryanov const char *const fmt = 306e7c2729bSNikita Kiryanov "\nEEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... "; 307e7c2729bSNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 308aa9e6044SNikita Kiryanov struct eeprom_layout layout; 309e7c2729bSNikita Kiryanov #endif 310aa9e6044SNikita Kiryanov 311aa9e6044SNikita Kiryanov if (action == EEPROM_ACTION_INVALID) 312aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 313aa9e6044SNikita Kiryanov 314aa9e6044SNikita Kiryanov eeprom_init(i2c_bus); 315e7c2729bSNikita Kiryanov if (action == EEPROM_READ) { 316e7c2729bSNikita Kiryanov printf(fmt, i2c_addr, "read", addr, off, cnt); 317e7c2729bSNikita Kiryanov 318e7c2729bSNikita Kiryanov rcode = eeprom_read(i2c_addr, off, (uchar *)addr, cnt); 319e7c2729bSNikita Kiryanov 320e7c2729bSNikita Kiryanov puts("done\n"); 321e7c2729bSNikita Kiryanov return rcode; 322e7c2729bSNikita Kiryanov } else if (action == EEPROM_WRITE) { 323e7c2729bSNikita Kiryanov printf(fmt, i2c_addr, "write", addr, off, cnt); 324e7c2729bSNikita Kiryanov 325e7c2729bSNikita Kiryanov rcode = eeprom_write(i2c_addr, off, (uchar *)addr, cnt); 326e7c2729bSNikita Kiryanov 327e7c2729bSNikita Kiryanov puts("done\n"); 328e7c2729bSNikita Kiryanov return rcode; 329e7c2729bSNikita Kiryanov } 330e7c2729bSNikita Kiryanov 331e7c2729bSNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 332aa9e6044SNikita Kiryanov rcode = eeprom_read(i2c_addr, 0, eeprom_buf, CONFIG_SYS_EEPROM_SIZE); 333aa9e6044SNikita Kiryanov if (rcode < 0) 334aa9e6044SNikita Kiryanov return rcode; 335aa9e6044SNikita Kiryanov 336aa9e6044SNikita Kiryanov eeprom_layout_setup(&layout, eeprom_buf, CONFIG_SYS_EEPROM_SIZE, 337aa9e6044SNikita Kiryanov layout_ver); 338aa9e6044SNikita Kiryanov 339aa9e6044SNikita Kiryanov if (action == EEPROM_PRINT) { 340aa9e6044SNikita Kiryanov layout.print(&layout); 341aa9e6044SNikita Kiryanov return 0; 342aa9e6044SNikita Kiryanov } 343aa9e6044SNikita Kiryanov 344aa9e6044SNikita Kiryanov layout.update(&layout, key, value); 345aa9e6044SNikita Kiryanov 346aa9e6044SNikita Kiryanov rcode = eeprom_write(i2c_addr, 0, layout.data, CONFIG_SYS_EEPROM_SIZE); 347e7c2729bSNikita Kiryanov #endif 348aa9e6044SNikita Kiryanov 349aa9e6044SNikita Kiryanov return rcode; 350aa9e6044SNikita Kiryanov } 351aa9e6044SNikita Kiryanov 352aa9e6044SNikita Kiryanov #define NEXT_PARAM(argc, index) { (argc)--; (index)++; } 353*3dc9be82SNikita Kiryanov int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 354aa9e6044SNikita Kiryanov { 355aa9e6044SNikita Kiryanov int layout_ver = LAYOUT_VERSION_AUTODETECT; 356aa9e6044SNikita Kiryanov enum eeprom_action action = EEPROM_ACTION_INVALID; 357*3dc9be82SNikita Kiryanov int i2c_bus = -1, index = 0; 358*3dc9be82SNikita Kiryanov ulong i2c_addr = -1, addr = 0, cnt = 0, off = 0; 359*3dc9be82SNikita Kiryanov int ret; 360aa9e6044SNikita Kiryanov char *field_name = ""; 361aa9e6044SNikita Kiryanov char *field_value = ""; 362aa9e6044SNikita Kiryanov 363aa9e6044SNikita Kiryanov if (argc <= 1) 364aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 365aa9e6044SNikita Kiryanov 366aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); /* Skip program name */ 367aa9e6044SNikita Kiryanov 368aa9e6044SNikita Kiryanov action = parse_action(argv[index]); 369aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 370aa9e6044SNikita Kiryanov 371*3dc9be82SNikita Kiryanov if (action == EEPROM_ACTION_INVALID) 372aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 373aa9e6044SNikita Kiryanov 374*3dc9be82SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 375*3dc9be82SNikita Kiryanov if (action == EEPROM_PRINT || action == EEPROM_UPDATE) { 376aa9e6044SNikita Kiryanov if (!strcmp(argv[index], "-l")) { 377aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 378aa9e6044SNikita Kiryanov layout_ver = eeprom_parse_layout_version(argv[index]); 379aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 380aa9e6044SNikita Kiryanov } 381*3dc9be82SNikita Kiryanov } 382*3dc9be82SNikita Kiryanov #endif 383aa9e6044SNikita Kiryanov 384*3dc9be82SNikita Kiryanov switch (action) { 385*3dc9be82SNikita Kiryanov case EEPROM_READ: 386*3dc9be82SNikita Kiryanov case EEPROM_WRITE: 387*3dc9be82SNikita Kiryanov ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc, 388*3dc9be82SNikita Kiryanov argv + index, 3); 389*3dc9be82SNikita Kiryanov break; 390*3dc9be82SNikita Kiryanov case EEPROM_PRINT: 391*3dc9be82SNikita Kiryanov ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc, 392*3dc9be82SNikita Kiryanov argv + index, 0); 393*3dc9be82SNikita Kiryanov break; 394*3dc9be82SNikita Kiryanov case EEPROM_UPDATE: 395*3dc9be82SNikita Kiryanov ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc, 396*3dc9be82SNikita Kiryanov argv + index, 2); 397*3dc9be82SNikita Kiryanov break; 398*3dc9be82SNikita Kiryanov default: 399*3dc9be82SNikita Kiryanov /* Get compiler to stop whining */ 400aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 401aa9e6044SNikita Kiryanov } 402aa9e6044SNikita Kiryanov 403*3dc9be82SNikita Kiryanov if (ret == CMD_RET_USAGE) 404*3dc9be82SNikita Kiryanov return ret; 405*3dc9be82SNikita Kiryanov 406*3dc9be82SNikita Kiryanov while (ret--) 407*3dc9be82SNikita Kiryanov NEXT_PARAM(argc, index); 408*3dc9be82SNikita Kiryanov 409*3dc9be82SNikita Kiryanov if (action == EEPROM_READ || action == EEPROM_WRITE) { 410*3dc9be82SNikita Kiryanov addr = parse_numeric_param(argv[index]); 411*3dc9be82SNikita Kiryanov NEXT_PARAM(argc, index); 412*3dc9be82SNikita Kiryanov off = parse_numeric_param(argv[index]); 413*3dc9be82SNikita Kiryanov NEXT_PARAM(argc, index); 414*3dc9be82SNikita Kiryanov cnt = parse_numeric_param(argv[index]); 415*3dc9be82SNikita Kiryanov } 416*3dc9be82SNikita Kiryanov 417*3dc9be82SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 418*3dc9be82SNikita Kiryanov if (action == EEPROM_UPDATE) { 419*3dc9be82SNikita Kiryanov field_name = argv[index]; 420*3dc9be82SNikita Kiryanov NEXT_PARAM(argc, index); 421aa9e6044SNikita Kiryanov field_value = argv[index]; 422aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 423aa9e6044SNikita Kiryanov } 424*3dc9be82SNikita Kiryanov #endif 425aa9e6044SNikita Kiryanov 426aa9e6044SNikita Kiryanov return eeprom_execute_command(action, i2c_bus, i2c_addr, layout_ver, 427*3dc9be82SNikita Kiryanov field_name, field_value, addr, off, cnt); 4282e192b24SSimon Glass } 4292e192b24SSimon Glass 4302e192b24SSimon Glass U_BOOT_CMD( 431aa9e6044SNikita Kiryanov eeprom, 8, 1, do_eeprom, 4322e192b24SSimon Glass "EEPROM sub-system", 4332e192b24SSimon Glass "read <bus> <devaddr> addr off cnt\n" 4342e192b24SSimon Glass "eeprom write <bus> <devaddr> addr off cnt\n" 4352e192b24SSimon Glass " - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'" 436aa9e6044SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 437aa9e6044SNikita Kiryanov "\n" 438*3dc9be82SNikita Kiryanov "eeprom print [-l <layout_version>] <bus> <devaddr>\n" 439aa9e6044SNikita Kiryanov " - Print layout fields and their data in human readable format\n" 440*3dc9be82SNikita Kiryanov "eeprom update [-l <layout_version>] <bus> <devaddr> field_name field_value\n" 441aa9e6044SNikita Kiryanov " - Update a specific eeprom field with new data.\n" 442aa9e6044SNikita Kiryanov " The new data must be written in the same human readable format as shown by the print command.\n" 443aa9e6044SNikita Kiryanov "\n" 444aa9e6044SNikita Kiryanov "LAYOUT VERSIONS\n" 445aa9e6044SNikita Kiryanov "The -l option can be used to force the command to interpret the EEPROM data using the chosen layout.\n" 446aa9e6044SNikita Kiryanov "If the -l option is omitted, the command will auto detect the layout based on the data in the EEPROM.\n" 447aa9e6044SNikita Kiryanov "The values which can be provided with the -l option are:\n" 448aa9e6044SNikita Kiryanov CONFIG_EEPROM_LAYOUT_HELP_STRING"\n" 449aa9e6044SNikita Kiryanov #endif 4502e192b24SSimon Glass ) 451