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/spi-gpio.h> 23 #include <time.h> 24 25 26 27 Spi_gpio::Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin, 28 Hw::Gpio_chip *data_device, int data_pin, 29 Hw::Gpio_chip *enable_device, int enable_pin, 30 Hw::Gpio_chip *control_device, int control_pin) 31 : _clock_device(clock_device), 32 _clock_pin(clock_pin), 33 _data_device(data_device), 34 _data_pin(data_pin), 35 _enable_device(enable_device), 36 _enable_pin(enable_pin), 37 _control_device(control_device), 38 _control_pin(control_pin) 39 { 40 _clock_device->setup(_clock_pin, Hw::Gpio_chip::Output, 1); 41 _data_device->setup(_data_pin, Hw::Gpio_chip::Output, 0); 42 _enable_device->setup(_enable_pin, Hw::Gpio_chip::Output, 1); 43 _control_device->setup(_control_pin, Hw::Gpio_chip::Output, 0); 44 } 45 46 Spi_gpio::Spi_gpio(uint64_t frequency, 47 Hw::Gpio_chip *clock_device, int clock_pin, 48 Hw::Gpio_chip *data_device, int data_pin, 49 Hw::Gpio_chip *enable_device, int enable_pin, 50 Hw::Gpio_chip *control_device, int control_pin) 51 : Spi_gpio(clock_device, clock_pin, data_device, data_pin, enable_device, 52 enable_pin, control_device, control_pin) 53 { 54 _frequency = frequency; 55 } 56 57 /* Send a byte sequence. */ 58 59 uint32_t Spi_gpio::send(uint32_t bytes, const uint8_t data[]) 60 { 61 return send_dc(bytes, data, NULL); 62 } 63 64 /* Send a byte sequence with accompanying data/command indicators. */ 65 66 uint32_t Spi_gpio::send_dc(uint32_t bytes, const uint8_t data[], 67 const int dc[]) 68 { 69 struct timespec ts; 70 uint8_t mask; 71 int bit; 72 uint32_t byte; 73 74 if (_frequency) 75 { 76 ts.tv_sec = 0; 77 ts.tv_nsec = 1000000000 / _frequency; 78 } 79 80 /* Initialise pin levels. */ 81 82 _enable_device->set(_enable_pin, 1); 83 _clock_device->set(_clock_pin, 1); 84 _data_device->set(_data_pin, 0); 85 86 /* Enter the transmission state. */ 87 88 _enable_device->set(_enable_pin, 0); 89 90 /* Clock data using the clock and data outputs. */ 91 92 for (byte = 0; byte < bytes; byte++) 93 { 94 mask = 0x80; 95 96 for (bit = 0; bit < 8; bit++) 97 { 98 /* NOTE: Data presented on falling clock level and sampled on rising clock 99 level. This is SPI mode 3, or 0 given that the enable level is 100 driven low immediately before the first bit is presented. */ 101 102 _clock_device->set(_clock_pin, 0); 103 _data_device->set(_data_pin, data[byte] & mask ? 1 : 0); 104 105 if ((_control_device != NULL) && (_control_pin >= 0) && (dc != NULL)) 106 _control_device->set(_control_pin, dc[byte] ? 1 : 0); 107 108 if (_frequency) 109 nanosleep(&ts, NULL); 110 111 _clock_device->set(_clock_pin, 1); 112 113 if (_frequency) 114 nanosleep(&ts, NULL); 115 116 mask >>= 1; 117 } 118 } 119 120 _enable_device->set(_enable_pin, 1); 121 122 return bytes; 123 } 124 125 /* Send a number of units, each holding a value in a big endian arrangement 126 limited to the given character size, with any bit immediately above the 127 character portion of the unit indicating the data/command level. */ 128 129 uint32_t Spi_gpio::send_units(uint32_t bytes, const uint8_t data[], 130 uint8_t unit_size, uint8_t char_size) 131 { 132 /* Obtain the data/command values for each unit. */ 133 134 uint32_t chars = bytes / unit_size; 135 int dc[chars]; 136 137 /* Obtain the actual character bytes to be sent. */ 138 139 int char_unit_size = ((char_size ? char_size - 1 : 0) / 8) + 1; 140 uint8_t char_data[char_unit_size * chars]; 141 142 /* Traverse the byte sequence, extracting data/command bits for each unit. */ 143 144 for (uint32_t offset = 0, unit = 0, char_offset = 0; unit < chars; 145 offset += unit_size, unit++, char_offset += char_unit_size) 146 { 147 /* Obtain the unit value. */ 148 149 uint32_t value = 0; 150 151 for (uint8_t byte = 0; byte < unit_size; byte++) 152 value = (value << 8) | data[offset + byte]; 153 154 /* The unit size must be greater than the character size for data/command 155 bits to be present. */ 156 157 if (unit_size * 8 <= char_size) 158 dc[unit] = 0; 159 160 /* Extract the data/command level. */ 161 162 else 163 dc[unit] = value & (1 << char_size) ? 1 : 0; 164 165 /* Obtain the actual character data from the input data, discarding the most 166 significant bytes beyond the character and masking out any remaining 167 superfluous bits, thus obtaining a whole number of bytes. */ 168 169 value = value & ((1 << char_size) - 1); 170 171 for (uint8_t byte = char_unit_size; byte != 0; byte--) 172 { 173 char_data[char_offset + byte - 1] = value & 0xff; 174 value >>= 8; 175 } 176 } 177 178 return send_dc(chars, char_data, dc); 179 } 180 181 182 183 /* C language interface. */ 184 185 void *spi_gpio_get_channel(uint64_t frequency, 186 void *clock_chip, int clock_pin, 187 void *data_chip, int data_pin, 188 void *enable_chip, int enable_pin, 189 void *control_chip, int control_pin) 190 { 191 return (void *) new Spi_gpio(frequency, 192 reinterpret_cast<Hw::Gpio_chip *>(clock_chip), clock_pin, 193 reinterpret_cast<Hw::Gpio_chip *>(data_chip), data_pin, 194 reinterpret_cast<Hw::Gpio_chip *>(enable_chip), enable_pin, 195 reinterpret_cast<Hw::Gpio_chip *>(control_chip), control_pin); 196 } 197 198 uint32_t spi_gpio_send(void *channel, uint32_t bytes, const uint8_t data[]) 199 { 200 return static_cast<Spi_gpio *>(channel)->send(bytes, data); 201 } 202 203 uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[], 204 const int dc[]) 205 { 206 return static_cast<Spi_gpio *>(channel)->send_dc(bytes, data, dc); 207 } 208 209 uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[], 210 uint8_t unit_size, uint8_t char_size) 211 { 212 return static_cast<Spi_gpio *>(channel)->send_units(bytes, data, unit_size, char_size); 213 }