1 /* 2 * Copyright (C) 2006 Michael Brown <mbrown (at) fensystems.co.uk>. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 #include <stddef.h> 22 #include <errno.h> 23 #include <unistd.h> 24 #include <gpxe/spi.h> 25 26 /** @file 27 * 28 * SPI devices 29 * 30 */ 31 32 /** 33 * Munge SPI device address into command 34 * 35 * @v command SPI command 36 * @v address Address 37 * @v munge_address Device requires address munging 38 * @ret command Actual SPI command to use 39 * 40 * Some devices with 9-bit addresses (e.g. AT25040A EEPROM) use bit 3 41 * of the command byte as address bit A8, rather than having a 42 * two-byte address. This function takes care of generating the 43 * appropriate command. 44 */ 45 static inline unsigned int spi_command ( unsigned int command, 46 unsigned int address, 47 int munge_address ) { 48 return ( command | ( ( ( address >> 8 ) & munge_address ) << 3 ) ); 49 } 50 51 /** 52 * Wait for SPI device to complete operation 53 * 54 * @v device SPI device 55 * @ret rc Return status code 56 */ 57 static int spi_wait ( struct spi_device *device ) { 58 struct spi_bus *bus = device->bus; 59 uint8_t status; 60 int i; 61 int rc; 62 63 for ( i = 0 ; i < 50 ; i++ ) { 64 udelay ( 20 ); 65 if ( ( rc = bus->rw ( bus, device, SPI_RDSR, -1, NULL, 66 &status, sizeof ( status ) ) ) != 0 ) 67 return rc; 68 if ( ! ( status & SPI_STATUS_NRDY ) ) 69 return 0; 70 } 71 DBG ( "SPI %p timed out\n", device ); 72 return -ETIMEDOUT; 73 } 74 75 /** 76 * Read data from SPI device 77 * 78 * @v nvs NVS device 79 * @v address Address from which to read 80 * @v data Data buffer 81 * @v len Length of data buffer 82 * @ret rc Return status code 83 */ 84 int spi_read ( struct nvs_device *nvs, unsigned int address, 85 void *data, size_t len ) { 86 struct spi_device *device = nvs_to_spi ( nvs ); 87 struct spi_bus *bus = device->bus; 88 unsigned int command = spi_command ( SPI_READ, address, 89 device->munge_address ); 90 int rc; 91 92 DBG ( "SPI %p reading %zd bytes from %#04x\n", device, len, address ); 93 if ( ( rc = bus->rw ( bus, device, command, address, 94 NULL, data, len ) ) != 0 ) { 95 DBG ( "SPI %p failed to read data from device\n", device ); 96 return rc; 97 } 98 99 return 0; 100 } 101 102 /** 103 * Write data to SPI device 104 * 105 * @v nvs NVS device 106 * @v address Address from which to read 107 * @v data Data buffer 108 * @v len Length of data buffer 109 * @ret rc Return status code 110 */ 111 int spi_write ( struct nvs_device *nvs, unsigned int address, 112 const void *data, size_t len ) { 113 struct spi_device *device = nvs_to_spi ( nvs ); 114 struct spi_bus *bus = device->bus; 115 unsigned int command = spi_command ( SPI_WRITE, address, 116 device->munge_address ); 117 int rc; 118 119 DBG ( "SPI %p writing %zd bytes to %#04x\n", device, len, address ); 120 121 if ( ( rc = bus->rw ( bus, device, SPI_WREN, -1, 122 NULL, NULL, 0 ) ) != 0 ) { 123 DBG ( "SPI %p failed to write-enable device\n", device ); 124 return rc; 125 } 126 127 if ( ( rc = bus->rw ( bus, device, command, address, 128 data, NULL, len ) ) != 0 ) { 129 DBG ( "SPI %p failed to write data to device\n", device ); 130 return rc; 131 } 132 133 if ( ( rc = spi_wait ( device ) ) != 0 ) { 134 DBG ( "SPI %p failed to complete write operation\n", device ); 135 return rc; 136 } 137 138 return 0; 139 } 140 141