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, 0); 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 0 given that the enable level is driven 113 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 _clock_device->set(_clock_pin, 0); 132 133 return bytes; 134 } 135 136 /* Send a number of units, each holding a value limited to the given character 137 size, with any bit immediately above the character portion of the unit 138 indicating the data/command level. */ 139 140 uint32_t Spi_gpio::send_units(uint32_t bytes, const uint8_t data[], 141 uint8_t unit_size, uint8_t char_size, 142 bool big_endian) 143 { 144 uint32_t char_units = bytes / unit_size; 145 uint8_t char_unit_size = ((char_size ? char_size - 1 : 0) / 8) + 1; 146 147 /* Obtain the data/command values for each unit. */ 148 /* Obtain the actual character bytes to be sent. */ 149 150 /* NOTE: Work around stack allocation limitations in L4Re. We would want to 151 use a static allocation as follows: 152 153 int dc[char_units]; 154 uint8_t char_data[char_unit_size * char_units]; 155 */ 156 157 int *dc = (int *) calloc(char_units, sizeof(int)); 158 uint8_t *char_data = (uint8_t *) calloc(char_units, char_unit_size); 159 160 /* Traverse the byte sequence, extracting data/command bits for each unit. */ 161 162 for (uint32_t offset = 0, char_unit = 0, char_offset = 0; char_unit < char_units; 163 offset += unit_size, char_unit++, char_offset += char_unit_size) 164 { 165 /* Obtain the unit value. */ 166 167 uint32_t value = get_stored_value(&data[offset], unit_size, big_endian); 168 169 /* The unit size must be greater than the character size for data/command 170 bits to be present. */ 171 172 if (unit_size * 8 > char_size) 173 dc[char_unit] = value & (1 << char_size) ? 1 : 0; 174 175 /* Obtain the actual character data from the input data, discarding the most 176 significant bytes beyond the character and masking out any remaining 177 superfluous bits, thus obtaining a whole number of bytes. */ 178 179 value = value & ((1 << char_size) - 1); 180 181 set_stored_value(value, &char_data[char_offset], char_unit_size, big_endian); 182 } 183 184 /* Discard the data/command values if they will not be used. */ 185 186 uint32_t result = send_dc(char_units * char_unit_size, char_data, 187 (unit_size * 8 <= char_size) ? NULL : dc, 188 char_size, big_endian); 189 190 /* NOTE: Working around allocation limitations with dc... */ 191 192 free(dc); 193 free(char_data); 194 return result; 195 } 196 197 /* Perform a transfer, ignoring any DMA-specific parameters. */ 198 199 uint32_t Spi_gpio::transfer(l4_addr_t vaddr, 200 l4re_dma_space_dma_addr_t paddr, 201 uint32_t count, uint8_t unit_size, 202 uint8_t char_size, 203 l4_addr_t desc_vaddr, 204 l4re_dma_space_dma_addr_t desc_paddr) 205 { 206 (void) paddr; (void) desc_vaddr; (void) desc_paddr; 207 208 /* Assume little endian data is being transferred, being the native data 209 representation. */ 210 211 return send_units(count, (const uint8_t *) vaddr, unit_size, char_size, 212 false); 213 } 214 215 216 217 /* C language interface. */ 218 219 void *spi_gpio_get_channel(uint64_t frequency, 220 void *clock_chip, int clock_pin, 221 void *data_chip, int data_pin, 222 void *enable_chip, int enable_pin, 223 void *control_chip, int control_pin) 224 { 225 return (void *) new Spi_gpio(frequency, 226 reinterpret_cast<Hw::Gpio_chip *>(clock_chip), clock_pin, 227 reinterpret_cast<Hw::Gpio_chip *>(data_chip), data_pin, 228 reinterpret_cast<Hw::Gpio_chip *>(enable_chip), enable_pin, 229 reinterpret_cast<Hw::Gpio_chip *>(control_chip), control_pin); 230 } 231 232 uint32_t spi_gpio_send(void *channel, uint32_t bytes, const uint8_t data[]) 233 { 234 return static_cast<Spi_gpio *>(channel)->send(bytes, data); 235 } 236 237 uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[], 238 const int dc[], uint8_t char_size, int big_endian) 239 { 240 return static_cast<Spi_gpio *>(channel)->send_dc(bytes, data, dc, char_size, 241 big_endian); 242 } 243 244 uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[], 245 uint8_t unit_size, uint8_t char_size, int big_endian) 246 { 247 return static_cast<Spi_gpio *>(channel)->send_units(bytes, data, unit_size, 248 char_size, big_endian); 249 } 250 251 uint32_t spi_gpio_transfer(void *channel, l4_addr_t vaddr, 252 l4re_dma_space_dma_addr_t paddr, 253 uint32_t count, uint8_t unit_size, 254 uint8_t char_size) 255 { 256 return static_cast<Spi_gpio *>(channel)->transfer(vaddr, paddr, count, 257 unit_size, char_size); 258 } 259 260 uint32_t spi_gpio_transfer_descriptor(void *channel, l4_addr_t vaddr, 261 l4re_dma_space_dma_addr_t paddr, 262 uint32_t count, uint8_t unit_size, 263 uint8_t char_size, l4_addr_t desc_vaddr, 264 l4re_dma_space_dma_addr_t desc_paddr) 265 { 266 return static_cast<Spi_gpio *>(channel)->transfer(vaddr, paddr, count, 267 unit_size, char_size, desc_vaddr, desc_paddr); 268 }