Commit d44ace7e authored by Alessandro Rubini's avatar Alessandro Rubini

w1: complete eeprom low-level support

This completes w1-eeproom.c with the complete API. The provided test
commands allow to read and write any size at any offset (the low-level
code manages cross-page reads and writes. The following examples
modify a pre-written eeprom, which I host in an external socket of
my SPEC card:

   wrc# w1r 0 4
   read(0x0, 4): result = 4
   offset    0 (0x000): 240 (0xf0)
   offset    1 (0x001): 241 (0xf1)
   offset    2 (0x002): 242 (0xf2)
   offset    3 (0x003): 243 (0xf3)

   wrc# w1w 0 40 41 42
   offset    0 (0x000):  40 (0x28)
   offset    1 (0x001):  41 (0x29)
   offset    2 (0x002):  42 (0x2a)
   write(0x0, 3): result = 3

   wrc# w1r 0 4
   read(0x0, 4): result = 4
   offset    0 (0x000):  40 (0x28)
   offset    1 (0x001):  41 (0x29)
   offset    2 (0x002):  42 (0x2a)
   offset    3 (0x003): 243 (0xf3)

   wrc# w1r 30 4
   read(0x1e, 4): result = 4
   offset   30 (0x01e):  69 (0x45)
   offset   31 (0x01f):  70 (0x46)
   offset   32 (0x020):  71 (0x47)
   offset   33 (0x021):  72 (0x48)

   wrc# w1w 30 11 22 33 44 55 66
   offset   30 (0x01e):  11 (0x0b)
   offset   31 (0x01f):  22 (0x16)
   offset   32 (0x020):  33 (0x21)
   offset   33 (0x021):  44 (0x2c)
   offset   34 (0x022):  55 (0x37)
   offset   35 (0x023):  66 (0x42)
   write(0x1e, 6): result = 6

   wrc# w1r 30 6
   read(0x1e, 6): result = 6
   offset   30 (0x01e):  11 (0x0b)
   offset   31 (0x01f):  22 (0x16)
   offset   32 (0x020):  33 (0x21)
   offset   33 (0x021):  44 (0x2c)
   offset   34 (0x022):  55 (0x37)
   offset   35 (0x023):  66 (0x42)
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent e039c343
/* /*
* Eeprom support * Eeprom support (family 0x43)
* Cesar Prados, 2013 GNU GPL2 or later * Cesar Prados, Alessandro Rubini, 2013. GNU GPL2 or later
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
...@@ -11,39 +11,87 @@ ...@@ -11,39 +11,87 @@
#define LSB_ADDR(X) ((X) & 0xFF) #define LSB_ADDR(X) ((X) & 0xFF)
#define MSB_ADDR(X) (((X) & 0xFF00)>>8) #define MSB_ADDR(X) (((X) & 0xFF00)>>8)
int w1_write_eeprom(struct w1_dev *dev, int offset, const uint8_t *buffer, static int w1_write_page(struct w1_dev *dev, int offset, const uint8_t *buffer,
int blen) int blen)
{ {
int i; int i, j, es;
int read_data;
/* First, write scratchpad */
w1_match_rom(dev); w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDR_W_SPAD); w1_write_byte(dev->bus, W1_CMDR_W_SPAD);
w1_write_byte(dev->bus, LSB_ADDR(offset)); w1_write_byte(dev->bus, LSB_ADDR(offset));
w1_write_byte(dev->bus, MSB_ADDR(offset)); w1_write_byte(dev->bus, MSB_ADDR(offset));
for(i = 0; i < blen; i++)
for(i = 0; i < 32; i++)
w1_write_byte(dev->bus, buffer[i]); w1_write_byte(dev->bus, buffer[i]);
/* Then, read it back, and remember the return E/S */
w1_match_rom(dev); w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDR_C_SPAD); w1_write_byte(dev->bus, W1_CMDR_R_SPAD);
if (w1_read_byte(dev->bus) != LSB_ADDR(offset))
return -1;
if (w1_read_byte(dev->bus) != MSB_ADDR(offset))
return -2;
es = w1_read_byte(dev->bus);
for(i = 0; i < blen; i++) {
j = w1_read_byte(dev->bus);
if (j != buffer[i])
return -3;
}
/* Finally, "copy scratchpad" to actually write */
w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDR_C_SPAD);
w1_write_byte(dev->bus, LSB_ADDR(offset)); w1_write_byte(dev->bus, LSB_ADDR(offset));
w1_write_byte(dev->bus, MSB_ADDR(offset)); w1_write_byte(dev->bus, MSB_ADDR(offset));
w1_write_byte(dev->bus, es);
usleep(10000); /* 10ms, in theory */
w1_write_byte(dev->bus, 0x1f); /* Don't read back, as nothing useful is there (I get 0xf9, why?) */
usleep(10000); return blen;
}
read_data = w1_read_byte(dev->bus); int w1_write_eeprom(struct w1_dev *dev, int offset, const uint8_t *buffer,
if (read_data != 0xaa) int blen)
return -1; {
return 0; int i, page, endpage;
int ret = 0;
/* Split the write into several page-local writes */
page = offset / 32;
endpage = (offset + blen - 1) / 32;
/* Traling part of first page */
if (offset % 32) {
if (endpage != page)
i = 32 - (offset % 32);
else
i = blen;
ret += w1_write_page(dev, offset, buffer, i);
if (ret < 0)
return ret;
buffer += i;
offset += i;
blen -= i;
}
/* Whole pages and leading part of last page */
while (blen > 0 ) {
i = blen;
if (blen > 32)
i = 32;
i = w1_write_page(dev, offset, buffer, i);
if (i < 0)
return i;
ret += i;
buffer += 32;
offset += 32;
blen -= 32;
}
return ret;
} }
int w1_read_eeprom(struct w1_dev *dev, int offset, uint8_t *buffer, int blen) int w1_read_eeprom(struct w1_dev *dev, int offset, uint8_t *buffer, int blen)
{ {
int i; int i;
w1_match_rom(dev); w1_match_rom(dev);
...@@ -52,34 +100,63 @@ int w1_read_eeprom(struct w1_dev *dev, int offset, uint8_t *buffer, int blen) ...@@ -52,34 +100,63 @@ int w1_read_eeprom(struct w1_dev *dev, int offset, uint8_t *buffer, int blen)
w1_write_byte(dev->bus, LSB_ADDR(offset)); w1_write_byte(dev->bus, LSB_ADDR(offset));
w1_write_byte(dev->bus, MSB_ADDR(offset)); w1_write_byte(dev->bus, MSB_ADDR(offset));
for(i = 0; i < 32; i++) /* There is no page-size limit in reading, just go on at will */
for(i = 0; i < blen; i++)
buffer[i] = w1_read_byte(dev->bus); buffer[i] = w1_read_byte(dev->bus);
return 0; return blen;
} }
/* A shell command, for testing write*/ int w1_read_eeprom_bus(struct w1_bus *bus,
static int cmd_w1_w(const char *args[]) int offset, uint8_t *buffer, int blen)
{ {
struct w1_dev *d; int i, class;
int page;
int blen; for (i = 0; i < W1_MAX_DEVICES; i++) {
char pn[32]="\0"; class = w1_class(bus->devs + i);
if (class == 0x43)
return w1_read_eeprom(bus->devs + i, offset,
buffer, blen);
}
/* not found */
return -1;
}
d = wrpc_w1_bus.devs + 1; int w1_write_eeprom_bus(struct w1_bus *bus,
int offset, const uint8_t *buffer, int blen)
{
int i, class;
pp_printf("Writing in device: %08x%08x\n", for (i = 0; i < W1_MAX_DEVICES; i++) {
(int)(d->rom >> 32), (int)d->rom); class = w1_class(bus->devs + i);
if (class == 0x43)
return w1_write_eeprom(bus->devs + i, offset,
buffer, blen);
}
/* not found */
return -1;
}
page = atoi(args[0]); #define BLEN 32
blen = strlen(args[1]); /* A shell command, for testing write: "w1w <offset> <byte> [<byte> ...]" */
memcpy(pn, args[1], blen); static int cmd_w1_w(const char *args[])
if(!w1_write_eeprom(d, page*0x20, (uint8_t *)pn, blen)) {
pp_printf("Write success\n"); int offset, i, blen;
unsigned char buf[BLEN];
return 0; if (!args[0] || !args[1])
return -1;
offset = atoi(args[0]);
for (i = 1, blen = 0; args[i] && blen < BLEN; i++, blen++) {
buf[blen] = atoi(args[i]);
pp_printf("offset %4i (0x%03x): %3i (0x%02x)\n",
offset + blen, offset + blen, buf[blen], buf[blen]);
}
i = w1_write_eeprom_bus(&wrpc_w1_bus, offset, buf, blen);
pp_printf("write(0x%x, %i): result = %i\n", offset, blen, i);
return i == blen ? 0 : -1;
} }
DEFINE_WRC_COMMAND(w1w) = { DEFINE_WRC_COMMAND(w1w) = {
...@@ -87,77 +164,29 @@ DEFINE_WRC_COMMAND(w1w) = { ...@@ -87,77 +164,29 @@ DEFINE_WRC_COMMAND(w1w) = {
.exec = cmd_w1_w, .exec = cmd_w1_w,
}; };
/* A shell command, for testing read*/ /* A shell command, for testing read: "w1w <offset> <len> */
static int cmd_w1_r(const char *args[]) static int cmd_w1_r(const char *args[])
{ {
struct w1_dev *d; int offset, i, blen;
int page; unsigned char buf[BLEN];
int i;
char pn[32]="\0";
d = wrpc_w1_bus.devs + 1;
pp_printf("Reading from device: %08x%08x\n",
(int)(d->rom >> 32), (int)d->rom);
page = atoi(args[0]);
w1_read_eeprom(d, page*0x20, (uint8_t *)pn, 32);
for(i=0;i<32;i++) if (!args[0] || !args[1])
pp_printf("%c",pn[i]); return -1;
offset = atoi(args[0]);
pp_printf("\n"); blen = atoi(args[1]);
if (blen > BLEN)
return 0; blen = BLEN;
i = w1_read_eeprom_bus(&wrpc_w1_bus, offset, buf, blen);
pp_printf("read(0x%x, %i): result = %i\n", offset, blen, i);
if (i <= 0 || i > blen) return -1;
for (blen = 0; blen < i; blen++) {
pp_printf("offset %4i (0x%03x): %3i (0x%02x)\n",
offset + blen, offset + blen, buf[blen], buf[blen]);
}
return i == blen ? 0 : -1;
} }
DEFINE_WRC_COMMAND(w1r) = { DEFINE_WRC_COMMAND(w1r) = {
.name = "w1r", .name = "w1r",
.exec = cmd_w1_r, .exec = cmd_w1_r,
}; };
/* A shell command, for testing write/read*/
static int cmd_w1_test(const char *args[])
{
struct w1_dev *d;
int page;
int errors=0;
int blen;
int i;
char pn[32]="testing";
blen = strlen(pn);
d = wrpc_w1_bus.devs + 1;
pp_printf("Writing in device: %08x%08x\n",
(int)(d->rom >> 32), (int)d->rom);
for(page = 0; page < 80; page++) {
if(!w1_write_eeprom(d, page * 0x20, (uint8_t *)pn, blen)) {
pp_printf("Page %i: success\n", page);
} else {
pp_printf("Page %i: error\n", page);
errors++;
}
}
pp_printf("Write Errors: %d \n", errors);
usleep(1000 * 1000);
for(page = 0; page < 80; page++) {
w1_read_eeprom(d, page * 0x20, (uint8_t *)pn, 32);
for(i = 0; i < 32; i++)
pp_printf("%c",pn[i]);
pp_printf("\n");
}
return 0;
}
DEFINE_WRC_COMMAND(w1test) = {
.name = "w1test",
.exec = cmd_w1_test,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment