/*- * 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 SX127X_LEGACY_KERNEL #define DEBUG #include #include #include #include #include #include #include #include #include static unsigned tx_poll_div = 10; module_param(tx_poll_div, uint, 0000); MODULE_PARM_DESC(tx_poll_div, "Number of RX poll cycles to perform before attempting a single TX op"); /* 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 /* 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)) 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; unsigned tx_wait; 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, 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; modem_config1 &= ~SX127X_MODEM_CONFIG1_HEADER_MODE_MASK; modem_config1 |= SX127X_MODEM_CONFIG1_HEADER_MODE_EXPLICIT; ret = sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, modem_config1); if (ret < 0) return ret; ret = sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG3, 0x4); 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 = 0; 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; if (rx_length <= IEEE802154_MTU) { rx_skb = dev_alloc_skb(IEEE802154_MTU); if (!rx_skb) goto exit_busy; 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; } else dev_err(&hw->spi->dev, "%s: rx_length overflow: %u > IEEE802154_MTU\n", __func__, rx_length); 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->tx_wait >= tx_poll_div) hw->tx_wait = 0; if (hw->delayed_tx_length && hw->tx_wait == 0) { 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); spin_lock_irqsave(&hw->lock, spin_irq); hw->busy = false; if (tx_skb) hw->tx_skb = NULL; spin_unlock_irqrestore(&hw->lock, spin_irq); if (tx_skb) ieee802154_xmit_complete(hw->ieee, tx_skb, false); } 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); if (!ret) 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); 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); } 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->tx_wait = 0; 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; /*u8 buffer[] = { 0x36, 0x39 }; // 69? ret = sx127x_mode(hw, SX127X_STANDBY_MODE); if (ret < 0) { dev_err(&spi->dev, "%s: sx127x_mode() failed: %d\n", __func__, ret); goto fail_begin; } ret = sx127x_begin_packet(hw); if (ret < 0) { dev_err(&spi->dev, "%s: sx127x_begin_packet() failed: %d\n", __func__, ret); goto fail_begin; } ret = sx127x_write_buffer(hw, buffer, sizeof buffer); if (ret < 0) { dev_err(&spi->dev, "%s: sx127x_send() failed: %d\n", __func__, ret); goto fail_begin; } ret = sx127x_end_packet(hw, 0); if (ret < 0) { dev_err(&spi->dev, "%s: sx127x_end_packet() failed: %d\n", __func__, ret); goto fail_begin; }*/ 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");