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 <string.h> 23 #include <assert.h> 24 #include <unistd.h> 25 #include <gpxe/threewire.h> 26 27 /** @file 28 * 29 * Three-wire serial devices 30 * 31 */ 32 33 /** 34 * Read data from three-wire device 35 * 36 * @v nvs NVS device 37 * @v address Address from which to read 38 * @v data Data buffer 39 * @v len Length of data buffer 40 * @ret rc Return status code 41 */ 42 int threewire_read ( struct nvs_device *nvs, unsigned int address, 43 void *data, size_t len ) { 44 struct spi_device *device = nvs_to_spi ( nvs ); 45 struct spi_bus *bus = device->bus; 46 int rc; 47 48 assert ( bus->mode == SPI_MODE_THREEWIRE ); 49 50 DBGC ( device, "3wire %p reading %zd bytes at %04x\n", 51 device, len, address ); 52 53 if ( ( rc = bus->rw ( bus, device, THREEWIRE_READ, address, 54 NULL, data, len ) ) != 0 ) { 55 DBGC ( device, "3wire %p could not read: %s\n", 56 device, strerror ( rc ) ); 57 return rc; 58 } 59 60 return 0; 61 } 62 63 /** 64 * Write data to three-wire device 65 * 66 * @v nvs NVS device 67 * @v address Address from which to read 68 * @v data Data buffer 69 * @v len Length of data buffer 70 * @ret rc Return status code 71 */ 72 int threewire_write ( struct nvs_device *nvs, unsigned int address, 73 const void *data, size_t len ) { 74 struct spi_device *device = nvs_to_spi ( nvs ); 75 struct spi_bus *bus = device->bus; 76 int rc; 77 78 assert ( bus->mode == SPI_MODE_THREEWIRE ); 79 80 DBGC ( device, "3wire %p writing %zd bytes at %04x\n", 81 device, len, address ); 82 83 /* Enable device for writing */ 84 if ( ( rc = bus->rw ( bus, device, THREEWIRE_EWEN, 85 THREEWIRE_EWEN_ADDRESS, NULL, NULL, 0 ) ) != 0 ){ 86 DBGC ( device, "3wire %p could not enable writing: %s\n", 87 device, strerror ( rc ) ); 88 return rc; 89 } 90 91 /* Write data */ 92 if ( ( rc = bus->rw ( bus, device, THREEWIRE_WRITE, address, 93 data, NULL, len ) ) != 0 ) { 94 DBGC ( device, "3wire %p could not write: %s\n", 95 device, strerror ( rc ) ); 96 return rc; 97 } 98 99 /* Our model of an SPI bus doesn't provide a mechanism for 100 * "assert CS, wait for MISO to become high, so just wait for 101 * long enough to ensure that the write has completed. 102 */ 103 mdelay ( THREEWIRE_WRITE_MDELAY ); 104 105 return 0; 106 } 107 108 /** 109 * Autodetect device address length 110 * 111 * @v device SPI device 112 * @ret rc Return status code 113 */ 114 int threewire_detect_address_len ( struct spi_device *device ) { 115 struct nvs_device *nvs = &device->nvs; 116 int rc; 117 118 DBGC ( device, "3wire %p autodetecting address length\n", device ); 119 120 device->address_len = SPI_AUTODETECT_ADDRESS_LEN; 121 if ( ( rc = threewire_read ( nvs, 0, NULL, 122 ( 1 << nvs->word_len_log2 ) ) ) != 0 ) { 123 DBGC ( device, "3wire %p could not autodetect address " 124 "length: %s\n", device, strerror ( rc ) ); 125 return rc; 126 } 127 128 DBGC ( device, "3wire %p autodetected address length %d\n", 129 device, device->address_len ); 130 return 0; 131 } 132