Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | /** * Copyright (c) 2018 Linaro * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT inventek_eswifi #include "eswifi_log.h" LOG_MODULE_DECLARE(LOG_MODULE_NAME); #include <zephyr/zephyr.h> #include <zephyr/kernel.h> #include <zephyr/device.h> #include <string.h> #include <errno.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/spi.h> #include "eswifi.h" #define ESWIFI_SPI_THREAD_STACK_SIZE 1024 K_KERNEL_STACK_MEMBER(eswifi_spi_poll_stack, ESWIFI_SPI_THREAD_STACK_SIZE); #define SPI_READ_CHUNK_SIZE 32 struct eswifi_spi_data { struct spi_dt_spec bus; struct eswifi_gpio csn; struct eswifi_gpio dr; struct k_thread poll_thread; }; static struct eswifi_spi_data eswifi_spi0 = { /* Static instance */ .bus = SPI_DT_SPEC_INST_GET(0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(16) | SPI_HOLD_ON_CS | SPI_LOCK_ON, 1000U), }; static bool eswifi_spi_cmddata_ready(struct eswifi_spi_data *spi) { return gpio_pin_get(spi->dr.dev, spi->dr.pin) > 0; } static int eswifi_spi_wait_cmddata_ready(struct eswifi_spi_data *spi) { unsigned int max_retries = 60 * 1000; /* 1 minute */ do { /* allow other threads to be scheduled */ k_sleep(K_MSEC(1)); } while (!eswifi_spi_cmddata_ready(spi) && --max_retries); return max_retries ? 0 : -ETIMEDOUT; } static int eswifi_spi_write(struct eswifi_dev *eswifi, char *data, size_t dlen) { struct eswifi_spi_data *spi = eswifi->bus_data; struct spi_buf spi_tx_buf[1]; struct spi_buf_set spi_tx; int status; spi_tx_buf[0].buf = data; spi_tx_buf[0].len = dlen / 2; /* 16-bit words */ spi_tx.buffers = spi_tx_buf; spi_tx.count = ARRAY_SIZE(spi_tx_buf); status = spi_write_dt(&spi->bus, &spi_tx); if (status) { LOG_ERR("SPI write error %d", status); } else { status = dlen; } return status; } static int eswifi_spi_read(struct eswifi_dev *eswifi, char *data, size_t dlen) { struct eswifi_spi_data *spi = eswifi->bus_data; struct spi_buf spi_rx_buf[1]; struct spi_buf_set spi_rx; int status; spi_rx_buf[0].buf = data; spi_rx_buf[0].len = dlen / 2; /* 16-bit words */ spi_rx.buffers = spi_rx_buf; spi_rx.count = ARRAY_SIZE(spi_rx_buf); status = spi_read_dt(&spi->bus, &spi_rx); if (status) { LOG_ERR("SPI read error %d", status); } else { status = dlen; } return status; } static int eswifi_spi_request(struct eswifi_dev *eswifi, char *cmd, size_t clen, char *rsp, size_t rlen) { struct eswifi_spi_data *spi = eswifi->bus_data; unsigned int offset = 0U, to_read = SPI_READ_CHUNK_SIZE; char tmp[2]; int err; LOG_DBG("cmd=%p (%u byte), rsp=%p (%u byte)", cmd, clen, rsp, rlen); /* * CMD/DATA protocol: * 1. Module raises data-ready when ready for **command phase** * 2. Host announces command start by lowering chip-select (csn) * 3. Host write the command (possibly several spi transfers) * 4. Host announces end of command by raising chip-select * 5. Module lowers data-ready signal * 6. Module raises data-ready to signal start of the **data phase** * 7. Host lowers chip-select * 8. Host fetch data as long as data-ready pin is up * 9. Module lowers data-ready to signal the end of the data Phase * 10. Host raises chip-select * * Note: * All commands to the eS-WiFi module must be post-padded with * 0x0A (Line Feed) to an even number of bytes. * All data from eS-WiFi module are post-padded with 0x15(NAK) to an * even number of bytes. */ if (!cmd) { goto data; } /* CMD/DATA READY signals the Command Phase */ err = eswifi_spi_wait_cmddata_ready(spi); if (err) { LOG_ERR("CMD ready timeout\n"); return err; } if (clen % 2) { /* Add post-padding if necessary */ /* cmd is a string so cmd[clen] is 0x00 */ cmd[clen] = 0x0a; clen++; } eswifi_spi_write(eswifi, cmd, clen); /* Our device is flagged with SPI_HOLD_ON_CS|SPI_LOCK_ON, release */ spi_release_dt(&spi->bus); data: /* CMD/DATA READY signals the Data Phase */ err = eswifi_spi_wait_cmddata_ready(spi); if (err) { LOG_ERR("DATA ready timeout\n"); return err; } while (eswifi_spi_cmddata_ready(spi) && to_read) { to_read = MIN(rlen - offset, to_read); memset(rsp + offset, 0, to_read); eswifi_spi_read(eswifi, rsp + offset, to_read); offset += to_read; k_yield(); } /* Flush remaining data if receiving buffer not large enough */ while (eswifi_spi_cmddata_ready(spi)) { eswifi_spi_read(eswifi, tmp, 2); k_sleep(K_MSEC(1)); } /* Our device is flagged with SPI_HOLD_ON_CS|SPI_LOCK_ON, release */ spi_release_dt(&spi->bus); LOG_DBG("success"); return offset; } static void eswifi_spi_read_msg(struct eswifi_dev *eswifi) { const char startstr[] = "[SOMA]"; const char endstr[] = "[EOMA]"; char cmd[] = "MR\r"; size_t msg_len; char *rsp; int ret; LOG_DBG(""); eswifi_lock(eswifi); ret = eswifi_at_cmd_rsp(eswifi, cmd, &rsp); if (ret < 0) { LOG_ERR("Unable to read msg %d", ret); eswifi_unlock(eswifi); return; } if (strncmp(rsp, startstr, sizeof(endstr) - 1)) { LOG_ERR("Malformed async msg"); eswifi_unlock(eswifi); return; } /* \r\n[SOMA]...[EOMA]\r\nOK\r\n> */ msg_len = ret - (sizeof(startstr) - 1) - (sizeof(endstr) - 1); if (msg_len > 0) { eswifi_async_msg(eswifi, rsp + sizeof(endstr) - 1, msg_len); } eswifi_unlock(eswifi); } static void eswifi_spi_poll_thread(void *p1) { struct eswifi_dev *eswifi = p1; while (1) { k_sleep(K_MSEC(1000)); eswifi_spi_read_msg(eswifi); } } int eswifi_spi_init(struct eswifi_dev *eswifi) { struct eswifi_spi_data *spi = &eswifi_spi0; /* Static instance */ /* SPI DATA READY PIN */ spi->dr.dev = device_get_binding( DT_INST_GPIO_LABEL(0, data_gpios)); if (!spi->dr.dev) { LOG_ERR("Failed to initialize GPIO driver: %s", DT_INST_GPIO_LABEL(0, data_gpios)); return -ENODEV; } spi->dr.pin = DT_INST_GPIO_PIN(0, data_gpios); gpio_pin_configure(spi->dr.dev, spi->dr.pin, DT_INST_GPIO_FLAGS(0, data_gpios) | GPIO_INPUT); /* SPI BUS */ if (!spi_is_ready(&spi->bus)) { LOG_ERR("SPI bus is not ready"); return -ENODEV; }; eswifi->bus_data = spi; LOG_DBG("success"); k_thread_create(&spi->poll_thread, eswifi_spi_poll_stack, ESWIFI_SPI_THREAD_STACK_SIZE, (k_thread_entry_t)eswifi_spi_poll_thread, eswifi, NULL, NULL, K_PRIO_COOP(CONFIG_WIFI_ESWIFI_THREAD_PRIO), 0, K_NO_WAIT); return 0; } static struct eswifi_bus_ops eswifi_bus_ops_spi = { .init = eswifi_spi_init, .request = eswifi_spi_request, }; struct eswifi_bus_ops *eswifi_get_bus(void) { return &eswifi_bus_ops_spi; } |