diff options
author | Michael Brown <mcb30@etherboot.org> | 2009-05-28 14:45:32 +0100 |
---|---|---|
committer | Michael Brown <mcb30@etherboot.org> | 2009-05-28 19:32:03 +0100 |
commit | 92a9978b4403628345ca03ba4edc7641352460fa (patch) | |
tree | 02626e7d3a3970b7b14cb4dd6f76211c447057cf /src/drivers/nvs | |
parent | 8afafb65322a3fec01206720a1d8be4083e9c0d6 (diff) | |
download | ipxe-92a9978b4403628345ca03ba4edc7641352460fa.tar.gz |
[spi] Add address-length autodetection to the SPI bit-bashing code
Several SPI chips will respond to an SPI read command with a dummy
zero bit immediately prior to the first real data bit. This can be
used to autodetect the address length, provided that the command
length and data length are already known, and that the MISO data line
is tied high.
Tested-by: Thomas Miletich <thomas.miletich@gmail.com>
Debugged-by: Thomas Miletich <thomas.miletich@gmail.com>
Diffstat (limited to 'src/drivers/nvs')
-rw-r--r-- | src/drivers/nvs/threewire.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/src/drivers/nvs/threewire.c b/src/drivers/nvs/threewire.c index f7a20bbef..8e5213893 100644 --- a/src/drivers/nvs/threewire.c +++ b/src/drivers/nvs/threewire.c @@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stddef.h> +#include <string.h> #include <assert.h> #include <unistd.h> #include <gpxe/threewire.h> @@ -42,13 +43,21 @@ int threewire_read ( struct nvs_device *nvs, unsigned int address, void *data, size_t len ) { struct spi_device *device = nvs_to_spi ( nvs ); struct spi_bus *bus = device->bus; + int rc; assert ( bus->mode == SPI_MODE_THREEWIRE ); - DBG ( "3wire %p reading %zd bytes at %04x\n", device, len, address ); + DBGC ( device, "3wire %p reading %zd bytes at %04x\n", + device, len, address ); + + if ( ( rc = bus->rw ( bus, device, THREEWIRE_READ, address, + NULL, data, len ) ) != 0 ) { + DBGC ( device, "3wire %p could not read: %s\n", + device, strerror ( rc ) ); + return rc; + } - return bus->rw ( bus, device, THREEWIRE_READ, address, - NULL, data, len ); + return 0; } /** @@ -68,17 +77,24 @@ int threewire_write ( struct nvs_device *nvs, unsigned int address, assert ( bus->mode == SPI_MODE_THREEWIRE ); - DBG ( "3wire %p writing %zd bytes at %04x\n", device, len, address ); + DBGC ( device, "3wire %p writing %zd bytes at %04x\n", + device, len, address ); /* Enable device for writing */ if ( ( rc = bus->rw ( bus, device, THREEWIRE_EWEN, - THREEWIRE_EWEN_ADDRESS, NULL, NULL, 0 ) ) != 0 ) + THREEWIRE_EWEN_ADDRESS, NULL, NULL, 0 ) ) != 0 ){ + DBGC ( device, "3wire %p could not enable writing: %s\n", + device, strerror ( rc ) ); return rc; + } /* Write data */ if ( ( rc = bus->rw ( bus, device, THREEWIRE_WRITE, address, - data, NULL, len ) ) != 0 ) + data, NULL, len ) ) != 0 ) { + DBGC ( device, "3wire %p could not write: %s\n", + device, strerror ( rc ) ); return rc; + } /* Our model of an SPI bus doesn't provide a mechanism for * "assert CS, wait for MISO to become high, so just wait for @@ -88,3 +104,28 @@ int threewire_write ( struct nvs_device *nvs, unsigned int address, return 0; } + +/** + * Autodetect device address length + * + * @v device SPI device + * @ret rc Return status code + */ +int threewire_detect_address_len ( struct spi_device *device ) { + struct nvs_device *nvs = &device->nvs; + int rc; + + DBGC ( device, "3wire %p autodetecting address length\n", device ); + + device->address_len = SPI_AUTODETECT_ADDRESS_LEN; + if ( ( rc = threewire_read ( nvs, 0, NULL, + ( 1 << nvs->word_len_log2 ) ) ) != 0 ) { + DBGC ( device, "3wire %p could not autodetect address " + "length: %s\n", device, strerror ( rc ) ); + return rc; + } + + DBGC ( device, "3wire %p autodetected address length %d\n", + device, device->address_len ); + return 0; +} |