1 /*
2 * Copyright (c) 2019 Manivannan Sadhasivam
3 * Copyright (c) 2020 Andreas Sandberg
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <drivers/gpio.h>
9 #include <drivers/lora.h>
10 #include <drivers/spi.h>
11 #include <zephyr.h>
12
13 #include <sx126x/sx126x.h>
14
15 #include "sx12xx_common.h"
16 #include "sx126x_common.h"
17
18 #include <logging/log.h>
19 LOG_MODULE_REGISTER(sx126x, CONFIG_LORA_LOG_LEVEL);
20
21 BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(semtech_sx1261) +
22 DT_NUM_INST_STATUS_OKAY(semtech_sx1262) +
23 DT_NUM_INST_STATUS_OKAY(st_stm32wl_subghz_radio) <= 1,
24 "Multiple SX126x instances in DT");
25
26 #define DIO2_TX_ENABLE DT_INST_PROP(0, dio2_tx_enable)
27
28 #define HAVE_DIO3_TCXO DT_INST_NODE_HAS_PROP(0, dio3_tcxo_voltage)
29 #if HAVE_DIO3_TCXO
30 #define TCXO_DIO3_VOLTAGE DT_INST_PROP(0, dio3_tcxo_voltage)
31 #endif
32
33 #if DT_INST_NODE_HAS_PROP(0, tcxo_power_startup_delay_ms)
34 #define TCXO_POWER_STARTUP_DELAY_MS \
35 DT_INST_PROP(0, tcxo_power_startup_delay_ms)
36 #else
37 #define TCXO_POWER_STARTUP_DELAY_MS 0
38 #endif
39
40 #define SX126X_CALIBRATION_ALL 0x7f
41
42 static struct sx126x_data dev_data;
43
44 void SX126xWaitOnBusy(void);
45
46 #define MODE(m) [MODE_##m] = #m
47 static const char *const mode_names[] = {
48 MODE(SLEEP),
49 MODE(STDBY_RC),
50 MODE(STDBY_XOSC),
51 MODE(FS),
52 MODE(TX),
53 MODE(RX),
54 MODE(RX_DC),
55 MODE(CAD),
56 };
57 #undef MODE
58
sx126x_mode_name(RadioOperatingModes_t m)59 static const char *sx126x_mode_name(RadioOperatingModes_t m)
60 {
61 static const char *unknown_mode = "unknown";
62
63 if (m < ARRAY_SIZE(mode_names) && mode_names[m]) {
64 return mode_names[m];
65 } else {
66 return unknown_mode;
67 }
68 }
69
sx126x_spi_transceive(uint8_t * req_tx,uint8_t * req_rx,size_t req_len,void * data_tx,void * data_rx,size_t data_len)70 static int sx126x_spi_transceive(uint8_t *req_tx, uint8_t *req_rx,
71 size_t req_len, void *data_tx, void *data_rx,
72 size_t data_len)
73 {
74 int ret;
75
76 const struct spi_buf tx_buf[] = {
77 {
78 .buf = req_tx,
79 .len = req_len,
80 },
81 {
82 .buf = data_tx,
83 .len = data_len
84 }
85 };
86
87 const struct spi_buf rx_buf[] = {
88 {
89 .buf = req_rx,
90 .len = req_len,
91 },
92 {
93 .buf = data_rx,
94 .len = data_len
95 }
96 };
97
98 const struct spi_buf_set tx = {
99 .buffers = tx_buf,
100 .count = ARRAY_SIZE(tx_buf),
101 };
102
103 const struct spi_buf_set rx = {
104 .buffers = rx_buf,
105 .count = ARRAY_SIZE(rx_buf)
106 };
107
108 /* Wake the device if necessary */
109 SX126xCheckDeviceReady();
110
111 if (!req_rx && !data_rx) {
112 ret = spi_write(dev_data.spi, &dev_data.spi_cfg, &tx);
113 } else {
114 ret = spi_transceive(dev_data.spi, &dev_data.spi_cfg,
115 &tx, &rx);
116 }
117
118 if (ret < 0) {
119 LOG_ERR("SPI transaction failed: %i", ret);
120 }
121
122 if (req_len >= 1 && req_tx[0] != RADIO_SET_SLEEP) {
123 SX126xWaitOnBusy();
124 }
125 return ret;
126 }
127
SX126xReadRegister(uint16_t address)128 uint8_t SX126xReadRegister(uint16_t address)
129 {
130 uint8_t data;
131
132 SX126xReadRegisters(address, &data, 1);
133
134 return data;
135 }
136
SX126xReadRegisters(uint16_t address,uint8_t * buffer,uint16_t size)137 void SX126xReadRegisters(uint16_t address, uint8_t *buffer, uint16_t size)
138 {
139 uint8_t req[] = {
140 RADIO_READ_REGISTER,
141 (address >> 8) & 0xff,
142 address & 0xff,
143 0,
144 };
145
146 LOG_DBG("Reading %" PRIu16 " registers @ 0x%" PRIx16, size, address);
147 sx126x_spi_transceive(req, NULL, sizeof(req), NULL, buffer, size);
148 LOG_HEXDUMP_DBG(buffer, size, "register_value");
149 }
150
SX126xWriteRegister(uint16_t address,uint8_t value)151 void SX126xWriteRegister(uint16_t address, uint8_t value)
152 {
153 SX126xWriteRegisters(address, &value, 1);
154 }
155
SX126xWriteRegisters(uint16_t address,uint8_t * buffer,uint16_t size)156 void SX126xWriteRegisters(uint16_t address, uint8_t *buffer, uint16_t size)
157 {
158 uint8_t req[] = {
159 RADIO_WRITE_REGISTER,
160 (address >> 8) & 0xff,
161 address & 0xff,
162 };
163
164 LOG_DBG("Writing %" PRIu16 " registers @ 0x%" PRIx16
165 ": 0x%" PRIx8 " , ...",
166 size, address, buffer[0]);
167 sx126x_spi_transceive(req, NULL, sizeof(req), buffer, NULL, size);
168 }
169
SX126xReadCommand(RadioCommands_t opcode,uint8_t * buffer,uint16_t size)170 uint8_t SX126xReadCommand(RadioCommands_t opcode,
171 uint8_t *buffer, uint16_t size)
172 {
173 uint8_t tx_req[] = {
174 opcode,
175 0x00,
176 };
177
178 uint8_t rx_req[sizeof(tx_req)];
179
180 LOG_DBG("Issuing opcode 0x%x (data size: %" PRIx16 ")",
181 opcode, size);
182 sx126x_spi_transceive(tx_req, rx_req, sizeof(rx_req),
183 NULL, buffer, size);
184 LOG_DBG("-> status: 0x%" PRIx8, rx_req[1]);
185 return rx_req[1];
186 }
187
SX126xWriteCommand(RadioCommands_t opcode,uint8_t * buffer,uint16_t size)188 void SX126xWriteCommand(RadioCommands_t opcode, uint8_t *buffer, uint16_t size)
189 {
190 uint8_t req[] = {
191 opcode,
192 };
193
194 LOG_DBG("Issuing opcode 0x%x w. %" PRIu16 " bytes of data",
195 opcode, size);
196 sx126x_spi_transceive(req, NULL, sizeof(req), buffer, NULL, size);
197 }
198
SX126xReadBuffer(uint8_t offset,uint8_t * buffer,uint8_t size)199 void SX126xReadBuffer(uint8_t offset, uint8_t *buffer, uint8_t size)
200 {
201 uint8_t req[] = {
202 RADIO_READ_BUFFER,
203 offset,
204 0x00,
205 };
206
207 LOG_DBG("Reading buffers @ 0x%" PRIx8 " (%" PRIu8 " bytes)",
208 offset, size);
209 sx126x_spi_transceive(req, NULL, sizeof(req), NULL, buffer, size);
210 }
211
SX126xWriteBuffer(uint8_t offset,uint8_t * buffer,uint8_t size)212 void SX126xWriteBuffer(uint8_t offset, uint8_t *buffer, uint8_t size)
213 {
214 uint8_t req[] = {
215 RADIO_WRITE_BUFFER,
216 offset,
217 };
218
219 LOG_DBG("Writing buffers @ 0x%" PRIx8 " (%" PRIu8 " bytes)",
220 offset, size);
221 sx126x_spi_transceive(req, NULL, sizeof(req), buffer, NULL, size);
222 }
223
SX126xAntSwOn(void)224 void SX126xAntSwOn(void)
225 {
226 #if HAVE_GPIO_ANTENNA_ENABLE
227 LOG_DBG("Enabling antenna switch");
228 gpio_pin_set(dev_data.antenna_enable, GPIO_ANTENNA_ENABLE_PIN, 1);
229 #else
230 LOG_DBG("No antenna switch configured");
231 #endif
232 }
233
SX126xAntSwOff(void)234 void SX126xAntSwOff(void)
235 {
236 #if HAVE_GPIO_ANTENNA_ENABLE
237 LOG_DBG("Disabling antenna switch");
238 gpio_pin_set(dev_data.antenna_enable, GPIO_ANTENNA_ENABLE_PIN, 0);
239 #else
240 LOG_DBG("No antenna switch configured");
241 #endif
242 }
243
sx126x_set_tx_enable(int value)244 static void sx126x_set_tx_enable(int value)
245 {
246 #if HAVE_GPIO_TX_ENABLE
247 gpio_pin_set(dev_data.tx_enable, GPIO_TX_ENABLE_PIN, value);
248 #endif
249 }
250
sx126x_set_rx_enable(int value)251 static void sx126x_set_rx_enable(int value)
252 {
253 #if HAVE_GPIO_RX_ENABLE
254 gpio_pin_set(dev_data.rx_enable, GPIO_RX_ENABLE_PIN, value);
255 #endif
256 }
257
SX126xGetOperatingMode(void)258 RadioOperatingModes_t SX126xGetOperatingMode(void)
259 {
260 return dev_data.mode;
261 }
262
SX126xSetOperatingMode(RadioOperatingModes_t mode)263 void SX126xSetOperatingMode(RadioOperatingModes_t mode)
264 {
265 LOG_DBG("SetOperatingMode: %s (%i)", sx126x_mode_name(mode), mode);
266
267 dev_data.mode = mode;
268
269 /* To avoid inadvertently putting the RF switch in an
270 * undefined state, first disable the port we don't want to
271 * use and then enable the other one.
272 */
273 switch (mode) {
274 case MODE_TX:
275 sx126x_set_rx_enable(0);
276 sx126x_set_tx_enable(1);
277 break;
278
279 case MODE_RX:
280 case MODE_RX_DC:
281 case MODE_CAD:
282 sx126x_set_tx_enable(0);
283 sx126x_set_rx_enable(1);
284 break;
285
286 case MODE_SLEEP:
287 /* Additionally disable the DIO1 interrupt to save power */
288 sx126x_dio1_irq_disable(&dev_data);
289 __fallthrough;
290 default:
291 sx126x_set_rx_enable(0);
292 sx126x_set_tx_enable(0);
293 break;
294 }
295 }
296
SX126xGetBoardTcxoWakeupTime(void)297 uint32_t SX126xGetBoardTcxoWakeupTime(void)
298 {
299 return TCXO_POWER_STARTUP_DELAY_MS;
300 }
301
SX126xGetDeviceId(void)302 uint8_t SX126xGetDeviceId(void)
303 {
304 return SX126X_DEVICE_ID;
305 }
306
SX126xIoIrqInit(DioIrqHandler dioIrq)307 void SX126xIoIrqInit(DioIrqHandler dioIrq)
308 {
309 LOG_DBG("Configuring DIO IRQ callback");
310 dev_data.radio_dio_irq = dioIrq;
311 }
312
SX126xIoTcxoInit(void)313 void SX126xIoTcxoInit(void)
314 {
315 #if HAVE_DIO3_TCXO
316 CalibrationParams_t cal = {
317 .Value = SX126X_CALIBRATION_ALL,
318 };
319
320 LOG_DBG("TCXO on DIO3");
321
322 /* Delay in units of 15.625 us (1/64 ms) */
323 SX126xSetDio3AsTcxoCtrl(TCXO_DIO3_VOLTAGE,
324 TCXO_POWER_STARTUP_DELAY_MS << 6);
325 SX126xCalibrate(cal);
326 #else
327 LOG_DBG("No TCXO configured");
328 #endif
329 }
330
SX126xIoRfSwitchInit(void)331 void SX126xIoRfSwitchInit(void)
332 {
333 LOG_DBG("Configuring DIO2");
334 SX126xSetDio2AsRfSwitchCtrl(DIO2_TX_ENABLE);
335 }
336
SX126xReset(void)337 void SX126xReset(void)
338 {
339 LOG_DBG("Resetting radio");
340
341 sx126x_reset(&dev_data);
342
343 /* Device transitions to standby on reset */
344 dev_data.mode = MODE_STDBY_RC;
345 }
346
SX126xSetRfTxPower(int8_t power)347 void SX126xSetRfTxPower(int8_t power)
348 {
349 LOG_DBG("power: %" PRIi8, power);
350 SX126xSetTxParams(power, RADIO_RAMP_40_US);
351 }
352
SX126xWaitOnBusy(void)353 void SX126xWaitOnBusy(void)
354 {
355 while (sx126x_is_busy(&dev_data)) {
356 k_sleep(K_MSEC(1));
357 }
358 }
359
SX126xWakeup(void)360 void SX126xWakeup(void)
361 {
362 int ret;
363
364 /* Reenable DIO1 when waking up */
365 sx126x_dio1_irq_enable(&dev_data);
366
367 uint8_t req[] = { RADIO_GET_STATUS, 0 };
368 const struct spi_buf tx_buf = {
369 .buf = req,
370 .len = sizeof(req),
371 };
372
373 const struct spi_buf_set tx = {
374 .buffers = &tx_buf,
375 .count = 1,
376 };
377
378 LOG_DBG("Sending GET_STATUS");
379 ret = spi_write(dev_data.spi, &dev_data.spi_cfg, &tx);
380 if (ret < 0) {
381 LOG_ERR("SPI transaction failed: %i", ret);
382 return;
383 }
384
385 LOG_DBG("Waiting for device...");
386 SX126xWaitOnBusy();
387 LOG_DBG("Device ready");
388 /* This function is only called from sleep mode
389 * All edges on the SS SPI pin will transition the modem to
390 * standby mode (via startup)
391 */
392 dev_data.mode = MODE_STDBY_RC;
393 }
394
SX126xGetDio1PinState(void)395 uint32_t SX126xGetDio1PinState(void)
396 {
397 return sx126x_get_dio1_pin_state(&dev_data);
398 }
399
sx126x_dio1_irq_work_handler(struct k_work * work)400 static void sx126x_dio1_irq_work_handler(struct k_work *work)
401 {
402 LOG_DBG("Processing DIO1 interrupt");
403 if (!dev_data.radio_dio_irq) {
404 LOG_WRN("DIO1 interrupt without valid HAL IRQ callback.");
405 return;
406 }
407
408 dev_data.radio_dio_irq(NULL);
409 if (Radio.IrqProcess) {
410 Radio.IrqProcess();
411 }
412
413 /* Re-enable the interrupt if we are not in sleep mode */
414 if (dev_data.mode != MODE_SLEEP) {
415 sx126x_dio1_irq_enable(&dev_data);
416 }
417 }
418
sx126x_lora_init(const struct device * dev)419 static int sx126x_lora_init(const struct device *dev)
420 {
421 int ret;
422
423 LOG_DBG("Initializing %s", DT_INST_LABEL(0));
424
425 if (sx12xx_configure_pin(antenna_enable, GPIO_OUTPUT_INACTIVE) ||
426 sx12xx_configure_pin(rx_enable, GPIO_OUTPUT_INACTIVE) ||
427 sx12xx_configure_pin(tx_enable, GPIO_OUTPUT_INACTIVE)) {
428 return -EIO;
429 }
430
431 k_work_init(&dev_data.dio1_irq_work, sx126x_dio1_irq_work_handler);
432
433 ret = sx126x_variant_init(dev);
434 if (ret) {
435 LOG_ERR("Variant initialization failed");
436 return ret;
437 }
438
439 dev_data.spi = device_get_binding(DT_INST_BUS_LABEL(0));
440 if (!dev_data.spi) {
441 LOG_ERR("Cannot get pointer to %s device",
442 DT_INST_BUS_LABEL(0));
443 return -EINVAL;
444 }
445
446 #if HAVE_GPIO_CS
447 dev_data.spi_cs.gpio_dev = device_get_binding(GPIO_CS_LABEL);
448 if (!dev_data.spi_cs.gpio_dev) {
449 LOG_ERR("Cannot get pointer to %s device", GPIO_CS_LABEL);
450 return -EIO;
451 }
452
453 dev_data.spi_cs.gpio_pin = GPIO_CS_PIN;
454 dev_data.spi_cs.gpio_dt_flags = GPIO_CS_FLAGS;
455 dev_data.spi_cs.delay = 0U;
456
457 dev_data.spi_cfg.cs = &dev_data.spi_cs;
458 #endif
459 dev_data.spi_cfg.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB;
460 dev_data.spi_cfg.frequency = DT_INST_PROP(0, spi_max_frequency);
461 dev_data.spi_cfg.slave = DT_INST_REG_ADDR(0);
462
463
464 ret = sx12xx_init(dev);
465 if (ret < 0) {
466 LOG_ERR("Failed to initialize SX12xx common");
467 return ret;
468 }
469
470 return 0;
471 }
472
473 static const struct lora_driver_api sx126x_lora_api = {
474 .config = sx12xx_lora_config,
475 .send = sx12xx_lora_send,
476 .send_async = sx12xx_lora_send_async,
477 .recv = sx12xx_lora_recv,
478 .test_cw = sx12xx_lora_test_cw,
479 };
480
481 DEVICE_DT_INST_DEFINE(0, &sx126x_lora_init, NULL, &dev_data,
482 NULL, POST_KERNEL, CONFIG_LORA_INIT_PRIORITY,
483 &sx126x_lora_api);
484