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