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 			/* TODO: Configure firmware to include CRC in raw mode. */
344 			if (IS_ENABLED(CONFIG_IEEE802154_RAW_MODE) && len > 0) {
345 				/* append CRC-16/CCITT */
346 				uint16_t crc = 0;
347 
348 				crc = crc16_ccitt(0, sdu, len);
349 				sdu[len++] = crc;
350 				sdu[len++] = crc >> 8;
351 			}
352 
353 			LOG_DBG("Received: len = %u, rssi = %d status = %u",
354 				len, rssi, status);
355 
356 			pkt = net_pkt_rx_alloc_with_buffer(
357 				drv_data->iface, len, AF_UNSPEC, 0, K_NO_WAIT);
358 			if (!pkt) {
359 				LOG_WRN("Cannot allocate packet");
360 				continue;
361 			}
362 
363 			if (net_pkt_write(pkt, sdu, len)) {
364 				LOG_WRN("Cannot write packet");
365 				net_pkt_unref(pkt);
366 				continue;
367 			}
368 
369 			drv_data->rx_entry[i].status = DATA_ENTRY_PENDING;
370 
371 			/* TODO: Determine LQI in PROP mode. */
372 			net_pkt_set_ieee802154_lqi(pkt, 0xff);
373 			net_pkt_set_ieee802154_rssi_dbm(pkt,
374 							rssi == CC13XX_CC26XX_INVALID_RSSI
375 								? IEEE802154_MAC_RSSI_DBM_UNDEFINED
376 								: rssi);
377 
378 			if (ieee802154_handle_ack(drv_data->iface, pkt) == NET_OK) {
379 				net_pkt_unref(pkt);
380 				continue;
381 			}
382 
383 			if (net_recv_data(drv_data->iface, pkt)) {
384 				LOG_WRN("Packet dropped");
385 				net_pkt_unref(pkt);
386 			}
387 
388 		} else if (drv_data->rx_entry[i].status ==
389 			   DATA_ENTRY_UNFINISHED) {
390 			LOG_WRN("Frame not finished");
391 			drv_data->rx_entry[i].status = DATA_ENTRY_PENDING;
392 		}
393 	}
394 }
395 
cmd_prop_rx_adv_callback(RF_Handle h,RF_CmdHandle ch,RF_EventMask e)396 static void cmd_prop_rx_adv_callback(RF_Handle h, RF_CmdHandle ch,
397 	RF_EventMask e)
398 {
399 	const struct device *const dev = DEVICE_DT_INST_GET(0);
400 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
401 	RF_Op *op = RF_getCmdOp(h, ch);
402 
403 	LOG_DBG("ch: %u cmd: %04x st: %04x e: 0x%" PRIx64, ch,
404 		op->commandNo, op->status, e);
405 
406 	/* If PROP_ERROR_RXBUF is returned, then RF_EventRxEntryDone is never
407 	 * triggered. So finished buffers need to be cleaned up even on this
408 	 * status.
409 	 */
410 	if (e & RF_EventRxEntryDone || op->status == PROP_ERROR_RXBUF) {
411 		drv_rx_done(drv_data);
412 	}
413 
414 	if (op->status == PROP_ERROR_RXBUF
415 		|| op->status == PROP_ERROR_RXFULL
416 		|| op->status == PROP_ERROR_RXOVF) {
417 		LOG_DBG("RX Error %x", op->status);
418 
419 		/* Restart RX */
420 		if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
421 			return;
422 		}
423 
424 		(void)drv_start_rx(dev);
425 		k_sem_give(&drv_data->lock);
426 	}
427 }
428 
client_error_callback(RF_Handle h,RF_CmdHandle ch,RF_EventMask e)429 static void client_error_callback(RF_Handle h, RF_CmdHandle ch,
430 	RF_EventMask e)
431 {
432 	ARG_UNUSED(h);
433 	ARG_UNUSED(ch);
434 	LOG_ERR("client error: 0x%" PRIx64, e);
435 }
436 
client_event_callback(RF_Handle h,RF_ClientEvent event,void * arg)437 static void client_event_callback(RF_Handle h, RF_ClientEvent event,
438 	void *arg)
439 {
440 	ARG_UNUSED(h);
441 	LOG_DBG("event: %d arg: %p", event, arg);
442 }
443 
444 static enum ieee802154_hw_caps
ieee802154_cc13xx_cc26xx_subg_get_capabilities(const struct device * dev)445 ieee802154_cc13xx_cc26xx_subg_get_capabilities(const struct device *dev)
446 {
447 	/* TODO: enable IEEE802154_HW_FILTER */
448 	return IEEE802154_HW_FCS;
449 }
450 
ieee802154_cc13xx_cc26xx_subg_cca(const struct device * dev)451 static int ieee802154_cc13xx_cc26xx_subg_cca(const struct device *dev)
452 {
453 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
454 	bool was_rx_on = false;
455 	RF_EventMask events;
456 	int ret;
457 
458 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
459 		return -EWOULDBLOCK;
460 	}
461 
462 	if (!drv_data->is_up) {
463 		ret = -ENETDOWN;
464 		goto out;
465 	}
466 
467 	drv_data->cmd_prop_cs.status = IDLE;
468 
469 	was_rx_on = drv_data->cmd_prop_rx_adv.status == ACTIVE;
470 	if (was_rx_on) {
471 		ret = drv_stop_rx(dev);
472 		if (ret) {
473 			ret = -EIO;
474 			goto out;
475 		}
476 	}
477 
478 	events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_prop_cs, RF_PriorityNormal,
479 			   NULL, 0);
480 	if (events != RF_EventLastCmdDone) {
481 		LOG_DBG("Failed to request CCA: 0x%" PRIx64, events);
482 		ret = -EIO;
483 		goto out;
484 	}
485 
486 	switch (drv_data->cmd_prop_cs.status) {
487 	case PROP_DONE_IDLE:
488 		/* Do not re-enable RX when the channel is idle as
489 		 * this usually means we want to TX directly after
490 		 * and cannot afford any extra latency.
491 		 */
492 		ret = 0;
493 		break;
494 	case PROP_DONE_BUSY:
495 	case PROP_DONE_BUSYTIMEOUT:
496 		ret = -EBUSY;
497 		break;
498 	default:
499 		ret = -EIO;
500 	}
501 
502 out:
503 	/* Re-enable RX if we found it on initially
504 	 * and the channel is busy (or another error
505 	 * occurred) as this usually means we back off
506 	 * and want to be able to receive packets in
507 	 * the meantime.
508 	 */
509 	if (ret && was_rx_on) {
510 		drv_start_rx(dev);
511 	}
512 
513 	k_sem_give(&drv_data->lock);
514 	return ret;
515 }
516 
517 /* This method must be called with the lock held. */
drv_start_rx(const struct device * dev)518 static int drv_start_rx(const struct device *dev)
519 {
520 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
521 	RF_CmdHandle cmd_handle;
522 
523 	if (drv_data->cmd_prop_rx_adv.status == ACTIVE) {
524 		return -EALREADY;
525 	}
526 
527 #ifdef CONFIG_ASSERT
528 	if (CONFIG_ASSERT_LEVEL > 0) {
529 		/* ensure that all RX buffers are initialized and pending. */
530 		for (int i = 0; i < CC13XX_CC26XX_NUM_RX_BUF; i++) {
531 			__ASSERT_NO_MSG(drv_data->rx_entry[i].pNextEntry != NULL);
532 			__ASSERT_NO_MSG(drv_data->rx_entry[i].status == DATA_ENTRY_PENDING);
533 		}
534 	}
535 #endif
536 
537 	drv_data->cmd_prop_rx_adv.status = IDLE;
538 	cmd_handle = RF_postCmd(drv_data->rf_handle,
539 				(RF_Op *)&drv_data->cmd_prop_rx_adv, RF_PriorityNormal,
540 				cmd_prop_rx_adv_callback, RF_EventRxEntryDone);
541 	if (cmd_handle < 0) {
542 		LOG_DBG("Failed to post RX command (%d)", cmd_handle);
543 		return -EIO;
544 	}
545 
546 	drv_data->rx_cmd_handle = cmd_handle;
547 
548 	return 0;
549 }
550 
551 /* This method must be called with the lock held. */
drv_stop_rx(const struct device * dev)552 static int drv_stop_rx(const struct device *dev)
553 {
554 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
555 	RF_Stat status;
556 
557 	if (drv_data->cmd_prop_rx_adv.status != ACTIVE) {
558 		return -EALREADY;
559 	}
560 
561 	/* Stop RX without aborting ongoing reception of packets. */
562 	status = RF_cancelCmd(drv_data->rf_handle, drv_data->rx_cmd_handle, RF_ABORT_GRACEFULLY);
563 	switch (status) {
564 	case RF_StatSuccess:
565 	case RF_StatCmdEnded:
566 		return 0;
567 	default:
568 		return -EIO;
569 	}
570 }
571 
ieee802154_cc13xx_cc26xx_subg_set_channel(const struct device * dev,uint16_t channel)572 static int ieee802154_cc13xx_cc26xx_subg_set_channel(
573 	const struct device *dev, uint16_t channel)
574 {
575 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
576 	uint16_t freq, fract;
577 	RF_EventMask events;
578 	bool was_rx_on;
579 	int ret;
580 
581 	ret = drv_channel_frequency(channel, &freq, &fract);
582 	if (ret < 0) {
583 		return ret;
584 	}
585 
586 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
587 		return -EWOULDBLOCK;
588 	}
589 
590 	was_rx_on = drv_data->cmd_prop_rx_adv.status == ACTIVE;
591 	if (was_rx_on) {
592 		ret = drv_stop_rx(dev);
593 		if (ret) {
594 			ret = -EIO;
595 			goto out;
596 		}
597 	}
598 
599 	/* Set the frequency */
600 	drv_data->cmd_fs.status = IDLE;
601 	drv_data->cmd_fs.frequency = freq;
602 	drv_data->cmd_fs.fractFreq = fract;
603 	events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_fs,
604 			   RF_PriorityNormal, NULL, 0);
605 	if (events != RF_EventLastCmdDone || drv_data->cmd_fs.status != DONE_OK) {
606 		LOG_DBG("Failed to set frequency: 0x%" PRIx64, events);
607 		ret = -EIO;
608 	}
609 
610 out:
611 	if (was_rx_on) {
612 		/* Re-enable RX if we found it on initially. */
613 		(void)drv_start_rx(dev);
614 	} else if (!drv_data->is_up) {
615 		ret = drv_power_down(dev);
616 	}
617 
618 	k_sem_give(&drv_data->lock);
619 
620 	return ret;
621 }
622 
623 static int
ieee802154_cc13xx_cc26xx_subg_filter(const struct device * dev,bool set,enum ieee802154_filter_type type,const struct ieee802154_filter * filter)624 ieee802154_cc13xx_cc26xx_subg_filter(const struct device *dev, bool set,
625 				     enum ieee802154_filter_type type,
626 				     const struct ieee802154_filter *filter)
627 {
628 	ARG_UNUSED(dev);
629 	ARG_UNUSED(set);
630 	ARG_UNUSED(type);
631 	ARG_UNUSED(filter);
632 	return -ENOTSUP;
633 }
634 
ieee802154_cc13xx_cc26xx_subg_set_txpower(const struct device * dev,int16_t dbm)635 static int ieee802154_cc13xx_cc26xx_subg_set_txpower(
636 	const struct device *dev, int16_t dbm)
637 {
638 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
639 	RF_TxPowerTable_Value power_table_value;
640 	RF_Stat status;
641 	int ret = 0;
642 
643 	power_table_value = RF_TxPowerTable_findValue(
644 		(RF_TxPowerTable_Entry *)ieee802154_cc13xx_subg_power_table, dbm);
645 	if (power_table_value.rawValue == RF_TxPowerTable_INVALID_VALUE) {
646 		LOG_DBG("RF_TxPowerTable_findValue() failed");
647 		return -EINVAL;
648 	}
649 
650 	/* No need for locking: rf_handle is immutable after initialization. */
651 	status = RF_setTxPower(drv_data->rf_handle, power_table_value);
652 	if (status != RF_StatSuccess) {
653 		LOG_DBG("RF_setTxPower() failed: %d", status);
654 		return -EIO;
655 	}
656 
657 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
658 		return -EWOULDBLOCK;
659 	}
660 
661 	if (!drv_data->is_up) {
662 		ret = drv_power_down(dev);
663 	}
664 
665 	k_sem_give(&drv_data->lock);
666 
667 	return ret;
668 }
669 
670 /* 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)671 static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev,
672 					    enum ieee802154_tx_mode mode,
673 					    struct net_pkt *pkt,
674 					    struct net_buf *buf)
675 {
676 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
677 	RF_EventMask events;
678 	int ret = 0;
679 
680 	if (buf->len > (CC13XX_CC26XX_TX_BUF_SIZE - IEEE802154_PHY_SUN_FSK_PHR_LEN)) {
681 		return -EINVAL;
682 	}
683 
684 	if (mode != IEEE802154_TX_MODE_DIRECT) {
685 		/* For backwards compatibility we only log an error but do not bail. */
686 		NET_ERR("TX mode %d not supported - sending directly instead.", mode);
687 	}
688 
689 	if (k_sem_take(&drv_data->lock, K_FOREVER)) {
690 		return -EIO;
691 	}
692 
693 	if (!drv_data->is_up) {
694 		ret = -ENETDOWN;
695 		goto out;
696 	}
697 
698 	if (drv_data->cmd_prop_rx_adv.status == ACTIVE) {
699 		ret = drv_stop_rx(dev);
700 		if (ret) {
701 			ret = -EIO;
702 			goto out;
703 		}
704 	}
705 
706 	/* Complete the SUN FSK PHY header, see IEEE 802.15.4, section 19.2.4. */
707 	drv_data->tx_data[0] = buf->len + IEEE802154_FCS_LENGTH;
708 
709 	/* Set TX data
710 	 *
711 	 * TODO: Zero-copy TX, see discussion in #49775.
712 	 */
713 	memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], buf->data, buf->len);
714 	drv_data->cmd_prop_tx_adv.pktLen = buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN;
715 
716 	drv_data->cmd_prop_tx_adv.status = IDLE;
717 	events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_prop_tx_adv,
718 			   RF_PriorityNormal, cmd_prop_tx_adv_callback, RF_EventLastCmdDone);
719 	if ((events & RF_EventLastCmdDone) == 0) {
720 		LOG_DBG("Failed to run command (%" PRIx64 ")", events);
721 		ret = -EIO;
722 		goto out;
723 	}
724 
725 	if (drv_data->cmd_prop_tx_adv.status != PROP_DONE_OK) {
726 		LOG_DBG("Transmit failed (0x%x)", drv_data->cmd_prop_tx_adv.status);
727 		ret = -EIO;
728 	}
729 
730 out:
731 	(void)drv_start_rx(dev);
732 
733 	k_sem_give(&drv_data->lock);
734 	return ret;
735 }
736 
737 /* driver-allocated attribute memory - constant across all driver instances */
738 IEEE802154_DEFINE_PHY_SUPPORTED_CHANNELS(drv_attr, 0, 10);
739 
ieee802154_cc13xx_cc26xx_subg_attr_get(const struct device * dev,enum ieee802154_attr attr,struct ieee802154_attr_value * value)740 static int ieee802154_cc13xx_cc26xx_subg_attr_get(const struct device *dev,
741 						  enum ieee802154_attr attr,
742 						  struct ieee802154_attr_value *value)
743 {
744 	ARG_UNUSED(dev);
745 
746 	/* We claim channel page nine with channel page zero channel range to
747 	 * ensure SUN-FSK timing, see the TODO in
748 	 * ieee802154_cc13xx_cc26xx_subg_channel_to_frequency().
749 	 */
750 	return ieee802154_attr_get_channel_page_and_range(
751 		attr, IEEE802154_ATTR_PHY_CHANNEL_PAGE_NINE_SUN_PREDEFINED,
752 		&drv_attr.phy_supported_channels, value);
753 }
754 
ieee802154_cc13xx_cc26xx_subg_start(const struct device * dev)755 static int ieee802154_cc13xx_cc26xx_subg_start(const struct device *dev)
756 {
757 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
758 	int ret;
759 
760 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
761 		return -EIO;
762 	}
763 
764 	if (drv_data->is_up) {
765 		ret = -EALREADY;
766 		goto out;
767 	}
768 
769 	ret = drv_start_rx(dev);
770 	if (ret) {
771 		goto out;
772 	}
773 
774 	drv_data->is_up = true;
775 
776 out:
777 	k_sem_give(&drv_data->lock);
778 	return ret;
779 }
780 
781 /* Aborts all radio commands in the RF queue. Requires the lock to be held. */
drv_abort_commands(const struct device * dev)782 static int drv_abort_commands(const struct device *dev)
783 {
784 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
785 	RF_Stat status;
786 
787 	status = RF_flushCmd(drv_data->rf_handle, RF_CMDHANDLE_FLUSH_ALL, 0);
788 	if (!(status == RF_StatCmdDoneSuccess
789 		|| status == RF_StatSuccess
790 		|| status == RF_StatRadioInactiveError
791 		|| status == RF_StatInvalidParamsError)) {
792 		LOG_DBG("Failed to abort radio operations (%d)", status);
793 		return -EIO;
794 	}
795 
796 	return 0;
797 }
798 
799 /**
800  * Stops the sub-GHz interface and yields the radio (tells RF module to power
801  * down).
802  */
ieee802154_cc13xx_cc26xx_subg_stop_if(const struct device * dev)803 static int ieee802154_cc13xx_cc26xx_subg_stop_if(const struct device *dev)
804 {
805 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
806 	int ret;
807 
808 	if (k_sem_take(&drv_data->lock, LOCK_TIMEOUT)) {
809 		return -EIO;
810 	}
811 
812 	if (!drv_data->is_up) {
813 		ret = -EALREADY;
814 		goto out;
815 	}
816 
817 	ret = drv_abort_commands(dev);
818 	if (ret) {
819 		goto out;
820 	}
821 
822 	ret = drv_power_down(dev);
823 	if (ret) {
824 		goto out;
825 	}
826 
827 	drv_data->is_up = false;
828 
829  out:
830 	k_sem_give(&drv_data->lock);
831 	return ret;
832 }
833 
834 static int
ieee802154_cc13xx_cc26xx_subg_configure(const struct device * dev,enum ieee802154_config_type type,const struct ieee802154_config * config)835 ieee802154_cc13xx_cc26xx_subg_configure(const struct device *dev,
836 					enum ieee802154_config_type type,
837 					const struct ieee802154_config *config)
838 {
839 	return -ENOTSUP;
840 }
841 
drv_setup_rx_buffers(struct ieee802154_cc13xx_cc26xx_subg_data * drv_data)842 static void drv_setup_rx_buffers(struct ieee802154_cc13xx_cc26xx_subg_data *drv_data)
843 {
844 	/* No need to zero buffers as they are zeroed on initialization and no
845 	 * need for locking as initialization is done with exclusive access.
846 	 */
847 
848 	for (size_t i = 0; i < CC13XX_CC26XX_NUM_RX_BUF; ++i) {
849 		if (i < CC13XX_CC26XX_NUM_RX_BUF - 1) {
850 			drv_data->rx_entry[i].pNextEntry =
851 				(uint8_t *) &drv_data->rx_entry[i + 1];
852 		} else {
853 			drv_data->rx_entry[i].pNextEntry =
854 				(uint8_t *) &drv_data->rx_entry[0];
855 		}
856 
857 		drv_data->rx_entry[i].config.type = DATA_ENTRY_TYPE_PTR;
858 		drv_data->rx_entry[i].config.lenSz = 1;
859 		drv_data->rx_entry[i].length = sizeof(drv_data->rx_data[0]);
860 		drv_data->rx_entry[i].pData = drv_data->rx_data[i];
861 	}
862 
863 	drv_data->rx_queue.pCurrEntry = (uint8_t *)&drv_data->rx_entry[0];
864 	drv_data->rx_queue.pLastEntry = NULL;
865 }
866 
drv_setup_tx_buffer(struct ieee802154_cc13xx_cc26xx_subg_data * drv_data)867 static void drv_setup_tx_buffer(struct ieee802154_cc13xx_cc26xx_subg_data *drv_data)
868 {
869 	/* No need to zero buffers as they are zeroed on initialization and no
870 	 * need for locking as initialization is done with exclusive access.
871 	 */
872 
873 	/* Part of the SUN FSK PHY header, see IEEE 802.15.4, section 19.2.4. */
874 	drv_data->tx_data[1] = BIT(3) | /* FCS Type: 2-octet FCS */
875 			       BIT(4);  /* DW: Enable Data Whitening */
876 
877 	drv_data->cmd_prop_tx_adv.pPkt = drv_data->tx_data;
878 }
879 
drv_data_init(struct ieee802154_cc13xx_cc26xx_subg_data * drv_data)880 static void drv_data_init(struct ieee802154_cc13xx_cc26xx_subg_data *drv_data)
881 {
882 	uint8_t *mac;
883 
884 	/* TODO: Do multi-protocol devices need more than one IEEE MAC? */
885 	if (sys_read32(CCFG_BASE + CCFG_O_IEEE_MAC_0) != 0xFFFFFFFF &&
886 	    sys_read32(CCFG_BASE + CCFG_O_IEEE_MAC_1) != 0xFFFFFFFF) {
887 		mac = (uint8_t *)(CCFG_BASE + CCFG_O_IEEE_MAC_0);
888 	} else {
889 		mac = (uint8_t *)(FCFG1_BASE + FCFG1_O_MAC_15_4_0);
890 	}
891 
892 	sys_memcpy_swap(&drv_data->mac, mac, sizeof(drv_data->mac));
893 
894 	/* Setup circular RX queue (TRM 25.3.2.7) */
895 	drv_setup_rx_buffers(drv_data);
896 
897 	/* Setup TX buffer (TRM 25.10.2.1.1, table 25-171) */
898 	drv_setup_tx_buffer(drv_data);
899 
900 	k_sem_init(&drv_data->lock, 1, 1);
901 }
902 
ieee802154_cc13xx_cc26xx_subg_iface_init(struct net_if * iface)903 static void ieee802154_cc13xx_cc26xx_subg_iface_init(struct net_if *iface)
904 {
905 	const struct device *dev = net_if_get_device(iface);
906 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
907 
908 	net_if_set_link_addr(iface, drv_data->mac, sizeof(drv_data->mac),
909 			     NET_LINK_IEEE802154);
910 
911 	drv_data->iface = iface;
912 
913 	ieee802154_init(iface);
914 }
915 
916 static const struct ieee802154_radio_api
917 	ieee802154_cc13xx_cc26xx_subg_radio_api = {
918 	.iface_api.init = ieee802154_cc13xx_cc26xx_subg_iface_init,
919 
920 	.get_capabilities = ieee802154_cc13xx_cc26xx_subg_get_capabilities,
921 	.cca = ieee802154_cc13xx_cc26xx_subg_cca,
922 	.set_channel = ieee802154_cc13xx_cc26xx_subg_set_channel,
923 	.filter = ieee802154_cc13xx_cc26xx_subg_filter,
924 	.set_txpower = ieee802154_cc13xx_cc26xx_subg_set_txpower,
925 	.tx = ieee802154_cc13xx_cc26xx_subg_tx,
926 	.start = ieee802154_cc13xx_cc26xx_subg_start,
927 	.stop = ieee802154_cc13xx_cc26xx_subg_stop_if,
928 	.configure = ieee802154_cc13xx_cc26xx_subg_configure,
929 	.attr_get = ieee802154_cc13xx_cc26xx_subg_attr_get,
930 };
931 
ieee802154_cc13xx_cc26xx_subg_init(const struct device * dev)932 static int ieee802154_cc13xx_cc26xx_subg_init(const struct device *dev)
933 {
934 	struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data;
935 	uint16_t freq, fract;
936 	RF_Params rf_params;
937 	RF_EventMask events;
938 
939 	/* No need for locking - initialization is exclusive. */
940 
941 	/* Initialize driver data */
942 	drv_data_init(drv_data);
943 
944 	/* Setup radio */
945 	RF_Params_init(&rf_params);
946 	rf_params.pErrCb = client_error_callback;
947 	rf_params.pClientEventCb = client_event_callback;
948 
949 	drv_data->rf_handle = RF_open(&drv_data->rf_object,
950 		&rf_mode, (RF_RadioSetup *)&ieee802154_cc13xx_subg_radio_div_setup,
951 		&rf_params);
952 	if (drv_data->rf_handle == NULL) {
953 		LOG_ERR("RF_open() failed");
954 		return -EIO;
955 	}
956 
957 	/* Run CMD_FS for channel 0 to place a valid CMD_FS command in the
958 	 * driver's internal state which it requires for proper operation.
959 	 */
960 	(void)drv_channel_frequency(0, &freq, &fract);
961 	drv_data->cmd_fs.status = IDLE;
962 	drv_data->cmd_fs.frequency = freq;
963 	drv_data->cmd_fs.fractFreq = fract;
964 	events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_fs,
965 			   RF_PriorityNormal, NULL, 0);
966 	if (events != RF_EventLastCmdDone || drv_data->cmd_fs.status != DONE_OK) {
967 		LOG_ERR("Failed to set frequency: 0x%" PRIx64, events);
968 		return -EIO;
969 	}
970 
971 	return drv_power_down(dev);
972 }
973 
974 static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_data = {
975 	/* Common Radio Commands */
976 	.cmd_fs = {
977 		.commandNo = CMD_FS,
978 		.condition.rule = COND_NEVER,
979 	},
980 
981 	.cmd_prop_rx_adv = {
982 		.commandNo = CMD_PROP_RX_ADV,
983 		.condition.rule = COND_NEVER,
984 		.pktConf = {
985 			.bRepeatOk = true,
986 			.bRepeatNok = true,
987 			.bUseCrc = true,
988 			.filterOp = true,
989 		},
990 		.rxConf = {
991 			.bAutoFlushIgnored = true,
992 			.bAutoFlushCrcErr = true,
993 			.bAppendRssi = true,
994 			.bAppendStatus = true,
995 		},
996 		/* Last preamble byte and SFD for uncoded 2-FSK SUN PHY, phySunFskSfd = 0,
997 		 * see IEEE 802.15.4, section 19.2.3.2, table 19-2.
998 		 */
999 		.syncWord0 = 0x55904E,
1000 		.maxPktLen = IEEE802154_MAX_PHY_PACKET_SIZE,
1001 		/* PHR field format, see IEEE 802.15.4, section 19.2.4 */
1002 		.hdrConf = {
1003 			.numHdrBits = 16,
1004 			.numLenBits = 11,
1005 		},
1006 		.lenOffset = -4,
1007 		.endTrigger.triggerType = TRIG_NEVER,
1008 		.pQueue = &ieee802154_cc13xx_cc26xx_subg_data.rx_queue,
1009 		.pOutput =
1010 			(uint8_t *) &ieee802154_cc13xx_cc26xx_subg_data
1011 				.cmd_prop_rx_adv_output,
1012 	},
1013 
1014 	.cmd_prop_cs = {
1015 		.commandNo = CMD_PROP_CS,
1016 		.condition.rule = COND_NEVER,
1017 		.csConf = {
1018 			/* CCA Mode 1: Energy above threshold, see section 10.2.8.
1019 			 * CC13/26xx SubG does not support correlation mode.
1020 			 */
1021 			.bEnaRssi = true,
1022 			/* Abort as soon as any energy above the ED threshold is detected. */
1023 			.busyOp = true,
1024 			/* Continue sensing until the timeout is reached. */
1025 			.idleOp = false,
1026 		},
1027 		.rssiThr = CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CS_THRESHOLD,
1028 		.csEndTrigger.triggerType = TRIG_REL_START,
1029 		/* see IEEE 802.15.4, section 11.3, table 11-1 and section 10.2.8 */
1030 		.csEndTime = RF_convertUsToRatTicks(
1031 			IEEE802154_PHY_A_CCA_TIME *
1032 				(IEEE802154_PHY_SUN_FSK_863MHZ_915MHZ_SYMBOL_PERIOD_NS /
1033 					NSEC_PER_USEC)
1034 		),
1035 	},
1036 
1037 	.cmd_prop_tx_adv = {
1038 		.commandNo = CMD_PROP_TX_ADV,
1039 		.startTrigger.triggerType = TRIG_NOW,
1040 		.startTrigger.pastTrig = true,
1041 		.condition.rule = COND_NEVER,
1042 		.pktConf.bUseCrc = true,
1043 		/* PHR field format, see IEEE 802.15.4, section 19.2.4 */
1044 		.numHdrBits = 16,
1045 		.preTrigger.triggerType =
1046 			TRIG_REL_START, /* workaround for CC13_RF_ROM_FW_CPE--BUG00016 */
1047 		.preTrigger.pastTrig = true,
1048 		/* Last preamble byte and SFD for uncoded 2-FSK SUN PHY, phySunFskSfd = 0,
1049 		 * see IEEE 802.15.4, section 19.2.3.2, table 19-2.
1050 		 */
1051 		.syncWord = 0x55904E,
1052 	},
1053 };
1054 
1055 #if defined(CONFIG_NET_L2_IEEE802154)
1056 NET_DEVICE_DT_INST_DEFINE(0, ieee802154_cc13xx_cc26xx_subg_init, NULL,
1057 			  &ieee802154_cc13xx_cc26xx_subg_data, NULL,
1058 			  CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_INIT_PRIO,
1059 			  &ieee802154_cc13xx_cc26xx_subg_radio_api,
1060 			  IEEE802154_L2, NET_L2_GET_CTX_TYPE(IEEE802154_L2),
1061 			  IEEE802154_MTU);
1062 #else
1063 DEVICE_DT_INST_DEFINE(0, ieee802154_cc13xx_cc26xx_subg_init, NULL,
1064 		      &ieee802154_cc13xx_cc26xx_subg_data, NULL, POST_KERNEL,
1065 		      CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_INIT_PRIO,
1066 		      &ieee802154_cc13xx_cc26xx_subg_radio_api);
1067 #endif
1068