1 /*
2  * Copyright (c) 2021 Florin Stancu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * Implements the RF driver callback to configure the on-board antenna
9  * switch.
10  */
11 
12 #define DT_DRV_COMPAT skyworks_sky13317
13 
14 #include <zephyr/init.h>
15 #include <zephyr/device.h>
16 #include <zephyr/drivers/gpio.h>
17 #include <zephyr/drivers/pinctrl.h>
18 
19 #include <ti/drivers/rf/RF.h>
20 #include <driverlib/rom.h>
21 #include <driverlib/interrupt.h>
22 
23 /* custom pinctrl states for the antenna mux */
24 #define PINCTRL_STATE_ANT_24G		1
25 #define PINCTRL_STATE_ANT_24G_PA	2
26 #define PINCTRL_STATE_ANT_SUBG		3
27 #define PINCTRL_STATE_ANT_SUBG_PA	4
28 
29 #define BOARD_ANT_GPIO_24G   0
30 #define BOARD_ANT_GPIO_PA    1
31 #define BOARD_ANT_GPIO_SUBG  2
32 
33 static int board_antenna_init(const struct device *dev);
34 static void board_cc13xx_rf_callback(RF_Handle client, RF_GlobalEvent events, void *arg);
35 
36 const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = {
37 	.hwiPriority = INT_PRI_LEVEL7,
38 	.swiPriority = 0,
39 	.xoscHfAlwaysNeeded = true,
40 	/* RF driver callback for custom antenna switching */
41 	.globalCallback = board_cc13xx_rf_callback,
42 	/* Subscribe to events */
43 	.globalEventMask = (RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown),
44 };
45 
46 PINCTRL_DT_INST_DEFINE(0);
47 DEVICE_DT_INST_DEFINE(0, board_antenna_init, NULL, NULL, NULL, POST_KERNEL,
48 		      CONFIG_BOARD_ANTENNA_INIT_PRIO, NULL);
49 
50 static const struct pinctrl_dev_config *ant_pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0);
51 static const struct gpio_dt_spec ant_gpios[] = {
52 	DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(antenna_mux0), gpios, GPIO_DT_SPEC_GET_BY_IDX, (,))};
53 
54 /**
55  * Antenna switch GPIO init routine.
56  */
board_antenna_init(const struct device * dev)57 static int board_antenna_init(const struct device *dev)
58 {
59 	ARG_UNUSED(dev);
60 	int i;
61 
62 	/* default pinctrl configuration: set all antenna mux control pins as GPIOs */
63 	pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_DEFAULT);
64 	/* set all GPIOs to 0 (all RF paths disabled) */
65 	for (i = 0; i < ARRAY_SIZE(ant_gpios); i++) {
66 		gpio_pin_configure_dt(&ant_gpios[i], 0);
67 	}
68 	return 0;
69 }
70 
71 /**
72  * Custom TI RFCC26XX callback for switching the on-board antenna mux on radio setup.
73  */
board_cc13xx_rf_callback(RF_Handle client,RF_GlobalEvent events,void * arg)74 static void board_cc13xx_rf_callback(RF_Handle client, RF_GlobalEvent events, void *arg)
75 {
76 	bool sub1GHz = false;
77 	uint8_t loDivider = 0;
78 	int i;
79 
80 	/* Clear all antenna switch GPIOs (for all cases). */
81 	for (i = 0; i < ARRAY_SIZE(ant_gpios); i++) {
82 		gpio_pin_configure_dt(&ant_gpios[i], 0);
83 	}
84 
85 	if (events & RF_GlobalEventRadioSetup) {
86 		/* Decode the current PA configuration. */
87 		RF_TxPowerTable_PAType paType =
88 			(RF_TxPowerTable_PAType)RF_getTxPower(client).paType;
89 		/* Decode the generic argument as a setup command. */
90 		RF_RadioSetup *setupCommand = (RF_RadioSetup *)arg;
91 
92 		switch (setupCommand->common.commandNo) {
93 		case CMD_RADIO_SETUP:
94 		case CMD_BLE5_RADIO_SETUP:
95 			loDivider = RF_LODIVIDER_MASK & setupCommand->common.loDivider;
96 			break;
97 		case CMD_PROP_RADIO_DIV_SETUP:
98 			loDivider = RF_LODIVIDER_MASK & setupCommand->prop_div.loDivider;
99 			break;
100 		default:
101 			break;
102 		}
103 		sub1GHz = (loDivider != 0);
104 
105 		if (sub1GHz) {
106 			if (paType == RF_TxPowerTable_HighPA) {
107 				/* Note: RFC_GPO3 is a work-around because the RFC_GPO1 */
108 				/* is sometimes not de-asserted on CC1352 Rev A. */
109 				pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_ANT_SUBG_PA);
110 			} else {
111 				pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_ANT_SUBG);
112 				/* Manually set the sub-GHZ antenna switch DIO */
113 				gpio_pin_configure_dt(&ant_gpios[BOARD_ANT_GPIO_SUBG], 1);
114 			}
115 		} else /* 2.4 GHz */ {
116 			if (paType == RF_TxPowerTable_HighPA) {
117 				pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_ANT_24G_PA);
118 			} else {
119 				pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_ANT_24G);
120 				/* Manually set the 2.4GHZ antenna switch DIO */
121 				gpio_pin_configure_dt(&ant_gpios[BOARD_ANT_GPIO_24G], 1);
122 			}
123 		}
124 	} else {
125 		pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_DEFAULT);
126 	}
127 }
128