/*- * Copyright (c) 2017 Jian-Hong, Pan * Copyright (c) 2024 Fabian Montero * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * */ #define DEBUG #define SX127X_LEGACY_KERNEL #include #include #include #include #include #include #include #include #include #ifndef F_XOSC #define F_XOSC 32000000 #endif static u32 xosc_frq = F_XOSC; module_param(xosc_frq, uint, 0000); MODULE_PARM_DESC(xosc_frq, "Crystal oscillator frequency of the LoRa chip"); #define __POW_2_19 0x80000 #ifndef SX127X_SPRF #define SX127X_SPRF 512 #endif static u32 sprf = SX127X_SPRF; module_param(sprf, uint, 0000); MODULE_PARM_DESC(sprf, "Spreading factor of Chirp Spread Spectrum modulation"); #ifndef SX127X_RX_BYTE_TIMEOUT #define SX127X_RX_BYTE_TIMEOUT 1023 #endif static u32 rx_timeout = SX127X_RX_BYTE_TIMEOUT; module_param(rx_timeout, uint, 0000); MODULE_PARM_DESC(rx_timeout, "RX time-out value as number of symbols"); /* SX127X Registers addresses */ #define SX127X_REG_FIFO 0x00 #define SX127X_REG_OP_MODE 0x01 #define SX127X_REG_FRF_MSB 0x06 #define SX127X_REG_FRF_MID 0x07 #define SX127X_REG_FRF_LSB 0x08 #define SX127X_REG_PA_CONFIG 0x09 #define SX127X_REG_PA_RAMP 0x0A #define SX127X_REG_OCP 0x0B #define SX127X_REG_LNA 0x0C #define SX127X_REG_FIFO_ADDR_PTR 0x0D #define SX127X_REG_FIFO_TX_BASE_ADDR 0x0E #define SX127X_REG_FIFO_RX_BASE_ADDR 0x0F #define SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10 #define SX127X_REG_IRQ_FLAGS_MASK 0x11 #define SX127X_REG_IRQ_FLAGS 0x12 #define SX127X_REG_RX_NB_BYTES 0x13 #define SX127X_REG_RX_HEADER_CNT_VALUE_MSB 0x14 #define SX127X_REG_RX_HEADER_CNT_VALUE_LSB 0x15 #define SX127X_REG_RX_PACKET_CNT_VALUE_MSB 0x16 #define SX127X_REG_RX_PACKET_CNT_VALUE_LSB 0x17 #define SX127X_REG_MODEM_STAT 0x18 #define SX127X_REG_PKT_SNR_VALUE 0x19 #define SX127X_REG_PKT_RSSI_VALUE 0x1A #define SX127X_REG_RSSI_VALUE 0x1B #define SX127X_REG_HOP_CHANNEL 0x1C #define SX127X_REG_MODEM_CONFIG1 0x1D #define SX127X_REG_MODEM_CONFIG2 0x1E #define SX127X_REG_SYMB_TIMEOUT_LSB 0x1F #define SX127X_REG_PREAMBLE_MSB 0x20 #define SX127X_REG_PREAMBLE_LSB 0x21 #define SX127X_REG_PAYLOAD_LENGTH 0x22 #define SX127X_REG_MAX_PAYLOAD_LENGTH 0x23 #define SX127X_REG_HOP_PERIOD 0x24 #define SX127X_REG_FIFO_RX_BYTE_ADDR 0x25 #define SX127X_REG_MODEM_CONFIG3 0x26 #define SX127X_REG_FEI_MSB 0x28 #define SX127X_REG_FEI_MID 0x29 #define SX127X_REG_FEI_LSB 0x2A #define SX127X_REG_RSSI_WIDEBAND 0x2C #define SX127X_REG_DETECT_OPTIMIZE 0x31 #define SX127X_REG_INVERT_IRQ 0x33 #define SX127X_REG_DETECTION_THRESHOLD 0x37 #define SX127X_REG_SYNC_WORD 0x39 #define SX127X_REG_VERSION 0x42 #define SX127X_REG_TCXO 0x4B #define SX127X_REG_PA_DAC 0x4D #define SX127X_REG_FORMER_TEMP 0x5B #define SX127X_REG_AGC_REF 0x61 #define SX127X_REG_AGC_THRESH1 0x62 #define SX127X_REG_AGC_THRESH2 0x63 #define SX127X_REG_AGC_THRESH3 0x64 #define SX127X_REG_PLL 0x70 #define SX127X_MAX_REG SX127X_REG_PLL /* SX127X's operating states in LoRa mode */ #define SX127X_MODE_MASK 0x07 #define SX127X_SLEEP_MODE 0x00 #define SX127X_STANDBY_MODE 0x01 #define SX127X_FSTX_MODE 0x02 #define SX127X_TX_MODE 0x03 #define SX127X_FSRX_MODE 0x04 #define SX127X_RXCONTINUOUS_MODE 0x05 #define SX127X_RXSINGLE_MODE 0x06 #define SX127X_CAD_MODE 0x07 #define SX127X_LORA_MODE 0x80 /* SX127X_REG_OCP flags */ #define SX127X_FLAG_OCPON 0x20 /* SX127X's IRQ flags in LoRa mode */ #define SX127X_FLAG_RXTIMEOUT 0x80 #define SX127X_FLAG_RXDONE 0x40 #define SX127X_FLAG_PAYLOADCRCERROR 0x20 #define SX127X_FLAG_VALIDHEADER 0x10 #define SX127X_FLAG_TXDONE 0x08 #define SX127X_FLAG_CADDONE 0x04 #define SX127X_FLAG_FHSSCHANGECHANNEL 0x02 #define SX127X_FLAG_CADDETECTED 0x01 /* SX127X's IRQ flags' mask for output pins in LoRa mode */ #define SX127X_FLAGMASK_RXTIMEOUT 0x80 #define SX127X_FLAGMASK_RXDONE 0x40 #define SX127X_FLAGMASK_PAYLOADCRCERROR 0x20 #define SX127X_FLAGMASK_VALIDHEADER 0x10 #define SX127X_FLAGMASK_TXDONE 0x08 #define SX127X_FLAGMASK_CADDONE 0x04 #define SX127X_FLAGMASK_FHSSCHANGECHANNEL 0x02 #define SX127X_FLAGMASK_CADDETECTED 0x01 #define SX127X_MODEM_CONFIG1_HEADER_MODE_MASK 0x01 #define SX127X_MODEM_CONFIG1_HEADER_MODE_EXPLICIT 0x00 #define SX127X_MODEM_CONFIG1_HEADER_MODE_IMPLICIT 0x01 #define SX127X_MODEM_CONFIG2_RXPAYLOADCRCON 0x04 #define SX127X_MODEM_CONFIG3_AGCAUTOON 0x04 /* SX127X's RX/TX FIFO base address */ #define SX127X_FIFO_RX_BASE_ADDRESS 0x00 #define SX127X_FIFO_TX_BASE_ADDRESS 0x80 #define POLL_JIFFIES (msecs_to_jiffies(10)) /*stct sx1278_phy { struct ieee802154_hw *hw; struct regmap *map; bool suspended; u8 opmode; struct timer_list timer; struct work_struct irqwork; spinlock_t buf_lock; struct sk_buff *tx_buf; u8 tx_delay; bool one_to_be_sent; bool post_tx_done; bool is_busy; }; int sx127X_read_version(struct regmap *map) { u8 v; int status; status = sx127x_reg_read(hw, SX127X_REG_VERSION, &v); if ((status == 0) && (v > 0) && (v < 0xFF)) status = v; else status = -ENODEV; return status; } void sx127X_set_mode(struct regmap *map, u8 op_mode) { sx127x_reg_write(hw, SX127X_REG_OP_MODE, op_mode); } u8 sx127X_get_mode(struct regmap *map) { u8 op_mode; sx127x_reg_read(hw, SX127X_REG_OP_MODE, &op_mode); return op_mode; } void sx127X_set_state(struct regmap *map, u8 st) { u8 op_mode; op_mode = sx127X_get_mode(map); op_mode = (op_mode & 0xF8) | (st & 0x07); sx127x_reg_write(hw, SX127X_REG_OP_MODE, op_mode); } u8 sx127X_get_state(struct regmap *map) { u8 op_mode; op_mode = sx127X_get_mode(map) & 0x07; return op_mode; } void sx127X_set_lorafrq(struct regmap *map, u32 fr) { u64 frt; u8 buf[3]; s8 i; u32 f_xosc; u8 op_mode; struct device_node *of_node = (regmap_get_device(map))->of_node; if (of_property_read_u32(of_node, "clock-frequency", &f_xosc)) f_xosc = xosc_frq; frt = (uint64_t)fr * (uint64_t)__POW_2_19; do_div(frt, f_xosc); for (i = 2; i >= 0; i--) buf[i] = do_div(frt, 256); op_mode = sx127X_get_mode(map); if (fr >= 779000000) op_mode &= ~0x8; else if (fr <= 525000000) op_mode |= 0x8; sx127X_set_state(map, SX127X_SLEEP_MODE); regmap_raw_write(map, SX127X_REG_FRF_MSB, buf, 3); sx127X_set_mode(map, op_mode); } u32 sx127X_get_lorafrq(struct regmap *map) { u64 frt = 0; u8 buf[3]; u8 i; int status; u32 fr; u32 f_xosc; struct device_node *of_node = (regmap_get_device(map))->of_node; if (of_property_read_u32(of_node, "clock-frequency", &f_xosc)) f_xosc = xosc_frq; status = regmap_raw_read(map, SX127X_REG_FRF_MSB, buf, 3); if (status < 0) return 0.0; for (i = 0; i <= 2; i++) frt = frt * 256 + buf[i]; fr = frt * f_xosc / __POW_2_19; return fr; } void sx127X_set_lorapower(struct regmap *map, s32 pout) { u8 pacf; u8 boost; u8 output_power; s32 pmax; if (pout > 14) { boost = 1; pmax = 7; output_power = pout - 2; } else if (pout < 0) { boost = 0; pmax = 2; output_power = 3 + pout; } else { boost = 0; pmax = 7; output_power = pout; } pacf = (boost << 7) | (pmax << 4) | (output_power); sx127x_reg_write(hw, SX127X_REG_PA_CONFIG, pacf); } s32 sx127X_get_lorapower(struct regmap *map) { u8 pac; u8 boost; s32 output_power; s32 pmax; s32 pout; sx127x_reg_read(hw, SX127X_REG_PA_CONFIG, &pac); boost = (pac & 0x80) >> 7; output_power = pac & 0x0F; if (boost) { pout = 2 + output_power; } else { pmax = (108 + 6 * ((pac & 0x70) >> 4)); pout = (pmax - (150 - output_power * 10)) / 10; } return pout; } #define sx127X_dbm2mbm(dbm) (dbm * 100) #define sx127X_mbm2dbm(mbm) (mbm / 100) s8 lna_gain[] = { 0, -6, -12, -24, -26, -48 }; void sx127X_set_loralna(struct regmap *map, s32 db) { u8 i, g; u8 lnacf; for (i = 0; i < 5; i++) { if (lna_gain[i] <= db) break; } g = i + 1; sx127x_reg_read(hw, SX127X_REG_LNA, &lnacf); lnacf = (lnacf & 0x1F) | (g << 5); sx127x_reg_write(hw, SX127X_REG_LNA, lnacf); } s32 sx127X_get_loralna(struct regmap *map) { s32 db; s8 i, g; u8 lnacf; sx127x_reg_read(hw, SX127X_REG_LNA, &lnacf); g = (lnacf >> 5); i = g - 1; db = lna_gain[i]; return db; } void sx127X_set_loralnaagc(struct regmap *map, s32 yesno) { u8 mcf3; sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG3, &mcf3); mcf3 = (yesno) ? (mcf3 | 0x04) : (mcf3 & (~0x04)); sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG3, mcf3); } u8 sx127X_get_loraallflag(struct regmap *map) { u8 flags; sx127x_reg_read(hw, SX127X_REG_IRQ_FLAGS, &flags); return flags; } #define sx127X_get_loraflag(map, f) (sx127X_get_loraallflag(map) & (f)) void sx127X_clear_loraflag(struct regmap *map, u8 f) { u8 flag; flag = sx127X_get_loraallflag(map); flag |= f; sx127x_reg_write(hw, SX127X_REG_IRQ_FLAGS, flag); } #define sx127X_clear_loraallflag(spi) sx127X_clear_loraflag(spi, 0xFF) void sx127X_set_lorasprf(struct regmap *map, u32 c_s) { u8 sf; u8 mcf2; for (sf = 6; sf < 12; sf++) { if (c_s == ((u32)1 << sf)) break; } sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &mcf2); mcf2 = (mcf2 & 0x0F) | (sf << 4); sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG2, mcf2); } u32 sx127X_get_lorasprf(struct regmap *map) { u8 sf; u32 c_s; sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &sf); sf = sf >> 4; c_s = 1 << sf; return c_s; } const u32 hz[] = { 7800, 10400, 15600, 20800, 31250, 41700, 62500, 125000, 250000, 500000 }; void sx127X_set_lorabw(struct regmap *map, u32 bw) { u8 i; u8 mcf1; for (i = 0; i < 9; i++) { if (hz[i] >= bw) break; } sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); mcf1 = (mcf1 & 0x0F) | (i << 4); sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, mcf1); } u32 sx127X_get_lorabw(struct regmap *map) { u8 mcf1; u8 bw; sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); bw = mcf1 >> 4; return hz[bw]; } void sx127X_set_loracr(struct regmap *map, u8 cr) { u8 mcf1; sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); mcf1 = (mcf1 & 0x0E) | (((cr & 0xF) - 4) << 1); sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, mcf1); } u8 sx127X_get_loracr(struct regmap *map) { u8 mcf1; u8 cr; sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); cr = 0x40 + ((mcf1 & 0x0E) >> 1) + 4; return cr; } void sx127X_set_loraimplicit(struct regmap *map, u8 yesno) { u8 mcf1; sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); mcf1 = (yesno) ? (mcf1 | 0x01) : (mcf1 & 0xFE); sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, mcf1); } void sx127X_set_lorarxbytetimeout(struct regmap *map, u32 n) { u8 buf[2]; u8 mcf2; if (n < 1) n = 1; if (n > 1023) n = 1023; sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &mcf2); buf[1] = n % 256; buf[0] = (mcf2 & 0xFC) | (n >> 8); regmap_raw_write(map, SX127X_REG_MODEM_CONFIG2, buf, 2); } void sx127X_set_lorarxtimeout(struct regmap *map, u32 ms) { u32 n; n = ms * sx127X_get_lorabw(map) / (sx127X_get_lorasprf(map) * 1000); sx127X_set_lorarxbytetimeout(map, n); } u32 sx127X_get_lorarxbytetimeout(struct regmap *map) { u32 n; u8 buf[2]; regmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, buf, 2); n = (buf[0] & 0x03) * 256 + buf[1]; return n; } u32 sx127X_get_lorarxtimeout(struct regmap *map) { u32 ms; ms = 1000 * sx127X_get_lorarxbytetimeout(map) * sx127X_get_lorasprf(map) / sx127X_get_lorabw(map); return ms; } void sx127X_set_loramaxrxbuff(struct regmap *map, u8 len) { sx127x_reg_write(hw, SX127X_REG_MAX_PAYLOAD_LENGTH, len); } u8 sx127X_get_loralastpktpayloadlen(struct regmap *map) { u8 len; sx127x_reg_read(hw, SX127X_REG_RX_NB_BYTES, &len); return len; } ssize_t sx127X_readloradata(struct regmap *map, u8 *buf, size_t len) { u8 start_adr; int ret; start_adr = SX127X_FIFO_RX_BASE_ADDRESS; sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, start_adr); len = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU; ret = regmap_raw_read(map, SX127X_REG_FIFO, buf, len); return (ret >= 0) ? len : ret; } size_t sx127X_sendloradata(struct regmap *map, u8 *buf, size_t len) { u8 base_adr; u8 blen; base_adr = SX127X_FIFO_TX_BASE_ADDRESS; sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, base_adr); blen = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU; regmap_raw_write(map, SX127X_REG_FIFO, buf, blen); sx127x_reg_write(hw, SX127X_REG_PAYLOAD_LENGTH, blen); return blen; } s32 sx127X_get_loralastpktsnr(struct regmap *map) { s32 db; s8 snr; sx127x_reg_read(hw, SX127X_REG_PKT_SNR_VALUE, &snr); db = snr / 4; return db; } s32 sx127X_get_loralastpktrssi(struct regmap *map) { s32 dbm; u8 lhf; u8 rssi; s8 snr; lhf = sx127X_get_mode(map) & 0x08; sx127x_reg_read(hw, SX127X_REG_PKT_RSSI_VALUE, &rssi); dbm = (lhf) ? -164 + rssi : -157 + rssi; sx127x_reg_read(hw, SX127X_REG_PKT_SNR_VALUE, &snr); if (snr < 0) dbm += snr / 4; return dbm; } s32 sx127X_get_lorarssi(struct regmap *map) { s32 dbm; u8 lhf; u8 rssi; lhf = sx127X_get_mode(map) & 0x08; sx127x_reg_read(hw, SX127X_REG_RSSI_VALUE, &rssi); dbm = (lhf) ? -164 + rssi : -157 + rssi; return dbm; } void sx127X_set_lorapreamblelen(struct regmap *map, u32 len) { u8 pl[2]; pl[1] = len % 256; pl[0] = (len >> 8) % 256; regmap_raw_write(map, SX127X_REG_PREAMBLE_MSB, pl, 2); } u32 sx127X_get_lorapreamblelen(struct regmap *map) { u8 pl[2]; u32 len; regmap_raw_read(map, SX127X_REG_PREAMBLE_MSB, pl, 2); len = pl[0] * 256 + pl[1]; return len; } sx127X_set_loracrc(struct regmap *map, u8 yesno) { u8 mcf2; sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &mcf2); mcf2 = (yesno) ? mcf2 | (1 << 2) : mcf2 & (~(1 << 2)); sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG2, mcf2); } void sx127X_set_boost(struct regmap *map, u8 yesno) { u8 pacf; sx127x_reg_read(hw, SX127X_REG_PA_CONFIG, &pacf); pacf = (yesno) ? pacf | (1 << 7) : pacf & (~(1 << 7)); sx127x_reg_write(hw, SX127X_REG_PA_CONFIG, pacf); } void sx127X_start_loramode(struct regmap *map) { u8 op_mode; u8 base_adr; struct device_node *of_node = (regmap_get_device(map))->of_node; op_mode = sx127X_get_mode(map); dev_dbg(regmap_get_device(map), "the original OP mode is 0x%X\n", op_mode); sx127X_set_state(map, SX127X_SLEEP_MODE); op_mode = sx127X_get_mode(map); op_mode = op_mode | 0x80; sx127x_reg_write(hw, SX127X_REG_OP_MODE, op_mode); sx127X_set_state(map, SX127X_STANDBY_MODE); op_mode = sx127X_get_mode(map); dev_dbg(regmap_get_device(map), "the current OP mode is 0x%X\n", op_mode); sx127X_set_loraimplicit(map, 0); base_adr = SX127X_FIFO_RX_BASE_ADDRESS; sx127x_reg_write(hw, SX127X_REG_FIFO_RX_BASE_ADDR, base_adr); base_adr = SX127X_FIFO_TX_BASE_ADDRESS; sx127x_reg_write(hw, SX127X_REG_FIFO_TX_BASE_ADDR, base_adr); of_property_read_u32(of_node, "spreading-factor", &sprf); sx127X_set_lorasprf(map, sprf); sx127X_set_lorarxbytetimeout(map, rx_timeout); sx127X_clear_loraallflag(map); sx127X_set_state(map, SX127X_RXSINGLE_MODE); } int init_sx127x(struct regmap *map) { int v; #ifdef DEBUG u8 fv, mv; #endif dev_dbg(regmap_get_device(map), "init sx127X\n"); v = sx127X_read_version(map); if (v > 0) { #ifdef DEBUG fv = (v >> 4) & 0xF; mv = v & 0xF; dev_dbg(regmap_get_device(map), "chip version %d.%d\n", fv, mv); #endif return 0; } else { return -ENODEV; } } #ifndef SX1278_IEEE_SENSITIVITY #define SX1278_IEEE_SENSITIVITY (-148) #endif static s32 sensitivity = SX1278_IEEE_SENSITIVITY; module_param(sensitivity, int, 0000); MODULE_PARM_DESC(sensitivity, "RF receiver's sensitivity"); #define SX1278_IEEE_ENERGY_RANGE (-sensitivity) static int sx1278_ieee_ed(struct ieee802154_hw *hw, u8 *level) { struct sx1278_phy *phy = hw->priv; s32 rssi; s32 range = SX1278_IEEE_ENERGY_RANGE - 10; dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); rssi = sx127X_get_lorarssi(phy->map); if (rssi < (sensitivity + 10)) *level = 0; else if (rssi >= 0) *level = 255; else *level = ((s32)255 * (rssi + range) / range) % 255; return 0; } #ifndef SX1278_IEEE_CHANNEL_MIN #define SX1278_IEEE_CHANNEL_MIN 11 #endif static u8 channel_min = SX1278_IEEE_CHANNEL_MIN; module_param(channel_min, byte, 0000); MODULE_PARM_DESC(channel_min, "Minimal channel number"); #ifndef SX1278_IEEE_CHANNEL_MAX #define SX1278_IEEE_CHANNEL_MAX 11 #endif static u8 channel_max = SX1278_IEEE_CHANNEL_MAX; module_param(channel_max, byte, 0000); MODULE_PARM_DESC(channel_max, "Maximum channel number"); #ifndef SX1278_IEEE_CENTER_CARRIER_FRQ #define SX1278_IEEE_CENTER_CARRIER_FRQ 434000000 #endif static u32 carrier_frq = SX1278_IEEE_CENTER_CARRIER_FRQ; module_param(carrier_frq, uint, 0000); MODULE_PARM_DESC(carrier_frq, "Center carrier frequency in Hz"); #ifndef SX1278_IEEE_BANDWIDTH #define SX1278_IEEE_BANDWIDTH 500000 #endif static u32 bandwidth = SX1278_IEEE_BANDWIDTH; module_param(bandwidth, uint, 0000); MODULE_PARM_DESC(bandwidth, "Bandwidth in Hz"); struct rf_frq { u32 carrier; u32 bw; u8 ch_min; u8 ch_max; }; void sx1278_ieee_get_rf_config(struct ieee802154_hw *hw, struct rf_frq *rf) { struct sx1278_phy *phy = hw->priv; struct device_node *of_node = (regmap_get_device(phy->map))->of_node; if (of_property_read_u32(of_node, "center-carrier-frq", &rf->carrier)) rf->carrier = carrier_frq; if (of_property_read_u32(of_node, "rf-bandwidth", &rf->bw)) rf->bw = bandwidth; if (of_property_read_u8(of_node, "minimal-RF-channel", &rf->ch_min)) rf->ch_min = channel_min; if (of_property_read_u8(of_node, "maximum-RF-channel", &rf->ch_max)) rf->ch_max = channel_max; } static int sx1278_ieee_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel) { struct sx1278_phy *phy = hw->priv; struct rf_frq rf; u32 fr; s8 d; dev_dbg(regmap_get_device(phy->map), "%s channel: %u\n", __func__, channel); sx1278_ieee_get_rf_config(hw, &rf); if (channel < rf.ch_min) channel = rf.ch_min; else if (channel > rf.ch_max) channel = rf.ch_max; d = channel - (rf.ch_min + rf.ch_max) / 2; fr = rf.carrier + d * rf.bw; sx127X_set_lorafrq(phy->map, fr); phy->opmode = sx127X_get_mode(phy->map); return 0; } static int sx1278_ieee_set_txpower(struct ieee802154_hw *hw, s32 mbm) { struct sx1278_phy *phy = hw->priv; s32 dbm = sx127X_mbm2dbm(mbm); dev_dbg(regmap_get_device(phy->map), "%s TX power: %d mbm\n", __func__, mbm); sx127X_set_lorapower(phy->map, dbm); return 0; } int sx1278_ieee_rx(struct ieee802154_hw *hw) { struct sx1278_phy *phy = hw->priv; bool do_rx; unsigned long f; dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); spin_lock_irqsave(&phy->buf_lock, f); if (!phy->is_busy) { phy->is_busy = true; do_rx = true; } else { do_rx = false; } spin_unlock_irqrestore(&phy->buf_lock, f); if (do_rx) { sx127X_set_state(phy->map, SX127X_RXSINGLE_MODE); return 0; } else { dev_dbg(regmap_get_device(phy->map), "%s: device is busy\n", __func__); return -EBUSY; } } static int sx1278_ieee_rx_complete(struct ieee802154_hw *hw) { struct sx1278_phy *phy = hw->priv; struct sk_buff *skb; u8 len; u8 lqi; s32 rssi; s32 range = SX1278_IEEE_ENERGY_RANGE; int err; unsigned long f; skb = dev_alloc_skb(IEEE802154_MTU); if (!skb) { err = -ENOMEM; dev_err(regmap_get_device(phy->map), "%s: driver is out of memory\n", __func__); goto sx1278_ieee_rx_err; } len = sx127X_get_loralastpktpayloadlen(phy->map); sx127X_readloradata(phy->map, skb_put(skb, len), len); rssi = sx127X_get_loralastpktrssi(phy->map); rssi = (rssi > 0) ? 0 : rssi; lqi = ((s32)255 * (rssi + range) / range) % 255; ieee802154_rx_irqsafe(hw, skb, lqi); dev_dbg(regmap_get_device(phy->map), "%s: len=%u LQI=%u\n", __func__, len, lqi); err = 0; sx1278_ieee_rx_err: spin_lock_irqsave(&phy->buf_lock, f); phy->is_busy = false; spin_unlock_irqrestore(&phy->buf_lock, f); return err; } int sx1278_ieee_tx(struct ieee802154_hw *hw) { struct sx1278_phy *phy = hw->priv; struct sk_buff *tx_buf = phy->tx_buf; bool do_tx = false; unsigned long f; dev_dbg(regmap_get_device(phy->map), "%s: len=%u\n", __func__, tx_buf->len); if (!phy->post_tx_done) { sx127X_sendloradata(phy->map, tx_buf->data, tx_buf->len); phy->post_tx_done = true; } spin_lock_irqsave(&phy->buf_lock, f); if (!phy->is_busy) { phy->is_busy = true; do_tx = true; phy->one_to_be_sent = false; } spin_unlock_irqrestore(&phy->buf_lock, f); if (do_tx) { phy->opmode = (phy->opmode & 0xF8) | SX127X_TX_MODE; regmap_write_async(phy->map, SX127X_REG_OP_MODE, phy->opmode); return 0; } else { dev_dbg(regmap_get_device(phy->map), "%s: device is busy\n", __func__); return -EBUSY; } } static int sx1278_ieee_tx_complete(struct ieee802154_hw *hw) { struct sx1278_phy *phy = hw->priv; struct sk_buff *skb = phy->tx_buf; unsigned long f; dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); ieee802154_xmit_complete(hw, skb, false); spin_lock_irqsave(&phy->buf_lock, f); phy->is_busy = false; phy->tx_buf = NULL; spin_unlock_irqrestore(&phy->buf_lock, f); return 0; } static int sx1278_ieee_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) { struct sx1278_phy *phy = hw->priv; int ret; unsigned long f; dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); WARN_ON(phy->suspended); spin_lock_irqsave(&phy->buf_lock, f); if (phy->tx_buf) { ret = -EBUSY; } else { phy->tx_buf = skb; phy->one_to_be_sent = true; phy->post_tx_done = false; ret = 0; } spin_unlock_irqrestore(&phy->buf_lock, f); return ret; } static int sx1278_ieee_start(struct ieee802154_hw *hw) { struct sx1278_phy *phy = hw->priv; dev_dbg(regmap_get_device(phy->map), "interface up\n"); sx1278_ieee_set_channel(hw, 0, hw->phy->current_channel); phy->suspended = false; sx127X_start_loramode(phy->map); phy->opmode = sx127X_get_mode(phy->map); add_timer(&phy->timer); return 0; } static void sx1278_ieee_stop(struct ieee802154_hw *hw) { struct sx1278_phy *phy = hw->priv; dev_dbg(regmap_get_device(phy->map), "interface down\n"); phy->suspended = true; del_timer(&phy->timer); sx127X_set_state(phy->map, SX127X_SLEEP_MODE); } static int sx1278_ieee_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) { return 0; } void sx1278_ieee_statemachine(struct ieee802154_hw *hw) { struct sx1278_phy *phy = hw->priv; u8 flags; u8 state; bool do_next_rx = false; unsigned long f; flags = sx127X_get_loraallflag(phy->map); state = sx127X_get_state(phy->map); if (flags & (SX127X_FLAG_RXTIMEOUT | SX127X_FLAG_PAYLOADCRCERROR)) { sx127X_clear_loraflag(phy->map, SX127X_FLAG_RXTIMEOUT | SX127X_FLAG_PAYLOADCRCERROR | SX127X_FLAG_RXDONE); spin_lock_irqsave(&phy->buf_lock, f); phy->is_busy = false; spin_unlock_irqrestore(&phy->buf_lock, f); do_next_rx = true; } else if (flags & SX127X_FLAG_RXDONE) { sx1278_ieee_rx_complete(phy->hw); sx127X_clear_loraflag(phy->map, SX127X_FLAG_RXDONE); do_next_rx = true; } if (flags & SX127X_FLAG_TXDONE) { sx1278_ieee_tx_complete(phy->hw); sx127X_clear_loraflag(phy->map, SX127X_FLAG_TXDONE); phy->tx_delay = 10; do_next_rx = true; } if (phy->one_to_be_sent && (state == SX127X_STANDBY_MODE) && (phy->tx_delay == 0)) { if (!sx1278_ieee_tx(phy->hw)) do_next_rx = false; } if (do_next_rx) sx1278_ieee_rx(phy->hw); if (phy->tx_delay > 0) phy->tx_delay -= 1; if (!phy->suspended) { phy->timer.expires = jiffies_64 + 1; add_timer(&phy->timer); } } static void sx1278_timer_irqwork(struct work_struct *work) { struct sx1278_phy *phy; phy = container_of(work, struct sx1278_phy, irqwork); sx1278_ieee_statemachine(phy->hw); } static void sx1278_timer_isr(struct timer_list *timer) { struct sx1278_phy *phy = container_of(timer, struct sx1278_phy, timer); schedule_work(&phy->irqwork); } u32 sx1278_ieee_channel_mask(struct ieee802154_hw *hw) { struct rf_frq rf; u32 mask; sx1278_ieee_get_rf_config(hw, &rf); mask = ((u32)(1 << (rf.ch_max + 1)) - (u32)(1 << rf.ch_min)); return mask; } static int sx1278_ieee_add_one(struct sx1278_phy *phy) { INIT_WORK(&phy->irqwork, sx1278_timer_irqwork); timer_setup(&phy->timer, sx1278_timer_isr, 0); phy->timer.expires = jiffies_64 + HZ; spin_lock_init(&phy->buf_lock); err = init_sx127x(phy->map); if (err) goto err_reg; return 0; err_reg: dev_err(regmap_get_device(phy->map), "register as IEEE 802.15.4 device failed\n"); return err; } static void sx1278_ieee_del(struct sx1278_phy *phy) { del_timer(&phy->timer); flush_work(&phy->irqwork); }*/ ///////////////////////// // Frontera Chino/Soto // // Frontera Chino/Soto // // Frontera Chino/Soto // ///////////////////////// struct sx127x { struct regmap *regmap; struct ieee802154_hw *ieee; struct spi_device *spi; spinlock_t lock; bool busy; struct sk_buff *tx_skb; size_t delayed_tx_length; struct timer_list poll_timer; struct work_struct poll_work; struct work_struct tx_work; u32 oscillator_freq; }; static int sx127x_reg_read(struct sx127x *hw, unsigned int address, u8 *data) { int ret = regmap_raw_read(hw->regmap, address, data, 1); if (ret < 0) dev_err(&hw->spi->dev, "regmap_raw_read(0x%x) failed: %d\n", address, ret); return ret; } static int sx127x_reg_write(struct sx127x *hw, unsigned int address, u8 data) { int ret = regmap_raw_write(hw->regmap, address, &data, 1); if (ret < 0) dev_err(&hw->spi->dev, "regmap_raw_write(0x%x) failed: %d\n", address, ret); return ret; } static int sx127x_mode(struct sx127x *hw, unsigned int mode) { return sx127x_reg_write(hw, SX127X_REG_OP_MODE, SX127X_LORA_MODE | mode); } static int sx127x_set_frequency(struct sx127x *hw, unsigned long frequency) { u8 msb_mid_lsb[3]; int i; u64 frf; frf = (((u64) frequency) << 19) / hw->oscillator_freq; for (i = sizeof msb_mid_lsb - 1; i >= 0; --i) { msb_mid_lsb[i] = (frf & 0xff); frf >>= 8; } return regmap_raw_write(hw->regmap, SX127X_REG_FRF_MSB, msb_mid_lsb, sizeof msb_mid_lsb); } static int sx127x_get_frequency(struct sx127x *hw, unsigned long *frequency) { u8 msb_mid_lsb[3]; int i, ret; u64 frt; ret = regmap_raw_read(hw->regmap, SX127X_REG_FRF_MSB, msb_mid_lsb, sizeof msb_mid_lsb); if (ret < 0) return ret; frt = 0; for (i = 0; i < sizeof msb_mid_lsb; ++i) frt = (frt << 8) | msb_mid_lsb[i]; *frequency = (frt * hw->oscillator_freq) >> 19; return 0; } static int sx127x_set_ocp(struct sx127x *hw, u8 current_ma) { u8 ocp_trim; /* P. 109 * * Trimming of OCP current: * Imax = 45+5*OcpTrim [mA] if OcpTrim <= 15 (120 mA) / * Imax = -30+10*OcpTrim [mA] if 15 < OcpTrim <= 27 (130 to * 240 mA) * Imax = 240mA for higher settings * Default Imax = 100mA */ if (current_ma <= 45) ocp_trim = 0; else if (current_ma <= 120) ocp_trim = (current_ma - 45) / 5; else if (current_ma <= 240) ocp_trim = (current_ma + 30) / 10; else ocp_trim = 28; return sx127x_reg_write(hw, SX127X_REG_OCP, SX127X_FLAG_OCPON | ocp_trim); } static int sx127x_set_tx_power(struct sx127x *hw, int level) { int ret; // PA BOOST if (level > 17) { if (level > 20) level = 20; // subtract 3 from level, so 18 - 20 maps to 15 - 17 level -= 3; // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) ret = sx127x_reg_write(hw, SX127X_REG_PA_DAC, 0x87); if (ret < 0) return ret; ret = sx127x_set_ocp(hw, 140); if (ret < 0) return ret; } else { if (level < 2) level = 2; // Default value PA_HF/LF or +17dBm ret = sx127x_reg_write(hw, SX127X_REG_PA_DAC, 0x84); if (ret < 0) return ret; ret = sx127x_set_ocp(hw, 100); if (ret < 0) return ret; } // PA_CONFIG #define PA_BOOST 0x80 return sx127x_reg_write(hw, SX127X_REG_PA_CONFIG, PA_BOOST | (level - 2)); } static int sx127x_init(struct sx127x *hw, u8 *major, u8 *minor) { u8 modem_config1, modem_config2, lna, version; int ret; ret = sx127x_reg_read(hw, SX127X_REG_VERSION, &version); if (ret < 0) return ret; if (version != 0x12) { dev_err(&hw->spi->dev, "%s: bad version 0x%02x\n", __func__, version); return -ENODEV; } *major = (version >> 4) & 0xf; *minor = (version >> 0) & 0xf; ret = sx127x_mode(hw, SX127X_SLEEP_MODE); if (ret < 0) { dev_err(&hw->spi->dev, "%s: sx127x_mode() failed: %d\n", __func__, ret); return ret; } ret = sx127x_reg_write(hw, SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDRESS); if (ret < 0) return ret; ret = sx127x_reg_write(hw, SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDRESS); if (ret < 0) return ret; ret = sx127x_reg_read(hw, SX127X_REG_LNA, &lna); if (ret < 0) return ret; lna |= 0x3; // ???, pero lo hace el sketch ret = sx127x_reg_write(hw, SX127X_REG_LNA, lna); if (ret < 0) return ret; ret = sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &modem_config1); if (ret < 0) return ret; ret = sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &modem_config2); if (ret < 0) return ret; modem_config1 &= ~SX127X_MODEM_CONFIG1_HEADER_MODE_MASK; modem_config1 |= SX127X_MODEM_CONFIG1_HEADER_MODE_EXPLICIT; modem_config2 |= SX127X_MODEM_CONFIG2_RXPAYLOADCRCON; ret = sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, modem_config1); if (ret < 0) return ret; ret = sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG2, modem_config2); if (ret < 0) return ret; ret = sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG3, SX127X_MODEM_CONFIG3_AGCAUTOON); if (ret < 0) return ret; return 0; } static void sx127x_tx_work(struct work_struct *work) { u8 mode; int ret = 0; bool set_busy = false; size_t i, size; const u8 *buffer; struct sx127x *hw = container_of(work, struct sx127x, tx_work); struct sk_buff *tx_skb; unsigned long spin_irq; spin_lock_irqsave(&hw->lock, spin_irq); tx_skb = hw->tx_skb; if (!hw->busy && !hw->delayed_tx_length) { hw->busy = true; set_busy = true; } spin_unlock_irqrestore(&hw->lock, spin_irq); if (!set_busy) { ret = -EBUSY; goto exit_busy; } else if (!tx_skb) { ret = -EINVAL; goto exit_busy; } size = tx_skb->len; buffer = tx_skb->data; if (!size || size > 128) { ret = -EINVAL; goto exit_busy; } ret = sx127x_reg_read(hw, SX127X_REG_OP_MODE, &mode); if (ret < 0) goto exit_busy; if ((mode & SX127X_MODE_MASK) == SX127X_TX_MODE) { ret = -EBUSY; goto exit_busy; } // reset FIFO address and payload length ret = sx127x_reg_write(hw, SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDRESS); if (ret < 0) goto exit_busy; ret = sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDRESS); if (ret < 0) goto exit_busy; // write data for (i = 0; i < size; i++) { ret = sx127x_reg_write(hw, SX127X_REG_FIFO, buffer[i]); if (ret < 0) goto exit_busy; } ret = sx127x_reg_write(hw, SX127X_REG_PAYLOAD_LENGTH, (u8) size); if (ret < 0) goto exit_busy; hw->delayed_tx_length = size; exit_busy: spin_lock_irqsave(&hw->lock, spin_irq); if (set_busy) hw->busy = false; if (ret && tx_skb) hw->tx_skb = NULL; spin_unlock_irqrestore(&hw->lock, spin_irq); if (ret && tx_skb) { #ifdef SX127X_LEGACY_KERNEL ieee802154_xmit_complete(hw->ieee, tx_skb, false); #else ieee802154_xmit_error(hw->ieee, tx_skb, ret); #endif } (void) ret; } static void sx127x_poll_work(struct work_struct *work) { u8 ack_flags, lqi, mode, read_flags, rx_base, *rx_data, rx_length; bool do_rx = false, was_busy = false; unsigned long spin_irq; struct sx127x *hw = container_of(work, struct sx127x, poll_work); struct sk_buff *rx_skb = NULL, *tx_skb = NULL; spin_lock_irqsave(&hw->lock, spin_irq); if (!hw->busy) hw->busy = true; else was_busy = true; tx_skb = hw->tx_skb; spin_unlock_irqrestore(&hw->lock, spin_irq); if (was_busy) return; if (sx127x_reg_read(hw, SX127X_REG_IRQ_FLAGS, &read_flags) < 0) goto exit_busy; ack_flags = 0; if (read_flags & SX127X_FLAG_TXDONE) ack_flags |= SX127X_FLAG_TXDONE; else tx_skb = NULL; if (read_flags & SX127X_FLAG_RXDONE) { do_rx = true; ack_flags |= SX127X_FLAG_RXDONE; if (read_flags & SX127X_FLAG_VALIDHEADER) ack_flags |= SX127X_FLAG_VALIDHEADER; else do_rx = false; if (read_flags & SX127X_FLAG_PAYLOADCRCERROR) { do_rx = false; ack_flags |= SX127X_FLAG_PAYLOADCRCERROR; } } if (do_rx) { if (sx127x_reg_read(hw, SX127X_REG_FIFO_RX_CURRENT_ADDR, &rx_base) < 0 || sx127x_reg_read(hw, SX127X_REG_RX_NB_BYTES, &rx_length) < 0) goto exit_busy; if (sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, rx_base) < 0) goto exit_busy; rx_skb = dev_alloc_skb(IEEE802154_MTU); if (!rx_skb) goto exit_busy; if (rx_length > IEEE802154_MTU) rx_length = IEEE802154_MTU; rx_data = skb_put(rx_skb, rx_length); while (rx_length--) if (sx127x_reg_read(hw, SX127X_REG_FIFO, rx_data++) < 0) goto exit_busy; if (sx127x_reg_write(hw, SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDRESS) < 0) goto exit_busy; } if (sx127x_reg_write(hw, SX127X_REG_IRQ_FLAGS, ack_flags) < 0) goto exit_busy; if (sx127x_reg_read(hw, SX127X_REG_OP_MODE, &mode) < 0) goto exit_busy; if ((mode & SX127X_MODE_MASK) != SX127X_TX_MODE) { if (hw->delayed_tx_length) { sx127x_mode(hw, SX127X_TX_MODE); hw->delayed_tx_length = 0; } else if ((mode & SX127X_MODE_MASK) != SX127X_RXCONTINUOUS_MODE) sx127x_mode(hw, SX127X_RXCONTINUOUS_MODE); } if (rx_skb) { lqi = 69; //TODO ieee802154_rx_irqsafe(hw->ieee, rx_skb, lqi); rx_skb = NULL; // rx_skb ownership transferred to the mac802154 layer } exit_busy: if (rx_skb) kfree_skb(rx_skb); if (tx_skb) ieee802154_xmit_complete(hw->ieee, tx_skb, false); spin_lock_irqsave(&hw->lock, spin_irq); hw->busy = false; if (tx_skb) hw->tx_skb = NULL; spin_unlock_irqrestore(&hw->lock, spin_irq); } static void sx127x_poll_timer(struct timer_list *timer) { struct sx127x *hw = container_of(timer, struct sx127x, poll_timer); schedule_work(&hw->poll_work); mod_timer(&hw->poll_timer, jiffies + POLL_JIFFIES); } static int sx127x_802154_xmit_async(struct ieee802154_hw *ieee, struct sk_buff *skb) { int ret = 0; struct sx127x *hw = ieee->priv; unsigned long spin_irq; spin_lock_irqsave(&hw->lock, spin_irq); if (!hw->tx_skb) hw->tx_skb = skb; else ret = -EBUSY; spin_unlock_irqrestore(&hw->lock, spin_irq); schedule_work(&hw->tx_work); return ret; } static int sx127x_802154_ed(struct ieee802154_hw *ieee, u8 *level) { struct sx127x *hw = ieee->priv; (void) hw; return -ENOSYS; } static int sx127x_802154_set_channel(struct ieee802154_hw *ieee, u8 page, u8 channel) { struct sx127x *hw = ieee->priv; (void) hw; return -ENOSYS; } static int sx127x_802154_set_txpower(struct ieee802154_hw *ieee, s32 mbm) { struct sx127x *hw = ieee->priv; (void) hw; return -ENOSYS; } static int sx127x_802154_start(struct ieee802154_hw *ieee) { int ret; struct sx127x *hw = ieee->priv; ret = sx127x_mode(hw, SX127X_STANDBY_MODE); if (ret < 0) { dev_err(&hw->spi->dev, "%s: sx127x_mode() failed: %d\n", __func__, ret); return ret; } mod_timer(&hw->poll_timer, jiffies + POLL_JIFFIES); dev_dbg(regmap_get_device(hw->regmap), "%s\n", __func__); return 0; } static void sx127x_802154_stop(struct ieee802154_hw *ieee) { struct sx127x *hw = ieee->priv; del_timer_sync(&hw->poll_timer); cancel_work_sync(&hw->poll_work); (void) sx127x_mode(hw, SX127X_SLEEP_MODE); dev_dbg(regmap_get_device(hw->regmap), "%s\n", __func__); } static int sx127x_802154_set_promiscuous_mode(struct ieee802154_hw *ieee, const bool on) { return 0; } static const struct ieee802154_ops sx127x_802154_ops = { .owner = THIS_MODULE, .xmit_async = sx127x_802154_xmit_async, .ed = sx127x_802154_ed, .set_channel = sx127x_802154_set_channel, .set_txpower = sx127x_802154_set_txpower, .start = sx127x_802154_start, .stop = sx127x_802154_stop, .set_promiscuous_mode = sx127x_802154_set_promiscuous_mode, }; static bool sx127x_reg_volatile(struct device *dev, unsigned int reg) { return true; } static const struct regmap_config sx127x_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = SX127X_MAX_REG, .read_flag_mask = 0x00, .write_flag_mask = 0x80, .volatile_reg = sx127x_reg_volatile, }; /* in mbm */ static const s32 sx127x_tx_powers[] = { -200, -100, 0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300}; static int sx127x_spi_probe(struct spi_device *spi) { u8 major, minor; int ret = 0; struct sx127x *hw; unsigned long frequency; struct ieee802154_hw *ieee; struct device_node *of_node; dev_dbg(&spi->dev, "%s hello\n", __func__); ieee = ieee802154_alloc_hw(sizeof *hw, &sx127x_802154_ops); if (!ieee) { dev_err(&spi->dev, "ieee802154_alloc_hw(): out of memory\n"); return -ENOMEM; } hw = ieee->priv; hw->spi = spi; hw->ieee = ieee; hw->busy = false; hw->delayed_tx_length = 0; spin_lock_init(&hw->lock); INIT_WORK(&hw->tx_work, sx127x_tx_work); INIT_WORK(&hw->poll_work, sx127x_poll_work); timer_setup(&hw->poll_timer, sx127x_poll_timer, 0); hw->regmap = devm_regmap_init_spi(spi, &sx127x_regmap_config); if (IS_ERR(hw->regmap)) { dev_err(&spi->dev, "%s: devm_regmap_init_spi() failed: %d\n", __func__, ret); return PTR_ERR(hw->regmap); } of_node = regmap_get_device(hw->regmap)->of_node; if (of_property_read_u32(of_node, "clock-frequency", &hw->oscillator_freq)) { dev_err(&spi->dev, "%s: 'clock-frequency' missing from DT node\n", __func__); return -EINVAL; } ieee->parent = &spi->dev; spi_set_drvdata(spi, hw); //TODO: pin de reset ieee802154_random_extended_addr(&ieee->phy->perm_extended_addr); ieee->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_RX_OMIT_CKSUM | IEEE802154_HW_PROMISCUOUS; ieee->phy->flags = WPAN_PHY_FLAG_TXPOWER; ieee->phy->transmit_power = sx127x_tx_powers[12]; ieee->phy->supported.tx_powers = sx127x_tx_powers; ieee->phy->supported.tx_powers_size = ARRAY_SIZE(sx127x_tx_powers); /* SX1278 phy channel 11 as default */ ieee->phy->current_channel = 11; /* Define channels could be used. */ ieee->phy->supported.channels[0] = 1 << 11; /*TODO: sx1278_ieee_channel_mask(hw);*/ ret = sx127x_init(hw, &major, &minor); if (ret < 0) { dev_err(&spi->dev, "%s: sx127x_init() failed: %d\n", __func__, ret); goto fail_init; } dev_info(&spi->dev, "IEEE 802.15.4 over LoRa SX127x compatible device v%u.%u\n", major, minor); // Valor viene del sketch ret = sx127x_set_frequency(hw, 434000000); if (ret < 0) { dev_err(&spi->dev, "%s: sx127x_set_frequency() failed: %d\n", __func__, ret); goto fail_init; } ret = sx127x_get_frequency(hw, &frequency); if (ret < 0) { dev_err(&spi->dev, "%s: sx127x_get_frequency() failed: %d\n", __func__, ret); goto fail_init; } dev_dbg(&spi->dev, "%s: frequency sanity test: %lu Hz\n", __func__, frequency); ret = sx127x_set_tx_power(hw, 17); // 17 dBm if (ret < 0) { dev_err(&spi->dev, "%s: sx127x_set_tx_power() failed: %d\n", __func__, ret); goto fail_init; } ret = ieee802154_register_hw(ieee); if (ret < 0) dev_err(&spi->dev, "ieee802154_register_hw() failed: %d\n", ret); return ret; fail_init: ieee802154_free_hw(ieee); return ret; } #ifdef SX127X_LEGACY_KERNEL static int sx127x_spi_remove(struct spi_device *spi) #else static void sx127x_spi_remove(struct spi_device *spi) #endif { struct sx127x *hw = spi_get_drvdata(spi); dev_dbg(&hw->spi->dev, "%s bye\n", __func__); ieee802154_unregister_hw(hw->ieee); ieee802154_free_hw(hw->ieee); #ifdef SX127X_LEGACY_KERNEL return 0; #endif } static const struct of_device_id sx127x_of_ids[] = { { .compatible = "semtech,sx1276" }, { .compatible = "semtech,sx1277" }, { .compatible = "semtech,sx1278" }, { .compatible = "semtech,sx1279" }, {}, }; MODULE_DEVICE_TABLE(of, sx127x_of_ids); static const struct spi_device_id sx127x_spi_ids[] = { { .name = "sx1276" }, { .name = "sx1277" }, { .name = "sx1278" }, { .name = "sx1279" }, {}, }; MODULE_DEVICE_TABLE(spi, sx127x_spi_ids); static struct spi_driver sx127x_spi_driver = { .driver = { .name = "sx127x", .owner = THIS_MODULE, .of_match_table = of_match_ptr(sx127x_of_ids), }, .probe = sx127x_spi_probe, .remove = sx127x_spi_remove, .id_table = sx127x_spi_ids, }; module_spi_driver(sx127x_spi_driver); MODULE_AUTHOR("Jian-Hong Pan, "); MODULE_AUTHOR("Fabian Montero "); MODULE_DESCRIPTION("Semtech SX127x LoRa PHY driver with IEEE 802.15.4 MAC interface"); MODULE_LICENSE("GPL");