Hello Pan, >From my point of view, it is not a good idea to write sx127x driver for IEEE 802154. Because LoRa is not compatible with IEEE 802.15.4 in PHY and MAC layer. I think it is better to make individual Phy and MAC layers for LoRa in Linux kernel, where a sx127x driver will make sense. Regards, Xue Liu On 10 September 2017 at 11:30, Jian-Hong Pan <starnight@xxxxxxxxxxxx> wrote: > LoRa is an implementation of LPWPAN. > Chirp Spread Spectrum (CSS) modulation, which is used by LoRa has been > specified by IEEE 802.15.4a. > This driver implements IEEE 802.15.4 mac over LoRa physical layer not > LoRaWAN. > > Signed-off-by: Jian-Hong Pan <starnight@xxxxxxxxxxxx> > --- > .../devicetree/bindings/net/ieee802154/sx1278.txt | 30 + > drivers/net/ieee802154/Kconfig | 12 + > drivers/net/ieee802154/Makefile | 1 + > drivers/net/ieee802154/sx1278.c | 1636 ++++++++++++++++++++ > 4 files changed, 1679 insertions(+) > create mode 100644 Documentation/devicetree/bindings/net/ieee802154/sx1278.txt > create mode 100644 drivers/net/ieee802154/sx1278.c > > diff --git a/Documentation/devicetree/bindings/net/ieee802154/sx1278.txt b/Documentation/devicetree/bindings/net/ieee802154/sx1278.txt > new file mode 100644 > index 000000000000..78ca60feac30 > --- /dev/null > +++ b/Documentation/devicetree/bindings/net/ieee802154/sx1278.txt > @@ -0,0 +1,30 @@ > +* SX1278 IEEE 802.15.4 Compatible Radio * > + > +Required properties: > + - compatible: should be "semtech,sx1276", "semtech,sx1277", > + "semtech,sx1277" or "semtech,sx1279" depends on your > + transceiver board > + - spi-max-frequency: maximal bus speed, should be set something under or > + equal 10000000 Hz > + - reg: the chipselect index > + - clock-frequency: the external crystal oscillator frequency in Hz of the > + transceiver > +Optional properties: > + - center-carrier-frq: the RF center carrier frequency in Hz > + - rf-bandwidth: the RF bandwidth in Hz > + - minimal-RF-channel: the minimal RF channel number and the value must be with > + prefix "/bits/ 8" because of being a byte datatype > + - maximum-RF-channel: the maximum RF channel number and the value must be with > + prefix "/bits/ 8" because of being a byte datatype > + - spreading-factor: the spreading factor of Chirp Spread Spectrum modulation > + > +Example: > + > + sx1278@0 { > + compatible = "semtech,sx1278"; > + spi-max-frequency = <15200>; > + reg = <0>; > + clock-frequency = <32000000>; > + minimal-RF-channel = /bits/ 8 <11>; > + maximum-RF-channel = /bits/ 8 <11>; > + }; > diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig > index 303ba4133920..57ed64e55d13 100644 > --- a/drivers/net/ieee802154/Kconfig > +++ b/drivers/net/ieee802154/Kconfig > @@ -104,3 +104,15 @@ config IEEE802154_CA8210_DEBUGFS > exposes a debugfs node for each CA8210 instance which allows > direct use of the Cascoda API, exposing the 802.15.4 MAC > management entities. > + > +config IEEE802154_SX1278 > + tristate "Semtech SX1276/77/78/79 transceiver driver" > + depends on IEEE802154_DRIVERS && MAC802154 > + depends on SPI > + select REGMAP_SPI > + ---help--- > + Say Y here to enable the SX1278 SPI 802.15.4 wireless > + controller. > + > + This driver can also be built as a module. To do so, say M here. > + the module will be called 'sx1278'. > diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile > index 8374bb44a145..634e8e1bfad6 100644 > --- a/drivers/net/ieee802154/Makefile > +++ b/drivers/net/ieee802154/Makefile > @@ -5,3 +5,4 @@ obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o > obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o > obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o > obj-$(CONFIG_IEEE802154_CA8210) += ca8210.o > +obj-$(CONFIG_IEEE802154_SX1278) += sx1278.o > diff --git a/drivers/net/ieee802154/sx1278.c b/drivers/net/ieee802154/sx1278.c > new file mode 100644 > index 000000000000..2018407a0ab7 > --- /dev/null > +++ b/drivers/net/ieee802154/sx1278.c > @@ -0,0 +1,1636 @@ > +/*- > + * Copyright (c) 2017 Jian-Hong, Pan <starnight@xxxxxxxxxxxx> > + * > + * 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. > + * > + */ > + > +#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> > + > +/*------------------------------ LoRa Functions ------------------------------*/ > + > +#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_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 > + > +/* 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 > + > +/* SX127X's RX/TX FIFO base address */ > +#define SX127X_FIFO_RX_BASE_ADDRESS 0x00 > +#define SX127X_FIFO_TX_BASE_ADDRESS 0x80 > + > +struct sx1278_phy { > + struct ieee802154_hw *hw; > + struct regmap *map; > + > + bool suspended; > + u8 opmode; > + struct timer_list timer; > + struct work_struct irqwork; > + /* Lock the RX and TX actions. */ > + spinlock_t buf_lock; > + struct sk_buff *tx_buf; > + u8 tx_delay; > + bool one_to_be_sent; > + bool post_tx_done; > + bool is_busy; > +}; > + > +/** > + * sx127X_read_version - Get LoRa device's chip version > + * @map: the device as a regmap to communicate with > + * > + * Return: Positive / negtive values for version code / failed > + * Version code: bits 7-4 full version number, > + * bits 3-0 metal mask revision number > + */ > +int > +sx127X_read_version(struct regmap *map) > +{ > + u8 v; > + int status; > + > + status = regmap_raw_read(map, SX127X_REG_VERSION, &v, 1); > + > + if ((status == 0) && (v > 0) && (v < 0xFF)) > + status = v; > + else > + status = -ENODEV; > + > + return status; > +} > + > +/** > + * sx127X_get_mode - Get LoRa device's mode register > + * @map: the device as a regmap to communicate with > + * > + * Return: LoRa device's register value > + */ > +u8 > +sx127X_get_mode(struct regmap *map) > +{ > + u8 op_mode; > + > + /* Get original OP Mode register. */ > + regmap_raw_read(map, SX127X_REG_OP_MODE, &op_mode, 1); > + > + return op_mode; > +} > + > +/** > + * sx127X_set_state - Set LoRa device's operating state > + * @map: the device as a regmap to communicate with > + * @st: LoRa device's operating state going to be assigned > + */ > +void > +sx127X_set_state(struct regmap *map, u8 st) > +{ > + u8 op_mode; > + > + /* Get original OP Mode register. */ > + op_mode = sx127X_get_mode(map); > + /* Set device to designated state. */ > + op_mode = (op_mode & 0xF8) | (st & 0x07); > + regmap_raw_write(map, SX127X_REG_OP_MODE, &op_mode, 1); > +} > + > +/** > + * sx127X_get_state - Get LoRa device's operating state > + * @map: the device as a regmap to communicate with > + * > + * Return: LoRa device's operating state > + */ > +u8 > +sx127X_get_state(struct regmap *map) > +{ > + u8 op_mode; > + > + op_mode = sx127X_get_mode(map) & 0x07; > + > + return op_mode; > +} > + > +/** > + * sx127X_set_lorafrq - Set RF frequency > + * @map: the device as a regmap to communicate with > + * @fr: RF frequency going to be assigned in Hz > + */ > +void > +sx127X_set_lorafrq(struct regmap *map, u32 fr) > +{ > + u64 frt64; > + u32 frt; > + u8 buf[3]; > + u8 i; > + u32 f_xosc; > + > +#ifdef CONFIG_OF > + /* Set the LoRa module's crystal oscillator's clock if OF is defined. */ > + 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; > +#else > + f_xosc = xosc_frq; > +#endif > + > + frt64 = (uint64_t)fr * (uint64_t)__POW_2_19; > + do_div(frt64, f_xosc); > + frt = frt64; > + > + for (i = 2; i >= 0; i--) { > + buf[i] = frt % 256; > + frt = frt >> 8; > + } > + > + regmap_raw_write(map, SX127X_REG_FRF_MSB, buf, 3); > +} > + > +/** > + * sx127X_get_lorafrq - Get RF frequency > + * @map: the device as a regmap to communicate with > + * > + * Return: RF frequency in Hz > + */ > +u32 > +sx127X_get_lorafrq(struct regmap *map) > +{ > + u64 frt = 0; > + u8 buf[3]; > + u8 i; > + int status; > + u32 fr; > + u32 f_xosc; > + > +#ifdef CONFIG_OF > + /* Set the LoRa module's crystal oscillator's clock if OF is defined. */ > + 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; > +#else > + f_xosc = xosc_frq; > +#endif > + > + 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; > +} > + > +/** > + * sx127X_set_lorapower - Set RF output power > + * @map: the device as a regmap to communicate with > + * @pout: RF output power going to be assigned in dbm > + */ > +void > +sx127X_set_lorapower(struct regmap *map, s32 pout) > +{ > + u8 pacf; > + u8 boost; > + u8 output_power; > + s32 pmax; > + > + if (pout > 14) { > + /* Pout > 14dbm */ > + boost = 1; > + pmax = 7; > + output_power = pout - 2; > + } else if (pout < 0) { > + /* Pout < 0dbm */ > + boost = 0; > + pmax = 2; > + output_power = 3 + pout; > + } else { > + /* 0dbm <= Pout <= 14dbm */ > + boost = 0; > + pmax = 7; > + output_power = pout; > + } > + > + pacf = (boost << 7) | (pmax << 4) | (output_power); > + regmap_raw_write(map, SX127X_REG_PA_CONFIG, &pacf, 1); > +} > + > +/** > + * sx127X_get_lorapower - Get RF output power > + * @map: the device as a regmap to communicate with > + * > + * Return: RF output power in dbm > + */ > +s32 > +sx127X_get_lorapower(struct regmap *map) > +{ > + u8 pac; > + u8 boost; > + s32 output_power; > + s32 pmax; > + s32 pout; > + > + regmap_raw_read(map, SX127X_REG_PA_CONFIG, &pac, 1); > + boost = (pac & 0x80) >> 7; > + output_power = pac & 0x0F; > + if (boost) { > + pout = 2 + output_power; > + } else { > + /* Power max should be pmax/10. It is 10 times for now. */ > + pmax = (108 + 6 * ((pac & 0x70) >> 4)); > + pout = (pmax - (150 - output_power * 10)) / 10; > + } > + > + return pout; > +} > + > +/** > + * sx127X_dbm2mbm - dbm to mbm unit conversion > + * @dbm: the value in dbm > + * > + * Return: the value in mbm > + */ > +#define sx127X_dbm2mbm(dbm) (dbm * 100) > + > +/** > + * sx127X_mbm2dbm - mbm to dbm unit conversion > + * @mbm: the value in mbm > + * > + * Return: the value in dbm > + */ > +#define sx127X_mbm2dbm(mbm) (mbm / 100) > + > +s8 lna_gain[] = { > + 0, > + -6, > + -12, > + -24, > + -26, > + -48 > +}; > + > +/** > + * sx127X_set_loralna - Set RF LNA gain > + * @map: the device as a regmap to communicate with > + * @db: RF LNA gain going to be assigned in db > + */ > +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; > + > + regmap_raw_read(map, SX127X_REG_LNA, &lnacf, 1); > + lnacf = (lnacf & 0x1F) | (g << 5); > + regmap_raw_write(map, SX127X_REG_LNA, &lnacf, 1); > +} > + > +/** > + * sx127X_get_loralna - Get RF LNA gain > + * @map: the device as a regmap to communicate with > + * > + * Return: RF LNA gain db > + */ > +s32 > +sx127X_get_loralna(struct regmap *map) > +{ > + s32 db; > + s8 i, g; > + u8 lnacf; > + > + regmap_raw_read(map, SX127X_REG_LNA, &lnacf, 1); > + g = (lnacf >> 5); > + i = g - 1; > + db = lna_gain[i]; > + > + return db; > +} > + > +/** > + * sx127X_set_loralnaagc - Set RF LNA go with auto gain control or manual > + * @map: the device as a regmap to communicate with > + * @yesno: 1 / 0 for auto gain control / manual > + */ > +void > +sx127X_set_loralnaagc(struct regmap *map, s32 yesno) > +{ > + u8 mcf3; > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG3, &mcf3, 1); > + mcf3 = (yesno) ? (mcf3 | 0x04) : (mcf3 & (~0x04)); > + regmap_raw_write(map, SX127X_REG_MODEM_CONFIG3, &mcf3, 1); > +} > + > +/** > + * sx127X_get_loraallflag - Get all of the LoRa device IRQ flags' current state > + * @map: the device as a regmap to communicate with > + * > + * Return: All of the LoRa device's IRQ flags' current state in a byte > + */ > +u8 > +sx127X_get_loraallflag(struct regmap *map) > +{ > + u8 flags; > + > + regmap_raw_read(map, SX127X_REG_IRQ_FLAGS, &flags, 1); > + > + return flags; > +} > + > +/** > + * sx127X_get_loraallflag - Get interested LoRa device IRQ flag's current state > + * @map: the device as a regmap to communicate with > + * @f: the interested LoRa device's IRQ flag > + * > + * Return: The interested LoRa device's IRQ flag's current state in a byte > + */ > +#define sx127X_get_loraflag(map, f) (sx127X_get_loraallflag(map) & (f)) > + > +/** > + * sx127X_clear_loraflag - Clear designated LoRa device's IRQ flag > + * @map: the device as a regmap to communicate with > + * @f: flags going to be cleared > + */ > +void > +sx127X_clear_loraflag(struct regmap *map, u8 f) > +{ > + u8 flag; > + > + /* Get oiginal flag. */ > + flag = sx127X_get_loraallflag(map); > + /* Set the designated bits of the flag. */ > + flag |= f; > + regmap_raw_write(map, SX127X_REG_IRQ_FLAGS, &flag, 1); > +} > + > +/** > + * sx127X_clear_loraallflag - Clear designated LoRa device's all IRQ flags > + * @map: the device as a regmap to communicate with > + */ > +#define sx127X_clear_loraallflag(spi) sx127X_clear_loraflag(spi, 0xFF) > + > +/** > + * sx127X_set_lorasprf - Set the RF modulation's spreading factor > + * @map: the device as a regmap to communicate with > + * @c_s: Spreading factor in chips / symbol > + */ > +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; > + } > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1); > + mcf2 = (mcf2 & 0x0F) | (sf << 4); > + regmap_raw_write(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1); > +} > + > +/** > + * sx127X_get_lorasprf - Get the RF modulation's spreading factor > + * @map: the device as a regmap to communicate with > + * > + * Return: Spreading factor in chips / symbol > + */ > +u32 > +sx127X_get_lorasprf(struct regmap *map) > +{ > + u8 sf; > + u32 c_s; > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, &sf, 1); > + sf = sf >> 4; > + c_s = 1 << sf; > + > + return c_s; > +} > + > +const u32 hz[] = { > + 7800, > + 10400, > + 15600, > + 20800, > + 31250, > + 41700, > + 62500, > + 125000, > + 250000, > + 500000 > +}; > + > +/** > + * sx127X_set_lorabw - Set RF bandwidth > + * @map: the device as a regmap to communicate with > + * @bw: RF bandwidth going to be assigned in Hz > + */ > +void > +sx127X_set_lorabw(struct regmap *map, u32 bw) > +{ > + u8 i; > + u8 mcf1; > + > + for (i = 0; i < 9; i++) { > + if (hz[i] >= bw) > + break; > + } > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1); > + mcf1 = (mcf1 & 0x0F) | (i << 4); > + regmap_raw_write(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1); > +} > + > +/** > + * sx127X_get_lorabw - Get RF bandwidth > + * @map: the device as a regmap to communicate with > + * > + * Return: RF bandwidth in Hz > + */ > +u32 > +sx127X_get_lorabw(struct regmap *map) > +{ > + u8 mcf1; > + u8 bw; > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1); > + bw = mcf1 >> 4; > + > + return hz[bw]; > +} > + > +/** > + * sx127X_set_loracr - Set LoRa package's coding rate > + * @map: the device as a regmap to communicate with > + * @cr: Coding rate going to be assigned in a byte > + * high 4 bits / low 4 bits: numerator / denominator > + */ > +void > +sx127X_set_loracr(struct regmap *map, u8 cr) > +{ > + u8 mcf1; > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1); > + mcf1 = (mcf1 & 0x0E) | (((cr & 0xF) - 4) << 1); > + regmap_raw_write(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1); > +} > + > +/** > + * sx127X_get_loracr - Get LoRa package's coding rate > + * @map: the device as a regmap to communicate with > + * > + * Return: Coding rate in a byte > + * high 4 bits / low 4 bits: numerator / denominator > + */ > +u8 > +sx127X_get_loracr(struct regmap *map) > +{ > + u8 mcf1; > + u8 cr; /* ex: 0x45 represents cr=4/5 */ > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1); > + cr = 0x40 + ((mcf1 & 0x0E) >> 1) + 4; > + > + return cr; > +} > + > +/** > + * sx127X_set_loraimplicit - Set LoRa packages with Explicit / Implicit Header > + * @map: the device as a regmap to communicate with > + * @yesno: 1 / 0 for Implicit Header Mode / Explicit Header Mode > + */ > +void > +sx127X_set_loraimplicit(struct regmap *map, u8 yesno) > +{ > + u8 mcf1; > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1); > + mcf1 = (yesno) ? (mcf1 | 0x01) : (mcf1 & 0xFE); > + regmap_raw_write(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1); > +} > + > +/** > + * sx127X_set_lorarxbytetimeout - Set RX operation time-out in terms of symbols > + * @map: the device as a regmap to communicate with > + * @n: Time-out in terms of symbols (bytes) going to be assigned > + */ > +void > +sx127X_set_lorarxbytetimeout(struct regmap *map, u32 n) > +{ > + u8 buf[2]; > + u8 mcf2; > + > + if (n < 1) > + n = 1; > + if (n > 1023) > + n = 1023; > + > + /* Read original Modem config 2. */ > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1); > + > + /* LSB */ > + buf[1] = n % 256; > + /* MSB */ > + buf[0] = (mcf2 & 0xFC) | (n >> 8); > + > + regmap_raw_write(map, SX127X_REG_MODEM_CONFIG2, buf, 2); > +} > + > +/** > + * sx127X_set_lorarxtimeout - Set RX operation time-out seconds > + * @map: the device as a regmap to communicate with > + * @ms: The RX time-out time in ms > + */ > +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); > +} > + > +/** > + * sx127X_get_lorarxbytetimeout - Get RX operation time-out in terms of symbols > + * @map: the device as a regmap to communicate with > + * > + * Return: Time-out in terms of symbols (bytes) > + */ > +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; > +} > + > +/** > + * sx127X_get_lorarxtimeout - Get RX operation time-out seconds > + * @map: the device as a regmap to communicate with > + * > + * Return: The RX time-out time in ms > + */ > +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; > +} > + > +/** > + * sx127X_set_loramaxrxbuff - Maximum payload length in LoRa packet > + * @map: the device as a regmap to communicate with > + * @len: the max payload length going to be assigned in bytes > + */ > +void > +sx127X_set_loramaxrxbuff(struct regmap *map, u8 len) > +{ > + regmap_raw_write(map, SX127X_REG_MAX_PAYLOAD_LENGTH, &len, 1); > +} > + > +/** > + * sx127X_get_loralastpktpayloadlen - Get the RX last packet payload length > + * @map: the device as a regmap to communicate with > + * > + * Return: the actual RX last packet payload length in bytes > + */ > +u8 > +sx127X_get_loralastpktpayloadlen(struct regmap *map) > +{ > + u8 len; > + > + regmap_raw_read(map, SX127X_REG_RX_NB_BYTES, &len, 1); > + > + return len; > +} > + > +/** > + * sx127X_readloradata - Read data from LoRa device (read RX FIFO) > + * @map: the device as a regmap to communicate with > + * @buf: buffer going to be read data into > + * @len: the length of the data going to be read in bytes > + * > + * Return: Positive / negtive values for the actual data length read from > + * the LoRa device in bytes / failed > + */ > +ssize_t > +sx127X_readloradata(struct regmap *map, u8 *buf, size_t len) > +{ > + u8 start_adr; > + int ret; > + > + /* Set chip FIFO pointer to FIFO last packet address. */ > + start_adr = SX127X_FIFO_RX_BASE_ADDRESS; > + regmap_raw_write(map, SX127X_REG_FIFO_ADDR_PTR, &start_adr, 1); > + > + /* Read LoRa packet payload. */ > + len = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU; > + ret = regmap_raw_read(map, SX127X_REG_FIFO, buf, len); > + > + return (ret >= 0) ? len : ret; > +} > + > +/** > + * sx127X_sendloradata - Send data through LoRa device (write TX FIFO) > + * @rm: the device as a regmap to communicate with > + * @buf: buffer going to be send > + * @len: the length of the buffer in bytes > + * > + * Return: the actual length written into the LoRa device in bytes > + */ > +size_t > +sx127X_sendloradata(struct regmap *map, u8 *buf, size_t len) > +{ > + u8 base_adr; > + u8 blen; > + > + /* Set chip FIFO pointer to FIFO TX base. */ > + base_adr = SX127X_FIFO_TX_BASE_ADDRESS; > + regmap_raw_write(map, SX127X_REG_FIFO_ADDR_PTR, &base_adr, 1); > + > + /* Write payload synchronously to fill the FIFO of the chip. */ > + blen = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU; > + regmap_raw_write(map, SX127X_REG_FIFO, buf, blen); > + > + /* Set the FIFO payload length. */ > + regmap_raw_write(map, SX127X_REG_PAYLOAD_LENGTH, &blen, 1); > + > + return blen; > +} > + > +/** > + * sx127X_get_loralastpktsnr - Get last LoRa packet's SNR > + * @map: the device as a regmap to communicate with > + * > + * Return: the last LoRa packet's SNR in db > + */ > +s32 > +sx127X_get_loralastpktsnr(struct regmap *map) > +{ > + s32 db; > + s8 snr; > + > + regmap_raw_read(map, SX127X_REG_PKT_SNR_VALUE, &snr, 1); > + db = snr / 4; > + > + return db; > +} > + > +/** > + * sx127X_get_loralastpktrssi - Get last LoRa packet's SNR > + * @map: the device as a regmap to communicate with > + * > + * Return: the last LoRa packet's RSSI in dbm > + */ > +s32 > +sx127X_get_loralastpktrssi(struct regmap *map) > +{ > + s32 dbm; > + u8 lhf; > + u8 rssi; > + s8 snr; > + > + /* Get LoRa is in high or low frequency mode. */ > + lhf = sx127X_get_mode(map) & 0x08; > + /* Get RSSI value. */ > + regmap_raw_read(map, SX127X_REG_PKT_RSSI_VALUE, &rssi, 1); > + dbm = (lhf) ? -164 + rssi : -157 + rssi; > + > + /* Adjust to correct the last packet RSSI if SNR < 0. */ > + regmap_raw_read(map, SX127X_REG_PKT_SNR_VALUE, &snr, 1); > + if (snr < 0) > + dbm += snr / 4; > + > + return dbm; > +} > + > +/** > + * sx127X_get_lorarssi - Get current RSSI value > + * @map: the device as a regmap to communicate with > + * > + * Return: the current RSSI in dbm > + */ > +s32 > +sx127X_get_lorarssi(struct regmap *map) > +{ > + s32 dbm; > + u8 lhf; > + u8 rssi; > + > + /* Get LoRa is in high or low frequency mode. */ > + lhf = sx127X_get_mode(map) & 0x08; > + /* Get RSSI value. */ > + regmap_raw_read(map, SX127X_REG_RSSI_VALUE, &rssi, 1); > + dbm = (lhf) ? -164 + rssi : -157 + rssi; > + > + return dbm; > +} > + > +/** > + * sx127X_set_lorapreamblelen - Set LoRa preamble length > + * @map: the device as a regmap to communicate with > + * @len: the preamble length going to be assigned > + */ > +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); > +} > + > +/** > + * sx127X_get_lorapreamblelen - Get LoRa preamble length > + * @map: the device as a regmap to communicate with > + * > + * Return: length of the LoRa preamble > + */ > +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 - Enable CRC generation and check on received payload > + * @map: the device as a regmap to communicate with > + * @yesno: 1 / 0 for check / not check > + */ > +void > +sx127X_set_loracrc(struct regmap *map, u8 yesno) > +{ > + u8 mcf2; > + > + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1); > + mcf2 = (yesno) ? mcf2 | (1 << 2) : mcf2 & (~(1 << 2)); > + regmap_raw_write(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1); > +} > + > +/** > + * sx127X_set_boost - Set RF power amplifier boost in normal output range > + * @map: the device as a regmap to communicate with > + * @yesno: 1 / 0 for boost / not boost > + */ > +void > +sx127X_set_boost(struct regmap *map, u8 yesno) > +{ > + u8 pacf; > + > + regmap_raw_read(map, SX127X_REG_PA_CONFIG, &pacf, 1); > + pacf = (yesno) ? pacf | (1 << 7) : pacf & (~(1 << 7)); > + regmap_raw_write(map, SX127X_REG_PA_CONFIG, &pacf, 1); > +} > + > +/** > + * sx127X_start_loramode - Start the device and set it in LoRa mode > + * @map: the device as a regmap to communicate with > + */ > +void > +sx127X_start_loramode(struct regmap *map) > +{ > + u8 op_mode; > + u8 base_adr; > +#ifdef CONFIG_OF > + struct device_node *of_node = (regmap_get_device(map))->of_node; > +#endif > + > + /* Get original OP Mode register. */ > + op_mode = sx127X_get_mode(map); > + dev_dbg(regmap_get_device(map), > + "the original OP mode is 0x%X\n", op_mode); > + > + /* Set device to sleep state. */ > + sx127X_set_state(map, SX127X_SLEEP_MODE); > + /* Set device to LoRa mode. */ > + op_mode = sx127X_get_mode(map); > + op_mode = op_mode | 0x80; > + regmap_raw_write(map, SX127X_REG_OP_MODE, &op_mode, 1); > + /* Set device to standby state. */ > + 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); > + > + /* Set LoRa in explicit header mode. */ > + sx127X_set_loraimplicit(map, 0); > + > + /* Set chip FIFO RX base. */ > + base_adr = SX127X_FIFO_RX_BASE_ADDRESS; > + regmap_raw_write(map, SX127X_REG_FIFO_RX_BASE_ADDR, &base_adr, 1); > + /* Set chip FIFO TX base. */ > + base_adr = SX127X_FIFO_TX_BASE_ADDRESS; > + regmap_raw_write(map, SX127X_REG_FIFO_TX_BASE_ADDR, &base_adr, 1); > + > + /* Set the CSS spreading factor. */ > +#ifdef CONFIG_OF > + of_property_read_u32(of_node, "spreading-factor", &sprf); > +#endif > + sx127X_set_lorasprf(map, sprf); > + > + /* Set RX time-out value. */ > + sx127X_set_lorarxbytetimeout(map, rx_timeout); > + > + /* Clear all of the IRQ flags. */ > + sx127X_clear_loraallflag(map); > + /* Set chip to RX state waiting for receiving. */ > + sx127X_set_state(map, SX127X_RXSINGLE_MODE); > +} > + > +/** > + * init_sx127x - Initial the SX127X device > + * @map: the device as a regmap to communicate with > + * > + * Return: 0 / negtive values for success / failed > + */ > +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; > + } > +} > + > +/*---------------------- SX1278 IEEE 802.15.4 Functions ----------------------*/ > + > +/* LoRa device's sensitivity in dbm. */ > +#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__); > + > + /* ED: IEEE 802.15.4-2011 8.2.5 Recevier ED. */ > + 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) > +{ > +#ifdef CONFIG_OF > + struct sx1278_phy *phy = hw->priv; > + struct device_node *of_node = (regmap_get_device(phy->map))->of_node; > + > + /* Set the LoRa chip's center carrier frequency. */ > + if (of_property_read_u32(of_node, "center-carrier-frq", &rf->carrier)) > + rf->carrier = carrier_frq; > + > + /* Set the LoRa chip's RF bandwidth. */ > + if (of_property_read_u32(of_node, "rf-bandwidth", &rf->carrier)) > + rf->bw = bandwidth; > + > + /* Set the LoRa chip's min & max RF channel if OF is defined. */ > + 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; > +#else > + rf->carrier = carrier_frq; > + rf->bw = bandwidth; > + rf->ch_min = channel_min; > + rf->ch_max = channel_max; > +#endif > +} > + > +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", __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); > + > + return 0; > +} > + > +/* in mbm */ > +s32 sx1278_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 > +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", __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; > + > + dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); > + > + spin_lock(&phy->buf_lock); > + if (!phy->is_busy) { > + phy->is_busy = true; > + do_rx = true; > + } else { > + do_rx = false; > + } > + spin_unlock(&phy->buf_lock); > + > + if (do_rx) { > + sx127X_set_state(phy->map, SX127X_RXSINGLE_MODE); > + return 0; > + } else { > + 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; > + > + skb = dev_alloc_skb(IEEE802154_MTU); > + if (!skb) { > + err = -ENOMEM; > + goto sx1278_ieee_rx_err; > + } > + > + len = sx127X_get_loralastpktpayloadlen(phy->map); > + sx127X_readloradata(phy->map, skb_put(skb, len), len); > + > + /* LQI: IEEE 802.15.4-2011 8.2.6 Link quality indicator. */ > + rssi = sx127X_get_loralastpktrssi(phy->map); > + rssi = (rssi > 0) ? 0 : rssi; > + lqi = ((s32)255 * (rssi + range) / range) % 255; > + > + ieee802154_rx_irqsafe(hw, skb, lqi); > + > + spin_lock(&phy->buf_lock); > + phy->is_busy = false; > + spin_unlock(&phy->buf_lock); > + > + dev_dbg(regmap_get_device(phy->map), > + "%s: len=%u LQI=%u\n", __func__, len, lqi); > + > + return 0; > + > +sx1278_ieee_rx_err: > + 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; > + > + 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(&phy->buf_lock); > + if (!phy->is_busy) { > + phy->is_busy = true; > + do_tx = true; > + phy->one_to_be_sent = false; > + } > + spin_unlock(&phy->buf_lock); > + > + if (do_tx) { > + /* Set chip as TX state and transfer the data in FIFO. */ > + phy->opmode = (phy->opmode & 0xF8) | SX127X_TX_MODE; > + regmap_write_async(phy->map, SX127X_REG_OP_MODE, phy->opmode); > + return 0; > + } else { > + 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; > + > + dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); > + > + ieee802154_xmit_complete(hw, skb, false); > + > + spin_lock(&phy->buf_lock); > + phy->is_busy = false; > + phy->tx_buf = NULL; > + spin_unlock(&phy->buf_lock); > + > + return 0; > +} > + > +static int > +sx1278_ieee_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) > +{ > + struct sx1278_phy *phy = hw->priv; > + int ret; > + > + dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); > + > + WARN_ON(phy->suspended); > + > + spin_lock(&phy->buf_lock); > + 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(&phy->buf_lock); > + > + 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"); > + > + 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; > + > + 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(&phy->buf_lock); > + phy->is_busy = false; > + spin_unlock(&phy->buf_lock); > + 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); > + } > +} > + > +/** > + * sx1278_timer_irqwork - The actual work which checks the IRQ flags of the chip > + * @work: the work entry listed in the workqueue > + */ > +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); > +} > + > +/** > + * sx1278_timer_isr - Callback function for the timer interrupt > + * @arg: the general argument for this callback function > + */ > +static void > +sx1278_timer_isr(unsigned long arg) > +{ > + struct sx1278_phy *phy = (struct sx1278_phy *)arg; > + > + schedule_work(&phy->irqwork); > +} > + > +static const struct ieee802154_ops sx1278_ops = { > + .owner = THIS_MODULE, > + .xmit_async = sx1278_ieee_xmit, > + .ed = sx1278_ieee_ed, > + .set_channel = sx1278_ieee_set_channel, > + .set_txpower = sx1278_ieee_set_txpower, > + .start = sx1278_ieee_start, > + .stop = sx1278_ieee_stop, > + .set_promiscuous_mode = sx1278_ieee_set_promiscuous_mode, > +}; > + > +/** > + * sx1278X_ieee_channel_mask - Get the available channels' mask of LoRa device > + * @hw: LoRa IEEE 802.15.4 device > + * > + * Return: The bitwise channel mask in 4 bytes > + */ > +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) > +{ > + struct ieee802154_hw *hw = phy->hw; > + int err; > + > + /* Define channels could be used. */ > + hw->phy->supported.channels[0] = sx1278_ieee_channel_mask(hw); > + /* SX1278 phy channel 11 as default */ > + hw->phy->current_channel = 11; > + > + /* Define RF power. */ > + hw->phy->supported.tx_powers = sx1278_powers; > + hw->phy->supported.tx_powers_size = ARRAY_SIZE(sx1278_powers); > + hw->phy->transmit_power = sx1278_powers[12]; > + > + ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); > + hw->flags = IEEE802154_HW_TX_OMIT_CKSUM > + | IEEE802154_HW_RX_OMIT_CKSUM > + | IEEE802154_HW_PROMISCUOUS; > + > + err = ieee802154_register_hw(hw); > + if (err) > + goto err_reg; > + > + INIT_WORK(&phy->irqwork, sx1278_timer_irqwork); > + > + init_timer(&phy->timer); > + phy->timer.expires = jiffies_64 + HZ; > + phy->timer.function = sx1278_timer_isr; > + phy->timer.data = (unsigned long)phy; > + > + 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) > +{ > + if (!phy) > + return; > + > + del_timer(&phy->timer); > + flush_work(&phy->irqwork); > + > + ieee802154_unregister_hw(phy->hw); > + ieee802154_free_hw(phy->hw); > +} > + > +/*--------------------------- SX1278 SPI Functions ---------------------------*/ > + > +/* The compatible chip array. */ > +#ifdef CONFIG_OF > +static const struct of_device_id sx1278_dt_ids[] = { > + { .compatible = "semtech,sx1276" }, > + { .compatible = "semtech,sx1277" }, > + { .compatible = "semtech,sx1278" }, > + { .compatible = "semtech,sx1279" }, > + { .compatible = "sx1278" }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, sx1278_dt_ids); > +#endif > + > +/* The compatible ACPI device array. */ > +#ifdef CONFIG_ACPI > +static const struct acpi_device_id sx1278_acpi_ids[] = { > + { .id = "sx1278" }, > + {}, > +}; > +MODULE_DEVICE_TABLE(acpi, sx1278_acpi_ids); > +#endif > + > +/* The compatible SPI device id array. */ > +static const struct spi_device_id sx1278_spi_ids[] = { > + { .name = "sx1278" }, > + {}, > +}; > +MODULE_DEVICE_TABLE(spi, sx1278_spi_ids); > + > +bool sx1278_reg_volatile(struct device *dev, unsigned int reg) > +{ > + return true; > +} > + > +/* The SX1278 regmap config. */ > +struct regmap_config sx1278_regmap_config = { > + .reg_bits = 8, > + .val_bits = 8, > + .max_register = SX127X_MAX_REG, > + .read_flag_mask = 0x00, > + .write_flag_mask = 0x80, > + .volatile_reg = sx1278_reg_volatile, > +}; > + > +/* The SPI probe callback function. */ > +static int sx1278_spi_probe(struct spi_device *spi) > +{ > + struct ieee802154_hw *hw; > + struct sx1278_phy *phy; > + int err; > + > + hw = ieee802154_alloc_hw(sizeof(*phy), &sx1278_ops); > + if (!hw) { > + dev_err(&spi->dev, "not enough memory\n"); > + return -ENOMEM; > + } > + > + phy = hw->priv; > + phy->hw = hw; > + hw->parent = &spi->dev; > + phy->map = devm_regmap_init_spi(spi, &sx1278_regmap_config); > + > + /* Set the SPI device's driver data for later usage. */ > + spi_set_drvdata(spi, phy); > + > + err = sx1278_ieee_add_one(phy); > + if (err < 0) { > + dev_err(&spi->dev, "no SX1278 compatible device\n"); > + goto sx1278_spi_probe_err; > + } > + > + dev_info(&spi->dev, > + "add an IEEE 802.15.4 over LoRa SX1278 compatible device\n"); > + > + return 0; > + > +sx1278_spi_probe_err: > + sx1278_ieee_del(phy); > + return err; > +} > + > +/* The SPI remove callback function. */ > +static int sx1278_spi_remove(struct spi_device *spi) > +{ > + struct sx1278_phy *phy = spi_get_drvdata(spi); > + > + sx1278_ieee_del(phy); > + > + return 0; > +} > + > +#define __DRIVER_NAME "sx1278" > + > +/* The SPI driver which acts as a protocol driver in this kernel module. */ > +static struct spi_driver sx1278_spi_driver = { > + .driver = { > + .name = __DRIVER_NAME, > + .owner = THIS_MODULE, > +#ifdef CONFIG_OF > + .of_match_table = of_match_ptr(sx1278_dt_ids), > +#endif > +#ifdef CONFIG_ACPI > + .acpi_match_table = ACPI_PTR(sx1278_acpi_ids), > +#endif > + }, > + .probe = sx1278_spi_probe, > + .remove = sx1278_spi_remove, > + .id_table = sx1278_spi_ids, > +}; > + > +/* Register SX1278 kernel module. */ > +module_spi_driver(sx1278_spi_driver); > + > +MODULE_AUTHOR("Jian-Hong Pan, <starnight@xxxxxxxxxxxx>"); > +MODULE_DESCRIPTION("LoRa device SX1278 driver with IEEE 802.15.4 interface"); > +MODULE_LICENSE("Dual BSD/GPL"); > -- > 2.14.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-wpan" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-wpan" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html