lora_sx127/lora_sx127.c

1861 lines
42 KiB
C

/*-
* Copyright (c) 2017 Jian-Hong, Pan <starnight@g.ncu.edu.tw>
* Copyright (c) 2024 Fabian Montero <fabian@posixlycorrect.com>
*
* 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 <linux/module.h>
#include <linux/timer.h>
#include <linux/device.h>
#include <linux/acpi.h>
#include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <net/mac802154.h>
#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, <starnight@g.ncu.edu.tw>");
MODULE_AUTHOR("Fabian Montero <fabian@posixlycorrect.com>");
MODULE_DESCRIPTION("Semtech SX127x LoRa PHY driver with IEEE 802.15.4 MAC interface");
MODULE_LICENSE("GPL");