1 /*
2  * Copyright (c) 2020 Friedt Professional Engineering Services, Inc
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ti_cc13xx_cc26xx_ieee802154_subghz
8 
9 #define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(ieee802154_cc13xx_cc26xx_subg);
12 
13 #include <errno.h>
14 #include <string.h>
15 
16 #include <zephyr/device.h>
17 #include <zephyr/net/ieee802154.h>
18 #include <zephyr/net/ieee802154_radio.h>
19 #include <zephyr/net/net_pkt.h>
20 #include <zephyr/random/random.h>
21 #include <zephyr/sys/byteorder.h>
22 #include <zephyr/sys/crc.h>
23 #include <zephyr/sys/sys_io.h>
24 
25 #include <driverlib/rf_mailbox.h>
26 #include <driverlib/rf_prop_mailbox.h>
27 #include <driverlib/rfc.h>
28 #include <inc/hw_ccfg.h>
29 #include <inc/hw_fcfg1.h>
30 #include <rf_patches/rf_patch_cpe_multi_protocol.h>
31 
32 #include <ti/drivers/rf/RF.h>
33 
34 #include "ieee802154_cc13xx_cc26xx_subg.h"
35 
36 static int drv_start_rx(const struct device *dev);
37 static int drv_stop_rx(const struct device *dev);
38 
39 #ifndef CMD_PROP_RADIO_DIV_SETUP_PA
40 /* workaround for older HAL TI SDK (less than 4.40) */
41 #define CMD_PROP_RADIO_DIV_SETUP_PA CMD_PROP_RADIO_DIV_SETUP
42 #endif
43 
44 #if defined(CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_RADIO_SETUP)
45 /* User-defined CMD_PROP_RADIO_DIV_SETUP structures */
46 #if defined(CONFIG_SOC_CC1352R)
47 extern volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_setup;
48 #elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7)
49 extern volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_div_setup;
50 #endif /* CONFIG_SOC_CC1352x, extern RADIO_DIV_SETUP */
51 #else
52 
53 #if defined(CONFIG_SOC_CC1352R)
54 /* Radio register overrides for CC13x2R (note: CC26x2 does not support sub-GHz radio)
55  * from SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW),
56  * approximates SUN FSK PHY, 915 MHz band, operating mode #3.
57  */
58 static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = {
59 	/* DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0x7 (DITHER_EN=0 and IPEAK=7). */
60 	(uint32_t)0x00F788D3,
61 	/* Set RF_FSCA.ANADIV.DIV_SEL_BIAS = 1. Bits [0:16, 24, 30] are don't care.. */
62 	(uint32_t)0x4001405D,
63 	/* Set RF_FSCA.ANADIV.DIV_SEL_BIAS = 1. Bits [0:16, 24, 30] are don't care.. */
64 	(uint32_t)0x08141131,
65 	/* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4:3]=0x3) */
66 	ADI_2HALFREG_OVERRIDE(0, 16, 0x8, 0x8, 17, 0x1, 0x1),
67 	/* Tx: Configure PA ramping, set wait time before turning off
68 	 * (0x1A ticks of 16/24 us = 17.3 us).
69 	 */
70 	HW_REG_OVERRIDE(0x6028, 0x001A),
71 	/* Rx: Set AGC reference level to 0x16 (default: 0x2E) */
72 	HW_REG_OVERRIDE(0x609C, 0x0016),
73 	/* Rx: Set RSSI offset to adjust reported RSSI by -1 dB (default: -2),
74 	 * trimmed for external bias and differential configuration
75 	 */
76 	(uint32_t)0x000188A3,
77 	/* Rx: Set anti-aliasing filter bandwidth to 0x8 (in ADI0, set IFAMPCTL3[7:4]=0x8) */
78 	ADI_HALFREG_OVERRIDE(0, 61, 0xF, 0x8),
79 	/* Tx: Set PA trim to max to maximize its output power (in ADI0, set PACTL0=0xF8) */
80 	ADI_REG_OVERRIDE(0, 12, 0xF8),
81 	(uint32_t)0xFFFFFFFF
82 };
83 
84 /* Radio values for CC13X2P */
85 #elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7)
86 /* CC1352P overrides from SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW) */
87 static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = {
88 	/* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4:3]=0x1) */
89 	ADI_2HALFREG_OVERRIDE(0, 16, 0x8, 0x8, 17, 0x1, 0x0),
90 	/* Rx: Set AGC reference level to 0x16 (default: 0x2E) */
91 	HW_REG_OVERRIDE(0x609C, 0x0016),
92 	/* Rx: Set RSSI offset to adjust reported RSSI by -1 dB (default: -2),
93 	 * trimmed for external bias and differential configuration.
94 	 */
95 	(uint32_t)0x000188A3,
96 	/* Rx: Set anti-aliasing filter bandwidth to 0x6 (in ADI0, set IFAMPCTL3[7:4]=0x8) */
97 	ADI_HALFREG_OVERRIDE(0, 61, 0xF, 0x8),
98 	/* override_prop_common_sub1g.xml */
99 	/* Set RF_FSCA.ANADIV.DIV_SEL_BIAS = 1. Bits [0:16, 24, 30] are don't care.. */
100 	(uint32_t)0x4001405D,
101 	/* Set RF_FSCA.ANADIV.DIV_SEL_BIAS = 1. Bits [0:16, 24, 30] are don't care.. */
102 	(uint32_t)0x08141131,
103 	/* override_prop_common.xml */
104 	/* DC/DC regulator: In Tx with 14 dBm PA setting, use DCDCCTL5[3:0]=0xF */
105 	/* (DITHER_EN=1 and IPEAK=7). In Rx, use default settings. */
106 	(uint32_t)0x00F788D3,
107 	(uint32_t)0xFFFFFFFF
108 };
109 static uint32_t rf_prop_overrides_tx_std[] = {
110 	/* The TX Power element should always be the first in the list */
111 	TX_STD_POWER_OVERRIDE(0x013F),
112 	/* The ANADIV radio parameter based on the LO divider (0) and front-end (0) settings */
113 	(uint32_t)0x11310703,
114 	/* override_phy_tx_pa_ramp_genfsk_std.xml */
115 	/* Tx: Configure PA ramping, set wait time before turning off */
116 	/* (0x1A ticks of 16/24 us = 17.3 us). */
117 	HW_REG_OVERRIDE(0x6028, 0x001A),
118 	/* Set TXRX pin to 0 in RX and high impedance in idle/TX. */
119 	HW_REG_OVERRIDE(0x60A8, 0x0401),
120 	(uint32_t)0xFFFFFFFF
121 };
122 static uint32_t rf_prop_overrides_tx_20[] = {
123 	/* The TX Power element should always be the first in the list */
124 	TX20_POWER_OVERRIDE(0x001B8ED2),
125 	/* The ANADIV radio parameter based on the LO divider (0) and front-end (0) settings */
126 	(uint32_t)0x11C10703,
127 	/* override_phy_tx_pa_ramp_genfsk_hpa.xml */
128 	/* Tx: Configure PA ramping, set wait time before turning off */
129 	/* (0x1F ticks of 16/24 us = 20.3 us). */
130 	HW_REG_OVERRIDE(0x6028, 0x001F),
131 	/* Set TXRX pin to 0 in RX/TX and high impedance in idle. */
132 	HW_REG_OVERRIDE(0x60A8, 0x0001),
133 	(uint32_t)0xFFFFFFFF
134 };
135 
136 #else
137 #error "unsupported CC13xx SoC"
138 #endif /* CONFIG_SOC_CC1352x */
139 
140 /* Radio setup command for CC13xx */
141 #if defined(CONFIG_SOC_CC1352R)
142 static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_setup = {
143 	.commandNo = CMD_PROP_RADIO_DIV_SETUP,
144 #elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7)
145 static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_div_setup = {
146 	.commandNo = CMD_PROP_RADIO_DIV_SETUP_PA,
147 #endif /* CONFIG_SOC_CC1352x */
148 	.condition.rule = COND_NEVER,
149 	.modulation = {
150 		.modType = 1, /* 2-GFSK - non-standard modulation */
151 		.deviation = 200, /* +/- 200*250 = 50kHz deviation (modulation index 0.5) */
152 	},
153 	.symbolRate = {
154 		.preScale = 15,
155 		.rateWord = 131072, /* 200 kBit, see TRM, section 25.10.5.2, formula 15 */
156 	},
157 	.rxBw = 0x59, /* 310.8 kHz RX bandwidth, see TRM, section 25.10.5.2, table 25-183 */
158 	.preamConf.nPreamBytes = 7, /* phyFskPreambleLength = 7 + 1, also see nSwBits below */
159 	.formatConf = {
160 		.nSwBits = 24, /* 24-bit (1 byte preamble + 16 bit SFD) */
161 		.bMsbFirst = true,
162 		.whitenMode = 7, /* Determine whitening and CRC from PHY header */
163 	},
164 	.config.biasMode = true, /* Rely on an external antenna biasing network. */
165 	.txPower = 0x013f, /* 14 dBm, see TRM 25.3.3.2.16 */
166 	.centerFreq = 906, /* Set channel page zero, channel 1 by default, see IEEE 802.15.4,
167 			    * section 10.1.3.3.
168 			    * TODO: Use compliant SUN PHY frequencies from channel page 9.
169 			    */
170 	.intFreq = 0x8000, /* Use default intermediate frequency. */
171 	.loDivider = 5,
172 	.pRegOverride = ieee802154_cc13xx_overrides_sub_ghz,
173 #if defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7)
174 	.pRegOverrideTxStd = rf_prop_overrides_tx_std,
175 	.pRegOverrideTx20 = rf_prop_overrides_tx_20,
176 #endif /* CONFIG_SOC_CC1352P, CONFIG_SOC_CC1352P7 */
177 };
178 
179 #endif /* CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_RADIO_SETUP */
180 
181 /* Sub GHz power tables */
182 #if defined(CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_POWER_TABLE)
183 extern RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[];
184 
185 #elif defined(CONFIG_SOC_CC1352R)
186 static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = {
187 	{ -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) },
188 	{ -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 3) },
189 	{ -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 5) },
190 	{ -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(4, 3, 0, 5) },
191 	{ 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 3, 0, 8) },
192 	{ 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 9) },
193 	{ 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 3, 0, 9) },
194 	{ 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 10) },
195 	{ 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 11) },
196 	{ 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) },
197 	{ 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 3, 0, 16) },
198 	{ 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 0, 19) },
199 	{ 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 22) },
200 	{ 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 3, 0, 31) },
201 	{ 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 2, 0, 31) },
202 	{ 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 2, 0, 51) },
203 	{ 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 0, 0, 82) },
204 	{ 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 0, 89) },
205 #ifdef CONFIG_CC13X2_CC26X2_BOOST_MODE
206 	{ 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) },
207 #endif
208 	RF_TxPowerTable_TERMINATION_ENTRY
209 };
210 #elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7)
211 /* Sub GHz power table */
212 static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = {
213 	{ -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) },
214 	{ -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 3) },
215 	{ -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 5) },
216 	{ -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(4, 3, 0, 5) },
217 	{ 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 3, 0, 8) },
218 	{ 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 9) },
219 	{ 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 3, 0, 9) },
220 	{ 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 10) },
221 	{ 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 11) },
222 	{ 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) },
223 	{ 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 3, 0, 16) },
224 	{ 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 0, 19) },
225 	{ 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 22) },
226 	{ 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 3, 0, 31) },
227 	{ 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 2, 0, 31) },
228 	{ 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 2, 0, 51) },
229 	{ 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 0, 0, 82) },
230 	{ 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 0, 89) },
231 #ifdef CONFIG_CC13X2_CC26X2_BOOST_MODE
232 	{ 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) },
233 #endif
234 	{ 15, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 36, 0) },
235 	{ 16, RF_TxPowerTable_HIGH_PA_ENTRY(24, 0, 0, 43, 0) },
236 	{ 17, RF_TxPowerTable_HIGH_PA_ENTRY(28, 0, 0, 51, 2) },
237 	{ 18, RF_TxPowerTable_HIGH_PA_ENTRY(34, 0, 0, 64, 4) },
238 	{ 19, RF_TxPowerTable_HIGH_PA_ENTRY(15, 3, 0, 36, 4) },
239 	{ 20, RF_TxPowerTable_HIGH_PA_ENTRY(18, 3, 0, 71, 27) },
240 	RF_TxPowerTable_TERMINATION_ENTRY
241 };
242 #endif /* CONFIG_SOC_CC1352x power table */
243 
244 #define LOCK_TIMEOUT (k_is_in_isr() ? K_NO_WAIT : K_FOREVER)
245 
246 /** RF patches to use (note: RF core keeps a pointer to this, so no stack). */
247 static RF_Mode rf_mode = {
248 	.rfMode = RF_MODE_MULTIPLE,
249 	.cpePatchFxn = &rf_patch_cpe_multi_protocol,
250 };
251 
drv_channel_frequency(uint16_t channel,uint16_t * frequency,uint16_t * fractFreq)252 static inline int drv_channel_frequency(uint16_t channel, uint16_t *frequency, uint16_t *fractFreq)
253 {
254 	__ASSERT_NO_MSG(frequency != NULL);
255 	__ASSERT_NO_MSG(fractFreq != NULL);
256 
257 	/* See IEEE 802.15.4-2020, section 10.1.3.3. */
258 	if (channel == 0) {
259 		*frequency = 868;
260 		/*
261 		 * uint16_t fractional part of 868.3 MHz
262 		 * equivalent to (0.3 * 1000 * BIT(16)) / 1000, rounded up
263 		 */
264 		*fractFreq = 0x4ccd;
265 	} else if (channel <= 10) {
266 		*frequency = 906 + 2 * (channel - 1);
267 		*fractFreq = 0;
268 	} else {
269 		*frequency = 0;
270 		*fractFreq = 0;
271 		return channel <= 26 ? -ENOTSUP : -EINVAL;
272 	}
273 
274 	/* TODO: This incorrectly mixes up legacy BPSK SubGHz PHY channel page
275 	 * zero frequency calculation with SUN FSK operating mode #3 PHY radio
276 	 * settings.
277 	 *
278 	 * The correct channel frequency calculation for this PHY is on channel page 9,
279 	 * using the formula ChanCenterFreq = ChanCenterFreq0 + channel * ChanSpacing.
280 	 *
281 	 * Assuming operating mode #3, the parameters for some frequently used bands
282 	 * on this channel page are:
283 	 *   863 MHz: ChanSpacing 0.2, TotalNumChan 35, ChanCenterFreq0 863.1
284 	 *   915 MHz: ChanSpacing 0.4, TotalNumChan 64, ChanCenterFreq0 902.4
285 	 *
286 	 * See IEEE 802.15.4, section 10.1.3.9.
287 	 *
288 	 * Setting the PHY, channel page, band and operating mode requires additional
289 	 * radio configuration settings.
290 	 *
291 	 * Making derived MAC/PHY PIB attributes available to L2 requires an additional
292 	 * attribute getter, see
293 	 * https://github.com/zephyrproject-rtos/zephyr/issues/50336#issuecomment-1251122582.
294 	 *
295 	 * We resolve this bug right now by basing all timing on SUN FSK
296 	 * parameters while maintaining the channel/channel page assignment of a
297 	 * BPSK PHY.
298 	 */
299 
300 	return 0;
301 }
302 
drv_power_down(const struct device * const dev)303 static inline int drv_power_down(const struct device *const dev)
304 {
305 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
306 
307 	(void)RF_yield(drv_data->rf_handle);
308 
309 	return 0;
310 }
311 
cmd_prop_tx_adv_callback(RF_Handle h,RF_CmdHandle ch,RF_EventMask e)312 static void cmd_prop_tx_adv_callback(RF_Handle h, RF_CmdHandle ch,
313 	RF_EventMask e)
314 {
315 	const struct device *const dev = DEVICE_DT_INST_GET(0);
316 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
317 	RF_Op *op = RF_getCmdOp(h, ch);
318 
319 	/* No need for locking as the RX status is volatile and there's no race. */
320 	LOG_DBG("ch: %u cmd: %04x cs st: %04x tx st: %04x e: 0x%" PRIx64, ch,
321 		op->commandNo, op->status, drv_data->cmd_prop_tx_adv.status, e);
322 }
323 
drv_rx_done(struct ieee802154_cc13xx_cc26xx_subg_data * drv_data)324 static void drv_rx_done(struct ieee802154_cc13xx_cc26xx_subg_data *drv_data)
325 {
326 	int8_t rssi, status;
327 	struct net_pkt *pkt;
328 	uint8_t len;
329 	uint8_t *sdu;
330 
331 	/* No need for locking as only immutable data is accessed from drv_data.
332 	 * The rx queue itself (entries and data) are managed and protected
333 	 * internally by TI's RF driver.
334 	 */
335 
336 	for (int i = 0; i < CC13XX_CC26XX_NUM_RX_BUF; i++) {
337 		if (drv_data->rx_entry[i].status == DATA_ENTRY_FINISHED) {
338 			len = drv_data->rx_data[i][0];
339 			sdu = drv_data->rx_data[i] + 1;
340 			status = drv_data->rx_data[i][len--];
341 			rssi = drv_data->rx_data[i][len--];
342 
343 			if (IS_ENABLED(CONFIG_IEEE802154_L2_PKT_INCL_FCS) && len > 0) {
344 				/* append CRC-16/CCITT */
345 				uint16_t crc = 0;
346 
347 				crc = crc16_ccitt(0, sdu, len);
348 				sdu[len++] = crc;
349 				sdu[len++] = crc >> 8;
350 			}
351 
352 			LOG_DBG("Received: len = %u, rssi = %d status = %u",
353 				len, rssi, status);
354 
355 			pkt = net_pkt_rx_alloc_with_buffer(
356 				drv_data->iface, len, AF_UNSPEC, 0, K_NO_WAIT);
357 			if (!pkt) {
358 				LOG_WRN("Cannot allocate packet");
359 				continue;
360 			}
361 
362 			if (net_pkt_write(pkt, sdu, len)) {
363 				LOG_WRN("Cannot write packet");
364 				net_pkt_unref(pkt);
365 				continue;
366 			}
367 
368 			drv_data->rx_entry[i].status = DATA_ENTRY_PENDING;
369 
370 			/* TODO: Determine LQI in PROP mode. */
371 			net_pkt_set_ieee802154_lqi(pkt, 0xff);
372 			net_pkt_set_ieee802154_rssi_dbm(pkt,
373 							rssi == CC13XX_CC26XX_INVALID_RSSI
374 								? IEEE802154_MAC_RSSI_DBM_UNDEFINED
375 								: rssi);
376 
377 			if (ieee802154_handle_ack(drv_data->iface, pkt) == NET_OK) {
378 				net_pkt_unref(pkt);
379 				continue;
380 			}
381 
382 			if (net_recv_data(drv_data->iface, pkt)) {
383 				LOG_WRN("Packet dropped");
384 				net_pkt_unref(pkt);
385 			}
386 
387 		} else if (drv_data->rx_entry[i].status ==
388 			   DATA_ENTRY_UNFINISHED) {
389 			LOG_WRN("Frame not finished");
390 			drv_data->rx_entry[i].status = DATA_ENTRY_PENDING;
391 		}
392 	}
393 }
394 
cmd_prop_rx_adv_callback(RF_Handle h,RF_CmdHandle ch,RF_EventMask e)395 static void cmd_prop_rx_adv_callback(RF_Handle h, RF_CmdHandle ch,
396 	RF_EventMask e)
397 {
398 	const struct device *const dev = DEVICE_DT_INST_GET(0);
399 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
400 	RF_Op *op = RF_getCmdOp(h, ch);
401 
402 	LOG_DBG("ch: %u cmd: %04x st: %04x e: 0x%" PRIx64, ch,
403 		op->commandNo, op->status, e);
404 
405 	/* If PROP_ERROR_RXBUF is returned, then RF_EventRxEntryDone is never
406 	 * triggered. So finished buffers need to be cleaned up even on this
407 	 * status.
408 	 */
409 	if (e & RF_EventRxEntryDone || op->status == PROP_ERROR_RXBUF) {
410 		drv_rx_done(drv_data);
411 	}
412 
413 	if (op->status == PROP_ERROR_RXBUF
414 		|| op->status == PROP_ERROR_RXFULL
415 		|| op->status == PROP_ERROR_RXOVF) {
416 		LOG_DBG("RX Error %x", op->status);
417 
418 		/* Restart RX */
419 		if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
420 			return;
421 		}
422 
423 		(void)drv_start_rx(dev);
424 		k_sem_give(&drv_data->lock);
425 	}
426 }
427 
client_error_callback(RF_Handle h,RF_CmdHandle ch,RF_EventMask e)428 static void client_error_callback(RF_Handle h, RF_CmdHandle ch,
429 	RF_EventMask e)
430 {
431 	ARG_UNUSED(h);
432 	ARG_UNUSED(ch);
433 	LOG_ERR("client error: 0x%" PRIx64, e);
434 }
435 
client_event_callback(RF_Handle h,RF_ClientEvent event,void * arg)436 static void client_event_callback(RF_Handle h, RF_ClientEvent event,
437 	void *arg)
438 {
439 	ARG_UNUSED(h);
440 	LOG_DBG("event: %d arg: %p", event, arg);
441 }
442 
443 static enum ieee802154_hw_caps
ieee802154_cc13xx_cc26xx_subg_get_capabilities(const struct device * dev)444 ieee802154_cc13xx_cc26xx_subg_get_capabilities(const struct device *dev)
445 {
446 	/* TODO: enable IEEE802154_HW_FILTER */
447 	return IEEE802154_HW_FCS;
448 }
449 
ieee802154_cc13xx_cc26xx_subg_cca(const struct device * dev)450 static int ieee802154_cc13xx_cc26xx_subg_cca(const struct device *dev)
451 {
452 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
453 	bool was_rx_on = false;
454 	RF_EventMask events;
455 	int ret;
456 
457 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
458 		return -EWOULDBLOCK;
459 	}
460 
461 	if (!drv_data->is_up) {
462 		ret = -ENETDOWN;
463 		goto out;
464 	}
465 
466 	drv_data->cmd_prop_cs.status = IDLE;
467 
468 	was_rx_on = drv_data->cmd_prop_rx_adv.status == ACTIVE;
469 	if (was_rx_on) {
470 		ret = drv_stop_rx(dev);
471 		if (ret) {
472 			ret = -EIO;
473 			goto out;
474 		}
475 	}
476 
477 	events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_prop_cs, RF_PriorityNormal,
478 			   NULL, 0);
479 	if (events != RF_EventLastCmdDone) {
480 		LOG_DBG("Failed to request CCA: 0x%" PRIx64, events);
481 		ret = -EIO;
482 		goto out;
483 	}
484 
485 	switch (drv_data->cmd_prop_cs.status) {
486 	case PROP_DONE_IDLE:
487 		/* Do not re-enable RX when the channel is idle as
488 		 * this usually means we want to TX directly after
489 		 * and cannot afford any extra latency.
490 		 */
491 		ret = 0;
492 		break;
493 	case PROP_DONE_BUSY:
494 	case PROP_DONE_BUSYTIMEOUT:
495 		ret = -EBUSY;
496 		break;
497 	default:
498 		ret = -EIO;
499 	}
500 
501 out:
502 	/* Re-enable RX if we found it on initially
503 	 * and the channel is busy (or another error
504 	 * occurred) as this usually means we back off
505 	 * and want to be able to receive packets in
506 	 * the meantime.
507 	 */
508 	if (ret && was_rx_on) {
509 		drv_start_rx(dev);
510 	}
511 
512 	k_sem_give(&drv_data->lock);
513 	return ret;
514 }
515 
516 /* This method must be called with the lock held. */
drv_start_rx(const struct device * dev)517 static int drv_start_rx(const struct device *dev)
518 {
519 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
520 	RF_CmdHandle cmd_handle;
521 
522 	if (drv_data->cmd_prop_rx_adv.status == ACTIVE) {
523 		return -EALREADY;
524 	}
525 
526 #ifdef CONFIG_ASSERT
527 	if (CONFIG_ASSERT_LEVEL > 0) {
528 		/* ensure that all RX buffers are initialized and pending. */
529 		for (int i = 0; i < CC13XX_CC26XX_NUM_RX_BUF; i++) {
530 			__ASSERT_NO_MSG(drv_data->rx_entry[i].pNextEntry != NULL);
531 			__ASSERT_NO_MSG(drv_data->rx_entry[i].status == DATA_ENTRY_PENDING);
532 		}
533 	}
534 #endif
535 
536 	drv_data->cmd_prop_rx_adv.status = IDLE;
537 	cmd_handle = RF_postCmd(drv_data->rf_handle,
538 				(RF_Op *)&drv_data->cmd_prop_rx_adv, RF_PriorityNormal,
539 				cmd_prop_rx_adv_callback, RF_EventRxEntryDone);
540 	if (cmd_handle < 0) {
541 		LOG_DBG("Failed to post RX command (%d)", cmd_handle);
542 		return -EIO;
543 	}
544 
545 	drv_data->rx_cmd_handle = cmd_handle;
546 
547 	return 0;
548 }
549 
550 /* This method must be called with the lock held. */
drv_stop_rx(const struct device * dev)551 static int drv_stop_rx(const struct device *dev)
552 {
553 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
554 	RF_Stat status;
555 
556 	if (drv_data->cmd_prop_rx_adv.status != ACTIVE) {
557 		return -EALREADY;
558 	}
559 
560 	/* Stop RX without aborting ongoing reception of packets. */
561 	status = RF_cancelCmd(drv_data->rf_handle, drv_data->rx_cmd_handle, RF_ABORT_GRACEFULLY);
562 	switch (status) {
563 	case RF_StatSuccess:
564 	case RF_StatCmdEnded:
565 		return 0;
566 	default:
567 		return -EIO;
568 	}
569 }
570 
ieee802154_cc13xx_cc26xx_subg_set_channel(const struct device * dev,uint16_t channel)571 static int ieee802154_cc13xx_cc26xx_subg_set_channel(
572 	const struct device *dev, uint16_t channel)
573 {
574 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
575 	uint16_t freq, fract;
576 	RF_EventMask events;
577 	bool was_rx_on;
578 	int ret;
579 
580 	ret = drv_channel_frequency(channel, &freq, &fract);
581 	if (ret < 0) {
582 		return ret;
583 	}
584 
585 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
586 		return -EWOULDBLOCK;
587 	}
588 
589 	was_rx_on = drv_data->cmd_prop_rx_adv.status == ACTIVE;
590 	if (was_rx_on) {
591 		ret = drv_stop_rx(dev);
592 		if (ret) {
593 			ret = -EIO;
594 			goto out;
595 		}
596 	}
597 
598 	/* Set the frequency */
599 	drv_data->cmd_fs.status = IDLE;
600 	drv_data->cmd_fs.frequency = freq;
601 	drv_data->cmd_fs.fractFreq = fract;
602 	events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_fs,
603 			   RF_PriorityNormal, NULL, 0);
604 	if (events != RF_EventLastCmdDone || drv_data->cmd_fs.status != DONE_OK) {
605 		LOG_DBG("Failed to set frequency: 0x%" PRIx64, events);
606 		ret = -EIO;
607 	}
608 
609 out:
610 	if (was_rx_on) {
611 		/* Re-enable RX if we found it on initially. */
612 		(void)drv_start_rx(dev);
613 	} else if (!drv_data->is_up) {
614 		ret = drv_power_down(dev);
615 	}
616 
617 	k_sem_give(&drv_data->lock);
618 
619 	return ret;
620 }
621 
622 static int
ieee802154_cc13xx_cc26xx_subg_filter(const struct device * dev,bool set,enum ieee802154_filter_type type,const struct ieee802154_filter * filter)623 ieee802154_cc13xx_cc26xx_subg_filter(const struct device *dev, bool set,
624 				     enum ieee802154_filter_type type,
625 				     const struct ieee802154_filter *filter)
626 {
627 	ARG_UNUSED(dev);
628 	ARG_UNUSED(set);
629 	ARG_UNUSED(type);
630 	ARG_UNUSED(filter);
631 	return -ENOTSUP;
632 }
633 
ieee802154_cc13xx_cc26xx_subg_set_txpower(const struct device * dev,int16_t dbm)634 static int ieee802154_cc13xx_cc26xx_subg_set_txpower(
635 	const struct device *dev, int16_t dbm)
636 {
637 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
638 	RF_TxPowerTable_Value power_table_value;
639 	RF_Stat status;
640 	int ret = 0;
641 
642 	power_table_value = RF_TxPowerTable_findValue(
643 		(RF_TxPowerTable_Entry *)ieee802154_cc13xx_subg_power_table, dbm);
644 	if (power_table_value.rawValue == RF_TxPowerTable_INVALID_VALUE) {
645 		LOG_DBG("RF_TxPowerTable_findValue() failed");
646 		return -EINVAL;
647 	}
648 
649 	/* No need for locking: rf_handle is immutable after initialization. */
650 	status = RF_setTxPower(drv_data->rf_handle, power_table_value);
651 	if (status != RF_StatSuccess) {
652 		LOG_DBG("RF_setTxPower() failed: %d", status);
653 		return -EIO;
654 	}
655 
656 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
657 		return -EWOULDBLOCK;
658 	}
659 
660 	if (!drv_data->is_up) {
661 		ret = drv_power_down(dev);
662 	}
663 
664 	k_sem_give(&drv_data->lock);
665 
666 	return ret;
667 }
668 
669 /* See IEEE 802.15.4 section 6.7.1 and TRM section 25.5.4.3 */
ieee802154_cc13xx_cc26xx_subg_tx(const struct device * dev,enum ieee802154_tx_mode mode,struct net_pkt * pkt,struct net_buf * buf)670 static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev,
671 					    enum ieee802154_tx_mode mode,
672 					    struct net_pkt *pkt,
673 					    struct net_buf *buf)
674 {
675 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
676 	RF_EventMask events;
677 	int ret = 0;
678 
679 	if (buf->len > (CC13XX_CC26XX_TX_BUF_SIZE - IEEE802154_PHY_SUN_FSK_PHR_LEN)) {
680 		return -EINVAL;
681 	}
682 
683 	if (mode != IEEE802154_TX_MODE_DIRECT) {
684 		/* For backwards compatibility we only log an error but do not bail. */
685 		NET_ERR("TX mode %d not supported - sending directly instead.", mode);
686 	}
687 
688 	if (k_sem_take(&drv_data->lock, K_FOREVER)) {
689 		return -EIO;
690 	}
691 
692 	if (!drv_data->is_up) {
693 		ret = -ENETDOWN;
694 		goto out;
695 	}
696 
697 	if (drv_data->cmd_prop_rx_adv.status == ACTIVE) {
698 		ret = drv_stop_rx(dev);
699 		if (ret) {
700 			ret = -EIO;
701 			goto out;
702 		}
703 	}
704 
705 	/* Complete the SUN FSK PHY header, see IEEE 802.15.4, section 19.2.4. */
706 	drv_data->tx_data[0] = buf->len + IEEE802154_FCS_LENGTH;
707 
708 	/* Set TX data
709 	 *
710 	 * TODO: Zero-copy TX, see discussion in #49775.
711 	 */
712 	memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], buf->data, buf->len);
713 	drv_data->cmd_prop_tx_adv.pktLen = buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN;
714 
715 	drv_data->cmd_prop_tx_adv.status = IDLE;
716 	events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_prop_tx_adv,
717 			   RF_PriorityNormal, cmd_prop_tx_adv_callback, RF_EventLastCmdDone);
718 	if ((events & RF_EventLastCmdDone) == 0) {
719 		LOG_DBG("Failed to run command (%" PRIx64 ")", events);
720 		ret = -EIO;
721 		goto out;
722 	}
723 
724 	if (drv_data->cmd_prop_tx_adv.status != PROP_DONE_OK) {
725 		LOG_DBG("Transmit failed (0x%x)", drv_data->cmd_prop_tx_adv.status);
726 		ret = -EIO;
727 	}
728 
729 out:
730 	(void)drv_start_rx(dev);
731 
732 	k_sem_give(&drv_data->lock);
733 	return ret;
734 }
735 
736 /* driver-allocated attribute memory - constant across all driver instances */
737 IEEE802154_DEFINE_PHY_SUPPORTED_CHANNELS(drv_attr, 0, 10);
738 
ieee802154_cc13xx_cc26xx_subg_attr_get(const struct device * dev,enum ieee802154_attr attr,struct ieee802154_attr_value * value)739 static int ieee802154_cc13xx_cc26xx_subg_attr_get(const struct device *dev,
740 						  enum ieee802154_attr attr,
741 						  struct ieee802154_attr_value *value)
742 {
743 	ARG_UNUSED(dev);
744 
745 	/* We claim channel page nine with channel page zero channel range to
746 	 * ensure SUN-FSK timing, see the TODO in
747 	 * ieee802154_cc13xx_cc26xx_subg_channel_to_frequency().
748 	 */
749 	return ieee802154_attr_get_channel_page_and_range(
750 		attr, IEEE802154_ATTR_PHY_CHANNEL_PAGE_NINE_SUN_PREDEFINED,
751 		&drv_attr.phy_supported_channels, value);
752 }
753 
ieee802154_cc13xx_cc26xx_subg_start(const struct device * dev)754 static int ieee802154_cc13xx_cc26xx_subg_start(const struct device *dev)
755 {
756 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
757 	int ret;
758 
759 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
760 		return -EIO;
761 	}
762 
763 	if (drv_data->is_up) {
764 		ret = -EALREADY;
765 		goto out;
766 	}
767 
768 	ret = drv_start_rx(dev);
769 	if (ret) {
770 		goto out;
771 	}
772 
773 	drv_data->is_up = true;
774 
775 out:
776 	k_sem_give(&drv_data->lock);
777 	return ret;
778 }
779 
780 /* Aborts all radio commands in the RF queue. Requires the lock to be held. */
drv_abort_commands(const struct device * dev)781 static int drv_abort_commands(const struct device *dev)
782 {
783 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
784 	RF_Stat status;
785 
786 	status = RF_flushCmd(drv_data->rf_handle, RF_CMDHANDLE_FLUSH_ALL, 0);
787 	if (!(status == RF_StatCmdDoneSuccess
788 		|| status == RF_StatSuccess
789 		|| status == RF_StatRadioInactiveError
790 		|| status == RF_StatInvalidParamsError)) {
791 		LOG_DBG("Failed to abort radio operations (%d)", status);
792 		return -EIO;
793 	}
794 
795 	return 0;
796 }
797 
798 /**
799  * Stops the sub-GHz interface and yields the radio (tells RF module to power
800  * down).
801  */
ieee802154_cc13xx_cc26xx_subg_stop_if(const struct device * dev)802 static int ieee802154_cc13xx_cc26xx_subg_stop_if(const struct device *dev)
803 {
804 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
805 	int ret;
806 
807 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
808 		return -EIO;
809 	}
810 
811 	if (!drv_data->is_up) {
812 		ret = -EALREADY;
813 		goto out;
814 	}
815 
816 	ret = drv_abort_commands(dev);
817 	if (ret) {
818 		goto out;
819 	}
820 
821 	ret = drv_power_down(dev);
822 	if (ret) {
823 		goto out;
824 	}
825 
826 	drv_data->is_up = false;
827 
828  out:
829 	k_sem_give(&drv_data->lock);
830 	return ret;
831 }
832 
833 static int
ieee802154_cc13xx_cc26xx_subg_configure(const struct device * dev,enum ieee802154_config_type type,const struct ieee802154_config * config)834 ieee802154_cc13xx_cc26xx_subg_configure(const struct device *dev,
835 					enum ieee802154_config_type type,
836 					const struct ieee802154_config *config)
837 {
838 	return -ENOTSUP;
839 }
840 
drv_setup_rx_buffers(struct ieee802154_cc13xx_cc26xx_subg_data * drv_data)841 static void drv_setup_rx_buffers(struct ieee802154_cc13xx_cc26xx_subg_data *drv_data)
842 {
843 	/* No need to zero buffers as they are zeroed on initialization and no
844 	 * need for locking as initialization is done with exclusive access.
845 	 */
846 
847 	for (size_t i = 0; i < CC13XX_CC26XX_NUM_RX_BUF; ++i) {
848 		if (i < CC13XX_CC26XX_NUM_RX_BUF - 1) {
849 			drv_data->rx_entry[i].pNextEntry =
850 				(uint8_t *) &drv_data->rx_entry[i + 1];
851 		} else {
852 			drv_data->rx_entry[i].pNextEntry =
853 				(uint8_t *) &drv_data->rx_entry[0];
854 		}
855 
856 		drv_data->rx_entry[i].config.type = DATA_ENTRY_TYPE_PTR;
857 		drv_data->rx_entry[i].config.lenSz = 1;
858 		drv_data->rx_entry[i].length = sizeof(drv_data->rx_data[0]);
859 		drv_data->rx_entry[i].pData = drv_data->rx_data[i];
860 	}
861 
862 	drv_data->rx_queue.pCurrEntry = (uint8_t *)&drv_data->rx_entry[0];
863 	drv_data->rx_queue.pLastEntry = NULL;
864 }
865 
drv_setup_tx_buffer(struct ieee802154_cc13xx_cc26xx_subg_data * drv_data)866 static void drv_setup_tx_buffer(struct ieee802154_cc13xx_cc26xx_subg_data *drv_data)
867 {
868 	/* No need to zero buffers as they are zeroed on initialization and no
869 	 * need for locking as initialization is done with exclusive access.
870 	 */
871 
872 	/* Part of the SUN FSK PHY header, see IEEE 802.15.4, section 19.2.4. */
873 	drv_data->tx_data[1] = BIT(3) | /* FCS Type: 2-octet FCS */
874 			       BIT(4);  /* DW: Enable Data Whitening */
875 
876 	drv_data->cmd_prop_tx_adv.pPkt = drv_data->tx_data;
877 }
878 
drv_data_init(struct ieee802154_cc13xx_cc26xx_subg_data * drv_data)879 static void drv_data_init(struct ieee802154_cc13xx_cc26xx_subg_data *drv_data)
880 {
881 	uint8_t *mac;
882 
883 	/* TODO: Do multi-protocol devices need more than one IEEE MAC? */
884 	if (sys_read32(CCFG_BASE + CCFG_O_IEEE_MAC_0) != 0xFFFFFFFF &&
885 	    sys_read32(CCFG_BASE + CCFG_O_IEEE_MAC_1) != 0xFFFFFFFF) {
886 		mac = (uint8_t *)(CCFG_BASE + CCFG_O_IEEE_MAC_0);
887 	} else {
888 		mac = (uint8_t *)(FCFG1_BASE + FCFG1_O_MAC_15_4_0);
889 	}
890 
891 	sys_memcpy_swap(&drv_data->mac, mac, sizeof(drv_data->mac));
892 
893 	/* Setup circular RX queue (TRM 25.3.2.7) */
894 	drv_setup_rx_buffers(drv_data);
895 
896 	/* Setup TX buffer (TRM 25.10.2.1.1, table 25-171) */
897 	drv_setup_tx_buffer(drv_data);
898 
899 	k_sem_init(&drv_data->lock, 1, 1);
900 }
901 
ieee802154_cc13xx_cc26xx_subg_iface_init(struct net_if * iface)902 static void ieee802154_cc13xx_cc26xx_subg_iface_init(struct net_if *iface)
903 {
904 	const struct device *dev = net_if_get_device(iface);
905 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
906 
907 	net_if_set_link_addr(iface, drv_data->mac, sizeof(drv_data->mac),
908 			     NET_LINK_IEEE802154);
909 
910 	drv_data->iface = iface;
911 
912 	ieee802154_init(iface);
913 }
914 
915 static const struct ieee802154_radio_api
916 	ieee802154_cc13xx_cc26xx_subg_radio_api = {
917 	.iface_api.init = ieee802154_cc13xx_cc26xx_subg_iface_init,
918 
919 	.get_capabilities = ieee802154_cc13xx_cc26xx_subg_get_capabilities,
920 	.cca = ieee802154_cc13xx_cc26xx_subg_cca,
921 	.set_channel = ieee802154_cc13xx_cc26xx_subg_set_channel,
922 	.filter = ieee802154_cc13xx_cc26xx_subg_filter,
923 	.set_txpower = ieee802154_cc13xx_cc26xx_subg_set_txpower,
924 	.tx = ieee802154_cc13xx_cc26xx_subg_tx,
925 	.start = ieee802154_cc13xx_cc26xx_subg_start,
926 	.stop = ieee802154_cc13xx_cc26xx_subg_stop_if,
927 	.configure = ieee802154_cc13xx_cc26xx_subg_configure,
928 	.attr_get = ieee802154_cc13xx_cc26xx_subg_attr_get,
929 };
930 
ieee802154_cc13xx_cc26xx_subg_init(const struct device * dev)931 static int ieee802154_cc13xx_cc26xx_subg_init(const struct device *dev)
932 {
933 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
934 	uint16_t freq, fract;
935 	RF_Params rf_params;
936 	RF_EventMask events;
937 
938 	/* No need for locking - initialization is exclusive. */
939 
940 	/* Initialize driver data */
941 	drv_data_init(drv_data);
942 
943 	/* Setup radio */
944 	RF_Params_init(&rf_params);
945 	rf_params.pErrCb = client_error_callback;
946 	rf_params.pClientEventCb = client_event_callback;
947 
948 	drv_data->rf_handle = RF_open(&drv_data->rf_object,
949 		&rf_mode, (RF_RadioSetup *)&ieee802154_cc13xx_subg_radio_div_setup,
950 		&rf_params);
951 	if (drv_data->rf_handle == NULL) {
952 		LOG_ERR("RF_open() failed");
953 		return -EIO;
954 	}
955 
956 	/* Run CMD_FS for channel 0 to place a valid CMD_FS command in the
957 	 * driver's internal state which it requires for proper operation.
958 	 */
959 	(void)drv_channel_frequency(0, &freq, &fract);
960 	drv_data->cmd_fs.status = IDLE;
961 	drv_data->cmd_fs.frequency = freq;
962 	drv_data->cmd_fs.fractFreq = fract;
963 	events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_fs,
964 			   RF_PriorityNormal, NULL, 0);
965 	if (events != RF_EventLastCmdDone || drv_data->cmd_fs.status != DONE_OK) {
966 		LOG_ERR("Failed to set frequency: 0x%" PRIx64, events);
967 		return -EIO;
968 	}
969 
970 	return drv_power_down(dev);
971 }
972 
973 static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_data = {
974 	/* Common Radio Commands */
975 	.cmd_fs = {
976 		.commandNo = CMD_FS,
977 		.condition.rule = COND_NEVER,
978 	},
979 
980 	.cmd_prop_rx_adv = {
981 		.commandNo = CMD_PROP_RX_ADV,
982 		.condition.rule = COND_NEVER,
983 		.pktConf = {
984 			.bRepeatOk = true,
985 			.bRepeatNok = true,
986 			.bUseCrc = true,
987 			.filterOp = true,
988 		},
989 		.rxConf = {
990 			.bAutoFlushIgnored = true,
991 			.bAutoFlushCrcErr = true,
992 			.bAppendRssi = true,
993 			.bAppendStatus = true,
994 		},
995 		/* Last preamble byte and SFD for uncoded 2-FSK SUN PHY, phySunFskSfd = 0,
996 		 * see IEEE 802.15.4, section 19.2.3.2, table 19-2.
997 		 */
998 		.syncWord0 = 0x55904E,
999 		.maxPktLen = IEEE802154_MAX_PHY_PACKET_SIZE,
1000 		/* PHR field format, see IEEE 802.15.4, section 19.2.4 */
1001 		.hdrConf = {
1002 			.numHdrBits = 16,
1003 			.numLenBits = 11,
1004 		},
1005 		.lenOffset = -4,
1006 		.endTrigger.triggerType = TRIG_NEVER,
1007 		.pQueue = &ieee802154_cc13xx_cc26xx_subg_data.rx_queue,
1008 		.pOutput =
1009 			(uint8_t *) &ieee802154_cc13xx_cc26xx_subg_data
1010 				.cmd_prop_rx_adv_output,
1011 	},
1012 
1013 	.cmd_prop_cs = {
1014 		.commandNo = CMD_PROP_CS,
1015 		.condition.rule = COND_NEVER,
1016 		.csConf = {
1017 			/* CCA Mode 1: Energy above threshold, see section 10.2.8.
1018 			 * CC13/26xx SubG does not support correlation mode.
1019 			 */
1020 			.bEnaRssi = true,
1021 			/* Abort as soon as any energy above the ED threshold is detected. */
1022 			.busyOp = true,
1023 			/* Continue sensing until the timeout is reached. */
1024 			.idleOp = false,
1025 		},
1026 		.rssiThr = CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CS_THRESHOLD,
1027 		.csEndTrigger.triggerType = TRIG_REL_START,
1028 		/* see IEEE 802.15.4, section 11.3, table 11-1 and section 10.2.8 */
1029 		.csEndTime = RF_convertUsToRatTicks(
1030 			IEEE802154_PHY_A_CCA_TIME *
1031 				(IEEE802154_PHY_SUN_FSK_863MHZ_915MHZ_SYMBOL_PERIOD_NS /
1032 					NSEC_PER_USEC)
1033 		),
1034 	},
1035 
1036 	.cmd_prop_tx_adv = {
1037 		.commandNo = CMD_PROP_TX_ADV,
1038 		.startTrigger.triggerType = TRIG_NOW,
1039 		.startTrigger.pastTrig = true,
1040 		.condition.rule = COND_NEVER,
1041 		.pktConf.bUseCrc = true,
1042 		/* PHR field format, see IEEE 802.15.4, section 19.2.4 */
1043 		.numHdrBits = 16,
1044 		.preTrigger.triggerType =
1045 			TRIG_REL_START, /* workaround for CC13_RF_ROM_FW_CPE--BUG00016 */
1046 		.preTrigger.pastTrig = true,
1047 		/* Last preamble byte and SFD for uncoded 2-FSK SUN PHY, phySunFskSfd = 0,
1048 		 * see IEEE 802.15.4, section 19.2.3.2, table 19-2.
1049 		 */
1050 		.syncWord = 0x55904E,
1051 	},
1052 };
1053 
1054 #if defined(CONFIG_NET_L2_IEEE802154)
1055 NET_DEVICE_DT_INST_DEFINE(0, ieee802154_cc13xx_cc26xx_subg_init, NULL,
1056 			  &ieee802154_cc13xx_cc26xx_subg_data, NULL,
1057 			  CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_INIT_PRIO,
1058 			  &ieee802154_cc13xx_cc26xx_subg_radio_api,
1059 			  IEEE802154_L2, NET_L2_GET_CTX_TYPE(IEEE802154_L2),
1060 			  IEEE802154_MTU);
1061 #else
1062 DEVICE_DT_INST_DEFINE(0, ieee802154_cc13xx_cc26xx_subg_init, NULL,
1063 		      &ieee802154_cc13xx_cc26xx_subg_data, NULL, POST_KERNEL,
1064 		      CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_INIT_PRIO,
1065 		      &ieee802154_cc13xx_cc26xx_subg_radio_api);
1066 #endif
1067