1 /* 2 * Perform SPI communication using GPIO operations. 3 * 4 * Copyright (C) 2018, 2020, 2023 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/byteorder.h> 23 #include <l4/devices/spi-gpio.h> 24 #include <stdlib.h> /* NOTE: required by calloc/free */ 25 #include <time.h> 26 27 28 29 Spi_gpio::Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin, 30 Hw::Gpio_chip *data_device, int data_pin, 31 Hw::Gpio_chip *enable_device, int enable_pin, 32 Hw::Gpio_chip *control_device, int control_pin) 33 : _clock_device(clock_device), 34 _clock_pin(clock_pin), 35 _data_device(data_device), 36 _data_pin(data_pin), 37 _enable_device(enable_device), 38 _enable_pin(enable_pin), 39 _control_device(control_device), 40 _control_pin(control_pin) 41 { 42 _clock_device->setup(_clock_pin, Hw::Gpio_chip::Output, 1); 43 _data_device->setup(_data_pin, Hw::Gpio_chip::Output, 0); 44 _enable_device->setup(_enable_pin, Hw::Gpio_chip::Output, 1); 45 _control_device->setup(_control_pin, Hw::Gpio_chip::Output, 0); 46 } 47 48 Spi_gpio::Spi_gpio(uint64_t frequency, 49 Hw::Gpio_chip *clock_device, int clock_pin, 50 Hw::Gpio_chip *data_device, int data_pin, 51 Hw::Gpio_chip *enable_device, int enable_pin, 52 Hw::Gpio_chip *control_device, int control_pin) 53 : Spi_gpio(clock_device, clock_pin, data_device, data_pin, enable_device, 54 enable_pin, control_device, control_pin) 55 { 56 _frequency = frequency; 57 } 58 59 /* Send a byte sequence. */ 60 61 uint32_t Spi_gpio::send(uint32_t bytes, const uint8_t data[]) 62 { 63 return send_dc(bytes, data, NULL, 8, false); 64 } 65 66 /* Send a byte sequence with accompanying data/command indicators. Bytes are 67 grouped into character units, with each unit holding a value with the given 68 byte ordering. */ 69 70 uint32_t Spi_gpio::send_dc(uint32_t bytes, const uint8_t data[], 71 const int dc[], uint8_t char_size, bool big_endian) 72 { 73 struct timespec ts; 74 uint32_t offset, char_unit; 75 uint8_t char_unit_size = ((char_size ? char_size - 1 : 0) / 8) + 1; 76 77 if (_frequency) 78 { 79 ts.tv_sec = 0; 80 ts.tv_nsec = 1000000000 / _frequency; 81 } 82 83 /* Initialise pin levels. */ 84 85 _enable_device->set(_enable_pin, 1); 86 _clock_device->set(_clock_pin, 1); 87 _data_device->set(_data_pin, 0); 88 89 if ((_control_device != NULL) && (_control_pin >= 0) && (dc != NULL)) 90 _control_device->set(_control_pin, dc[0] ? 1 : 0); 91 92 /* Enter the transmission state. */ 93 94 _enable_device->set(_enable_pin, 0); 95 96 /* Clock data using the clock and data outputs. */ 97 98 for (offset = 0, char_unit = 0; offset < bytes; offset += char_unit_size, char_unit++) 99 { 100 uint32_t mask, value = get_stored_value(&data[offset], char_unit_size, big_endian); 101 102 /* Set the control level, if appropriate. */ 103 104 if ((_control_device != NULL) && (_control_pin >= 0) && (dc != NULL)) 105 _control_device->set(_control_pin, dc[char_unit] ? 1 : 0); 106 107 mask = 1 << (char_size - 1); 108 109 for (uint8_t bit = 0; bit < char_size; bit++) 110 { 111 /* NOTE: Data presented on falling clock level and sampled on rising clock 112 level. This is SPI mode 3, or 0 given that the enable level is 113 driven low immediately before the first bit is presented. */ 114 115 _clock_device->set(_clock_pin, 0); 116 _data_device->set(_data_pin, value & mask ? 1 : 0); 117 118 if (_frequency) 119 nanosleep(&ts, NULL); 120 121 _clock_device->set(_clock_pin, 1); 122 123 if (_frequency) 124 nanosleep(&ts, NULL); 125 126 mask >>= 1; 127 } 128 } 129 130 _enable_device->set(_enable_pin, 1); 131 132 return bytes; 133 } 134 135 /* Send a number of units, each holding a value limited to the given character 136 size, with any bit immediately above the character portion of the unit 137 indicating the data/command level. */ 138 139 uint32_t Spi_gpio::send_units(uint32_t bytes, const uint8_t data[], 140 uint8_t unit_size, uint8_t char_size, 141 bool big_endian) 142 { 143 uint32_t char_units = bytes / unit_size; 144 uint8_t char_unit_size = ((char_size ? char_size - 1 : 0) / 8) + 1; 145 146 /* Obtain the data/command values for each unit. */ 147 /* Obtain the actual character bytes to be sent. */ 148 149 /* NOTE: Work around stack allocation limitations in L4Re. We would want to 150 use a static allocation as follows: 151 152 int dc[char_units]; 153 uint8_t char_data[char_unit_size * char_units]; 154 */ 155 156 int *dc = (int *) calloc(char_units, sizeof(int)); 157 uint8_t *char_data = (uint8_t *) calloc(char_units, char_unit_size); 158 159 /* Traverse the byte sequence, extracting data/command bits for each unit. */ 160 161 for (uint32_t offset = 0, char_unit = 0, char_offset = 0; char_unit < char_units; 162 offset += unit_size, char_unit++, char_offset += char_unit_size) 163 { 164 /* Obtain the unit value. */ 165 166 uint32_t value = get_stored_value(&data[offset], unit_size, big_endian); 167 168 /* The unit size must be greater than the character size for data/command 169 bits to be present. */ 170 171 if (unit_size * 8 > char_size) 172 dc[char_unit] = value & (1 << char_size) ? 1 : 0; 173 174 /* Obtain the actual character data from the input data, discarding the most 175 significant bytes beyond the character and masking out any remaining 176 superfluous bits, thus obtaining a whole number of bytes. */ 177 178 value = value & ((1 << char_size) - 1); 179 180 set_stored_value(value, &char_data[char_offset], char_unit_size, big_endian); 181 } 182 183 /* Discard the data/command values if they will not be used. */ 184 185 uint32_t result = send_dc(char_units * char_unit_size, char_data, 186 (unit_size * 8 <= char_size) ? NULL : dc, 187 char_size, big_endian); 188 189 /* NOTE: Working around allocation limitations with dc... */ 190 191 free(dc); 192 free(char_data); 193 return result; 194 } 195 196 /* Perform a transfer, ignoring any DMA-specific parameters. */ 197 198 uint32_t Spi_gpio::transfer(l4_addr_t vaddr, 199 l4re_dma_space_dma_addr_t paddr, 200 uint32_t count, uint8_t unit_size, 201 uint8_t char_size, 202 l4_addr_t desc_vaddr, 203 l4re_dma_space_dma_addr_t desc_paddr) 204 { 205 (void) paddr; (void) desc_vaddr; (void) desc_paddr; 206 207 /* Assume little endian data is being transferred, being the native data 208 representation. */ 209 210 return send_units(count, (const uint8_t *) vaddr, unit_size, char_size, 211 false); 212 } 213 214 215 216 /* C language interface. */ 217 218 void *spi_gpio_get_channel(uint64_t frequency, 219 void *clock_chip, int clock_pin, 220 void *data_chip, int data_pin, 221 void *enable_chip, int enable_pin, 222 void *control_chip, int control_pin) 223 { 224 return (void *) new Spi_gpio(frequency, 225 reinterpret_cast<Hw::Gpio_chip *>(clock_chip), clock_pin, 226 reinterpret_cast<Hw::Gpio_chip *>(data_chip), data_pin, 227 reinterpret_cast<Hw::Gpio_chip *>(enable_chip), enable_pin, 228 reinterpret_cast<Hw::Gpio_chip *>(control_chip), control_pin); 229 } 230 231 uint32_t spi_gpio_send(void *channel, uint32_t bytes, const uint8_t data[]) 232 { 233 return static_cast<Spi_gpio *>(channel)->send(bytes, data); 234 } 235 236 uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[], 237 const int dc[], uint8_t char_size, int big_endian) 238 { 239 return static_cast<Spi_gpio *>(channel)->send_dc(bytes, data, dc, char_size, 240 big_endian); 241 } 242 243 uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[], 244 uint8_t unit_size, uint8_t char_size, int big_endian) 245 { 246 return static_cast<Spi_gpio *>(channel)->send_units(bytes, data, unit_size, 247 char_size, big_endian); 248 } 249 250 uint32_t spi_gpio_transfer(void *channel, l4_addr_t vaddr, 251 l4re_dma_space_dma_addr_t paddr, 252 uint32_t count, uint8_t unit_size, 253 uint8_t char_size) 254 { 255 return static_cast<Spi_gpio *>(channel)->transfer(vaddr, paddr, count, 256 unit_size, char_size); 257 } 258 259 uint32_t spi_gpio_transfer_descriptor(void *channel, l4_addr_t vaddr, 260 l4re_dma_space_dma_addr_t paddr, 261 uint32_t count, uint8_t unit_size, 262 uint8_t char_size, l4_addr_t desc_vaddr, 263 l4re_dma_space_dma_addr_t desc_paddr) 264 { 265 return static_cast<Spi_gpio *>(channel)->transfer(vaddr, paddr, count, 266 unit_size, char_size, desc_vaddr, desc_paddr); 267 }