1 /*
2  * Copyright (c) 2021 Fabio Baltieri
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 
9 #include "sx126x_common.h"
10 
11 #include <stm32wlxx_ll_exti.h>
12 #include <stm32wlxx_ll_pwr.h>
13 #include <stm32wlxx_ll_rcc.h>
14 
15 #include <zephyr/logging/log.h>
16 #include <zephyr/irq.h>
17 LOG_MODULE_DECLARE(sx126x, CONFIG_LORA_LOG_LEVEL);
18 
19 static const enum {
20 	RFO_LP,
21 	RFO_HP,
22 } pa_output = DT_INST_STRING_UPPER_TOKEN(0, power_amplifier_output);
23 
sx126x_reset(struct sx126x_data * dev_data)24 void sx126x_reset(struct sx126x_data *dev_data)
25 {
26 	LL_RCC_RF_EnableReset();
27 	k_sleep(K_MSEC(20));
28 	LL_RCC_RF_DisableReset();
29 	k_sleep(K_MSEC(10));
30 }
31 
sx126x_is_busy(struct sx126x_data * dev_data)32 bool sx126x_is_busy(struct sx126x_data *dev_data)
33 {
34 	return LL_PWR_IsActiveFlag_RFBUSYS();
35 }
36 
sx126x_get_dio1_pin_state(struct sx126x_data * dev_data)37 uint32_t sx126x_get_dio1_pin_state(struct sx126x_data *dev_data)
38 {
39 	return 0;
40 }
41 
sx126x_dio1_irq_enable(struct sx126x_data * dev_data)42 void sx126x_dio1_irq_enable(struct sx126x_data *dev_data)
43 {
44 	NVIC_ClearPendingIRQ(DT_INST_IRQN(0));
45 	irq_enable(DT_INST_IRQN(0));
46 }
47 
sx126x_dio1_irq_disable(struct sx126x_data * dev_data)48 void sx126x_dio1_irq_disable(struct sx126x_data *dev_data)
49 {
50 	irq_disable(DT_INST_IRQN(0));
51 }
52 
sx126x_set_tx_params(int8_t power,RadioRampTimes_t ramp_time)53 void sx126x_set_tx_params(int8_t power, RadioRampTimes_t ramp_time)
54 {
55 	uint8_t buf[2];
56 
57 	if (pa_output == RFO_LP) {
58 		const int8_t max_power = DT_INST_PROP(0, rfo_lp_max_power);
59 
60 		if (power > max_power) {
61 			power = max_power;
62 		}
63 		if (max_power == 15) {
64 			SX126xSetPaConfig(0x07, 0x00, 0x01, 0x01);
65 			power = 14 - (max_power - power);
66 		} else if (max_power == 10) {
67 			SX126xSetPaConfig(0x01, 0x00, 0x01, 0x01);
68 			power = 13 - (max_power - power);
69 		} else { /* default +14 dBm */
70 			SX126xSetPaConfig(0x04, 0x00, 0x01, 0x01);
71 			power = 14 - (max_power - power);
72 		}
73 		if (power < -17) {
74 			power = -17;
75 		}
76 
77 		/* PA overcurrent protection limit 60 mA */
78 		SX126xWriteRegister(REG_OCP, 0x18);
79 	} else { /* RFO_HP */
80 		/* Better Resistance of the RFO High Power Tx to Antenna
81 		 * Mismatch, see STM32WL Erratasheet
82 		 */
83 		SX126xWriteRegister(REG_TX_CLAMP_CFG,
84 				    SX126xReadRegister(REG_TX_CLAMP_CFG)
85 					| (0x0F << 1));
86 
87 		const int8_t max_power = DT_INST_PROP(0, rfo_hp_max_power);
88 
89 		if (power > max_power) {
90 			power = max_power;
91 		}
92 		if (max_power == 20) {
93 			SX126xSetPaConfig(0x03, 0x05, 0x00, 0x01);
94 			power = 22 - (max_power - power);
95 		} else if (max_power == 17) {
96 			SX126xSetPaConfig(0x02, 0x03, 0x00, 0x01);
97 			power = 22 - (max_power - power);
98 		} else if (max_power == 14) {
99 			SX126xSetPaConfig(0x02, 0x02, 0x00, 0x01);
100 			power = 14 - (max_power - power);
101 		} else { /* default +22 dBm */
102 			SX126xSetPaConfig(0x04, 0x07, 0x00, 0x01);
103 			power = 22 - (max_power - power);
104 		}
105 		if (power < -9) {
106 			power = -9;
107 		}
108 
109 		/* PA overcurrent protection limit 140 mA */
110 		SX126xWriteRegister(REG_OCP, 0x38);
111 	}
112 
113 	buf[0] = power;
114 	buf[1] = (uint8_t)ramp_time;
115 	SX126xWriteCommand(RADIO_SET_TXPARAMS, buf, 2);
116 }
117 
radio_isr(const struct device * dev)118 static void radio_isr(const struct device *dev)
119 {
120 	struct sx126x_data *dev_data = dev->data;
121 
122 	irq_disable(DT_INST_IRQN(0));
123 	k_work_submit(&dev_data->dio1_irq_work);
124 }
125 
sx126x_variant_init(const struct device * dev)126 int sx126x_variant_init(const struct device *dev)
127 {
128 	IRQ_CONNECT(DT_INST_IRQN(0),
129 		    DT_INST_IRQ(0, priority),
130 		    radio_isr, DEVICE_DT_INST_GET(0), 0);
131 	LL_EXTI_EnableIT_32_63(LL_EXTI_LINE_44);
132 	irq_enable(DT_INST_IRQN(0));
133 
134 	return 0;
135 }
136