All of lore.kernel.org
 help / color / mirror / Atom feed
* Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-11 16:02 Marcus Wolf
  2017-07-12  7:43 ` Greg KH
  0 siblings, 1 reply; 49+ messages in thread
From: Marcus Wolf @ 2017-07-11 16:02 UTC (permalink / raw)
  To: gregkh, grant.likely, robh+dt, linux-kernel, devel, devicetree

[-- Attachment #1: Type: text/plain, Size: 169508 bytes --]

Hi folks,

I developed a radio shield for the 433MHz ISM band [0
https://en.wikipedia.org/wiki/ISM_band ] for the Raspberry Pi.
This shield is called Pi433 [1 https://www.pi433.de/en.html ]. It can be used to
communicate between two
Raspberries or to control third party equipment e. g. cheap radio sockets [2
http://www.pollin.de/shop/dt/MzMzOTQ0OTk-/Haustechnik_Sicherheitstechnik/Hausautomation/Funksteckdosen/Funksteckdosen_Set_mit_3_Steckdosen.html
].
The base of this radio shield is a radio module from HopeRf - a rfm69cw-433s2.
 
In the beginning, I conrolled the rf69 chip by direct access via SPI, but I
figured out, that several tasks were hard to handle. Especially the following
points were annoying:
* Just one process could open the SPI interface so just one process was
  able to access the module
* A simultaneous send and receive was very hard to implement

Therefore I started to implement a driver.
The drivers features:
* simple access/nice abstraction of spi registers via open, close,
  read, write and ioctl
* multiple applications can open
* tx requests are queued, so every app can send a tx request at any time
* first app asking for rx will block other apps, also asking for rx until one rx
  cycle is complete
* rx cycle means listening on the air until something appears
* if an app wants to tx during the driver is waiting in rx cycle, rx will be
  shortly interrupted to do the tx task
* for each tx task a seperate configuration of the rf chip (bitrate, modulation,
...)
  can be chosen
* wrtten in modular architecture, allowing to extend for other products with
  rf69 chip (e.g. rfm69hcw, ...) or even to support other HopeRf chips with
similar
  interface (e. g. rfm12, rfm95, ...)
 
In principle the driver was intended to be used by my project (Smarthome-Pi),
only.
But while having all this nice features, I was asked, whether I could offer the
driver to the community. I never did that before, so I started reading about
submitting drivers and figured out, that there is a lot of work to do, to meet
all
concepts and ideas of complying to kernel code. I spend some days and modified
a lot, but still, a lot of things aren't perfect.
Already known tasks are:

* coding style does not fully comply with the kernel style guide.
* still TODOs, annotated in the code
* currently the code introduces new IOCTLs. I'm afraid this is a bad idea.
  Replace this with another interface, hints are welcome!
 
I tested the patch on Raspbian with Kernel v4.12 and applied the patch on
mainline Linux v4.12
 
Is it posibble to integrate into the staging area to ease further development?

I'm looking forward for your feedback,

Marcus
 
[0] https://en.wikipedia.org/wiki/ISM_band
[1] https://www.pi433.de/en.html
[2]
http://www.pollin.de/shop/dt/MzMzOTQ0OTk-/Haustechnik_Sicherheitstechnik/Hausautomation/Funksteckdosen/Funksteckdosen_Set_mit_3_Steckdosen.html
 

--------8<------------------------------
 
>From 4d7cb74a578d7f8265163edf83573fc82c605bd5 Mon Sep 17 00:00:00 2001
From: Marcus Wolf <linux@wolf-entwicklungen.de>
Date: Mon, 10 Jul 2017 19:35:13 +0100
Subject: [PATCH] adde documentation for driver for the Pi433 radio module


Signed-off-by: Marcus Wolf <linux@wolf-entwicklungen.de>
---
 .../bindings/staging/pi433/pi433-overlay.dts       |   53 ++++
 .../devicetree/bindings/staging/pi433/pi433.txt    |   62 +++++
 Documentation/pi433.txt                            |  274 ++++++++++++++++++++
 3 files changed, 389 insertions(+)
 create mode 100644
Documentation/devicetree/bindings/staging/pi433/pi433-overlay.dts
 create mode 100644 Documentation/devicetree/bindings/staging/pi433/pi433.txt
 create mode 100644 Documentation/pi433.txt

diff --git a/Documentation/devicetree/bindings/staging/pi433/pi433-overlay.dts
b/Documentation/devicetree/bindings/staging/pi433/pi433-overlay.dts
new file mode 100644
index 0000000..004b502
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/pi433/pi433-overlay.dts
@@ -0,0 +1,53 @@
+// Definitions for Pi433
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+    fragment@1 {
+        target = <&gpio>;
+        __overlay__ {
+            pi433_pins: pi433_pins {
+                brcm,pins = <7 25 24>;
+                brcm,function = <0 0 0>; // in in in
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&spi0>;
+        __overlay__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            status = "okay";
+
+            pi433: pi433@0 {
+                compatible = "Smarthome-Wolf,pi433";
+                reg = <0>;
+                spi-max-frequency = <10000000>;
+                status = "okay";
+
+                pinctrl-0 = <&pi433_pins>;
+                DIO0-gpio = <&gpio 24 0>;
+                DIO1-gpio = <&gpio 25 0>;
+                DIO2-gpio = <&gpio  7 0>;
+            };
+        };
+    };
+};
diff --git a/Documentation/devicetree/bindings/staging/pi433/pi433.txt
b/Documentation/devicetree/bindings/staging/pi433/pi433.txt
new file mode 100644
index 0000000..14197c6
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/pi433/pi433.txt
@@ -0,0 +1,62 @@
+* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see
www.pi433.de)
+
+Required properties:
+- compatible: must be "Smarthome-Wolf,pi433"
+- reg: chip select of SPI Interface
+- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69
module
+
+
+Example:
+
+With the following lines in gpio-section, the gpio pins, connected with pi433
are
+reserved/declared.
+
+&gpio{
+    [...]
+
+    pi433_pins: pi433_pins {
+        brcm,pins = <7 25 24>;
+        brcm,function = <0 0 0>; // in in in
+    };
+
+    [...]
+}
+
+With the following lines in spi section, the device pi433 is declared.
+It consists of the three gpio pins and an spi interface (here chip select 0)
+
+&spi0{
+    [...]
+
+    pi433: pi433@0 {
+        compatible = "Smarthome-Wolf,pi433";
+        reg = <0>; /* CE 0 */
+        #address-cells = <1>;
+        #size-cells = <0>;
+        spi-max-frequency = <10000000>;
+
+        pinctrl-0 = <&pi433_pins>;
+        DIO0-gpio = <&gpio 24 0>;
+        DIO1-gpio = <&gpio 25 0>;
+        DIO2-gpio = <&gpio  7 0>;
+    };
+}
+
+
+
+For Raspbian users only
+=======================
+Since Raspbian supports device tree overlays, you may use and overlay, instead
+of editing your boards device tree.
+For using the overlay, you need to compile the file pi433-overlay.dts you can
+find aside to this documentation.
+The file needs to be compiled - either manually or by integration in your
kernel
+source tree. For a manual compile, you may use a command line like the
following:
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+arch/arm/boot/dts/overlays and you need to add the file to the list of files
+in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
+kernel make files compile the device tree overlay for you.
+
+
diff --git a/Documentation/pi433.txt b/Documentation/pi433.txt
new file mode 100644
index 0000000..860dd0f
--- /dev/null
+++ b/Documentation/pi433.txt
@@ -0,0 +1,274 @@
+=====
+Pi433
+=====
+
+
+Introduction
+============
+This driver is for controlling pi433, a radio module for the Raspberry Pi
+(www.pi433.de). It supports transmission and reception. It can be opened
+by multiple applications for transmission and reception. While transmit
+jobs were queued and process automatically in the background, the first  
+application asking for reception will block out all other applications  
+until something gets received terminates the read request.  
+The driver supports on the fly reloading of the hardware fifo of the rf
+chip, thus enabling for much longer telegrams then hardware fifo size.
+
+Discription of driver operation
+===============================
+
+a) transmission
+
+Each transmission can take place with a different configuration of the rf
+module. Therfore each application can set its own set of parameters. The driver
+takes care, that each transmission takes place with the parameterset of the
+application, that requests the transmission. To allow the transmission to take
+place in the background, a tx thread is introduced.
+The transfer of data from the main thread to the tx thread is realised by a
+kfifo. With each write request of an application, the passed in data and the
+corresponding parameter set gets written to the kfifo.  
+On the other "side" of the kfifo, the tx thread continuously checks, whether
the
+kfifo is empty. If not, it gets one set of config and data from the kfifo. If  
+there is no receive request or the receiver is still waiting for something in
+the air, the rf module is set to standby, the parameters for transmission gets
+set, the hardware fifo of the rf chip gets preloaded and the transmission gets
+started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling
+much longer telegrams then hardware fifo size. If the telegram is send and
there
+is more data available in the kfifo, the procedure is repeated. If not the
+transmission cycle ends.
+
+b) reception
+
+Since there is only one application allowed to receive data at a time, for
+reception there is only one configuration set.
+As soon as an application sets an request for receiving a telegram, the
reception
+configuration set is written to the rf module and it gets set into receiving
mode.  
+Now the driver is waiting, that a predefined RSSI level (signal strength at the
+receiver) is reached. Until this hasn't happened, the reception can be
+interrupted by the transmission thread at any time to insert a transmission
cycle.
+As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar
+as described for the transmission cycle the read out of the hardware fifo is
done
+dynamically. Upon each hardware fifo threshold interrupt, a portion of data
gets
+read. So also for reception it is possible to receive more data then the
hardware
+fifo can hold.
+
+
+Driver API
+==========
+
+The driver is currently implemented as a character device. Therefore it
supports
+the calls open, ioctl, read, write and close.
+
+
+params for ioctl
+----------------
+
+There are four options:  
+PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver
+PI433_IOC_WR_TX_CFG - set the transmission parameters
+PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver
+PI433_IOC_WR_RX_CFG - set the receiving parameters  
+
+The tx configuration is transfered via struct pi433_tx_cfg, the parameterset
for transmission.  
+It is devided into two sections: rf parameters and packet format.
+
+rf params:
+    frequency
+        frequency used for transmission.  
+        Allowed values: 433050000...434790000
+    bit_rate
+        bit rate used for transmission.  
+        Allowed values: #####
+    dev_frequency
+        frequency deviation in case of FSK.  
+        Allowed values: 600...500000
+    modulation
+        FSK - frequency shift key
+        OOK - On-Off-key
+    modShaping
+        shapingOff    - no shaping
+        shaping1_0    - gauss filter with BT 1 (FSK only)
+        shaping0_5    - gauss filter with BT 0.5 (FSK only)
+        shaping0_3    - gauss filter with BT 0.3 (FSK only)
+        shapingBR    - filter cut off at BR (OOK only)
+        shaping2BR    - filter cut off at 2*BR (OOK only)
+    paRamp (FSK only)
+        ramp3400    - amp ramps up in 3.4ms
+        ramp2000    - amp ramps up in 2.0ms
+        ramp1000    - amp ramps up in 1ms
+        ramp500        - amp ramps up in 500us
+        ramp250        - amp ramps up in 250us
+        ramp125        - amp ramps up in 125us
+        ramp100        - amp ramps up in 100us
+        ramp62        - amp ramps up in 62us
+        ramp50        - amp ramps up in 50us
+        ramp40        - amp ramps up in 40us
+        ramp31        - amp ramps up in 31us
+        ramp25        - amp ramps up in 25us
+        ramp20        - amp ramps up in 20us
+        ramp15        - amp ramps up in 15us
+        ramp12        - amp ramps up in 12us
+        ramp10        - amp ramps up in 10us
+    tx_start_condition
+        fifoLevel    - transmission starts, if fifo is filled to
+                  threshold level
+        fifoNotEmpty    - transmission starts, as soon as there is one
+                  byte in internal fifo
+    repetitions
+        This gives the option, to send a telegram multiple times. Default: 1
+
+packet format:
+    enable_preamble
+        optionOn    - a preamble will be automatically generated
+        optionOff    - no preamble will be generated
+    enable_sync
+        optionOn    - a sync word will be automatically added to
+                  the telegram after preamble
+        optionOff    - no sync word will be added
+        Attention: While possible to generate sync without preamble, the
+        receiver won't be able to detect the sync without preamble.
+    enable_length_byte
+        optionOn    - the length of the telegram will be automatically
+                  added to the telegram. It's part of the payload
+        optionOff    - no length information will be automatically added
+                  to the telegram.
+        Attention: For telegram length over 255 bytes, this option can't be
used
+        Attention: should be used in combination with sync, only
+    enable_address_byte
+        optionOn    - the address byte will be automatically added to the
+                  telgram. It's part of the payload
+        optionOff    - the address byte will not be added to the telegram.
+        The address byte can be used for address filtering, so the receiver
+        will only receive telegrams with a given address byte.
+        Attention: should be used in combination with sync, only
+    enable_crc
+        optionOn    - an crc will be automatically calculated over the
+                  payload of the telegram and added to the telegram
+                  after payload.
+        optionOff    - no crc will be calculated        
+    preamble_length
+        length of the preamble. Allowed values: 0...65536
+    sync_length
+        length of the sync word. Allowed values: 0...8
+    fixed_message_length
+        length of the payload of the telegram. Will override the length
+        given by the buffer, passed in with the write command. Will be
+        ignored if set to zero.
+    sync_pattern[8]
+        contains up to eight values, that are used as the sync pattern
+        on sync option
+    address_byte
+        one byte, used as address byte on address byte option.
+
+
+The rx configuration is transfered via struct pi433_rx_cfg, the parameterset
for receiving. It is devided into two sections: rf parameters and packet format.
+
+rf params:
+    frequency
+        frequency used for transmission.  
+        Allowed values: 433050000...434790000
+    bit_rate
+        bit rate used for transmission.
+        Allowed values: #####
+    dev_frequency
+        frequency deviation in case of FSK.
+        Allowed values: 600...500000
+    modulation
+        FSK - frequency shift key
+        OOK - on off key
+    rssi_threshold
+        threshold value for the signal strength on the receiver input.
+        If this value is exeeded, a reception cycle starts
+        Allowed values: 0...255
+    thresholdDecrement
+        in order to adapt to different levels of singnal strength, over
+        time the receiver gets more and more sensitive. This value  
+        determs, how fast the sensitivity increases.
+        step_0_5db    - increase in 0,5dB steps
+        step_1_0db    - increase in 1 db steps
+        step_1_5db    - increase in 1,5dB steps
+        step_2_0db    - increase in 2 db steps
+        step_3_0db    - increase in 3 db steps
+        step_4_0db    - increase in 4 db steps
+        step_5_0db    - increase in 5 db steps
+        step_6_0db    - increase in 6 db steps
+    antennaImpedance
+        sets the electrical adoption of the antenna
+        fiftyOhm    - for antennas with an impedance of 50Ohm
+        twohundretOhm    - for antennas with an impedance of 200Ohm
+    lnaGain
+        sets the gain of the low noise amp
+        automatic    - lna gain is determed by an agc
+        max        - lna gain is set to maximum
+        maxMinus6    - lna gain is set to  6db below max
+        maxMinus12    - lna gain is set to 12db below max
+        maxMinus24    - lna gain is set to 24db below max
+        maxMinus36    - lna gain is set to 36db below max
+        maxMinus48    - lna gain is set to 48db below max
+    bw_mantisse
+        sets the bandwidth of the channel filter - part one: mantisse.  
+        mantisse16    - mantisse is set to 16
+        mantisse20    - mantisse is set to 20
+        mantisse24    - mantisse is set to 24
+    bw_exponent
+        sets the bandwidth of the channel filter - part two: exponent.  
+        Allowd values: 0...7
+    dagc;
+        operation mode of the digital automatic gain control
+        normalMode
+        improve
+        improve4LowModulationIndex
+
+ packet format:
+    enable_sync
+        optionOn  - sync detection is enabled. If configured sync pattern
+                isn't found, telegram will be internally discarded  
+        optionOff - sync detection is disabled.
+    enable_length_byte
+        optionOn   - First byte of payload will be used as length byte,  
+                 regardless of the amount of bytes that were requested  
+                 by the read request.
+        optionOff  - Number of bytes to be read will be set according to
+                 amount of bytes that were requested by the read request.
+        Attention: should be used in combination with sync, only
+    enable_address_filtering;
+        filteringOff        - no adress filtering will take place
+        nodeAddress        - all telegrams, not matching the node  
+                      address will be internally discarded
+        nodeOrBroadcastAddress    - all telegrams, neither matching the
+                      node, nor the broadcast address will
+                      be internally discarded
+        Attention: Sync option must be enabled in order to use this feature
+    enable_crc
+        optionOn    - a crc will be calculated over the payload of
+                  the telegram, that was received. If the
+                  calculated crc doesn't match to two bytes,
+                  that follow the payload, the telegram will be
+                  internally discarded.
+        Attention: This option is only operational, if sync on and fixed length
+        or length byte is used
+    sync_length
+        Gives the length of the payload.  
+        Attention: This setting must meet the setting of the transmitter,
+        if sync option is used.
+    fixed_message_length
+        Overrides the telegram length either given by the first byte of
+        payload or by the read request.
+    bytes_to_drop
+        gives the number of bytes, that will be dropped before transfering
+        data to the read buffer
+        This option is only usefull, if all packet helper are switched
+        off and the rf chip is used in raw receiving mode. This may be
+        needed, if a telegram of a third party device should be received,
+        using a protocol not compatible with the packet engine of the rf69
chip.
+    sync_pattern[8]
+        contains up to eight values, that are used as the sync pattern
+        on sync option.
+        This setting must meet the configuration of the transmitting device,
+        if sync option is enabled.
+    node_address
+        one byte, used as node address byte on address byte option.
+    broadcast_address
+        one byte, used as broadcast address byte on address byte option.
+        
+
--
1.7.10.4

>From 5ace8010fb1e1d74cb6e925053da97e0c49237d1 Mon Sep 17 00:00:00 2001
From: Marcus Wolf <linux@Wolf-Entwicklungen.de>
Date: Tue, 4 Jul 2017 19:32:06 +0100
Subject: [PATCH 1/3] Added driver for Pi433, a 433MHz module for Raspberry
 Pi, based on HopeRf RFM69CW

---
 drivers/staging/Kconfig                |    2 +
 drivers/staging/Makefile               |    1 +
 drivers/staging/pi433/Kconfig          |    7 +
 drivers/staging/pi433/Makefile         |    3 +
 drivers/staging/pi433/pi433_if.c       | 1296 ++++++++++++++++++++++++++++++++
 drivers/staging/pi433/pi433_if.h       |  141 ++++
 drivers/staging/pi433/rf69.c           |  982 ++++++++++++++++++++++++
 drivers/staging/pi433/rf69.h           |   66 ++
 drivers/staging/pi433/rf69_enum.h      |  186 +++++
 drivers/staging/pi433/rf69_registers.h |  489 ++++++++++++
 10 files changed, 3173 insertions(+)
 create mode 100644 drivers/staging/pi433/Kconfig
 create mode 100644 drivers/staging/pi433/Makefile
 create mode 100644 drivers/staging/pi433/pi433_if.c
 create mode 100644 drivers/staging/pi433/pi433_if.h
 create mode 100644 drivers/staging/pi433/rf69.c
 create mode 100644 drivers/staging/pi433/rf69.h
 create mode 100644 drivers/staging/pi433/rf69_enum.h
 create mode 100644 drivers/staging/pi433/rf69_registers.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 268d4e6..fdf060c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"
 
 source "drivers/staging/typec/Kconfig"
 
+source "drivers/staging/pi433/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b93e6f5..998f644 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)        += ks7010/
 obj-$(CONFIG_GREYBUS)        += greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)    += vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)    += ccree/
+obj-$(CONFIG_PI433)        += pi433/
diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
new file mode 100644
index 0000000..a0b1bea
--- /dev/null
+++ b/drivers/staging/pi433/Kconfig
@@ -0,0 +1,7 @@
+config PI433
+        tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
+        default n
+        ---help---
+          This option allows you to enable support for the radio module Pi433.
+
+          If in doubt, say N here.
diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile
new file mode 100644
index 0000000..417f3e4
--- /dev/null
+++ b/drivers/staging/pi433/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PI433) += pi433.o
+
+pi433-objs := pi433_if.o rf69.o
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
new file mode 100644
index 0000000..f7fbd08
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.c
@@ -0,0 +1,1296 @@
+/*
+ * userspace interface for pi433 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+
+#include "pi433_if.h"
+#include "rf69.h"
+
+
+#define N_PI433_MINORS            (1U << MINORBITS) /*32*/    /* ... up to 256
*/
+#define MAX_MSG_SIZE            900
+#define MSG_FIFO_SIZE            65536   /* 65536 = 2^16  */
+#define NUM_DIO                2
+
+static dev_t pi433_dev;
+static DEFINE_IDR(pi433_idr);
+static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+
+static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
+
+/* tx config is instance specific
+    so with each open a new tx config struct is needed */
+/* rx config is device specific
+    so we have just one rx config, ebedded in device struct */
+struct pi433_device {
+    /* device handling related values */
+    dev_t            devt;
+    int            minor;
+    struct device        *dev;
+    struct cdev        *cdev;
+    struct spi_device    *spi;
+    unsigned        users;
+
+    /* irq related values */
+    struct gpio_desc    *gpiod[NUM_DIO];
+    int            irq_num[NUM_DIO];
+    u8            irq_state[NUM_DIO];
+
+    /* tx related values */
+    STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
+    struct mutex        tx_fifo_lock;
+    struct task_struct    *tx_task_struct;
+    wait_queue_head_t    tx_wait_queue;
+    u8            free_in_fifo;
+
+    /* rx related values */
+    struct pi433_rx_cfg    rx_cfg;
+    u8            *rx_buffer;
+    unsigned int        rx_buffer_size;
+    u32            rx_bytes_to_drop;
+    u32            rx_bytes_dropped;
+    unsigned int        rx_position;
+    struct mutex        rx_lock;
+    wait_queue_head_t    rx_wait_queue;
+
+    /* fifo wait queue */
+    struct task_struct    *fifo_task_struct;
+    wait_queue_head_t    fifo_wait_queue;
+
+    /* flags */
+    bool            rx_active;
+    bool            tx_active;
+    bool            interrupt_rx_allowed;
+};
+
+struct pi433_instance {
+    struct pi433_device    *device;
+    struct pi433_tx_cfg    tx_cfg;
+};
+
+// TODO: folgende Zeilen benötigt?
+static unsigned bufsiz = 4096;
+module_param(bufsiz, uint, S_IRUGO);
+MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI msg");
+
+/*-------------------------------------------------------------------------*/
+
+/* macro for checked access of registers of radio module */
+#define SET_CHECKED(retval) \
+    if (retval < 0) \
+        return retval;
+
+/*-------------------------------------------------------------------------*/
+
+/* GPIO interrupt handlers */
+static irq_handler_t
+DIO0_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct pi433_device *device = dev_id;
+
+    if      (device->irq_state[DIO0] == DIO_PacketSent)
+    {
+        device->free_in_fifo = FIFO_SIZE;
+        printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include
KERN_ facility level
+        wake_up_interruptible(&device->fifo_wait_queue);
+    }
+    else if (device->irq_state[DIO0] == DIO_Rssi_DIO0)
+    {
+        printk("DIO0 irq: RSSI level over threshold\n");
+        wake_up_interruptible(&device->rx_wait_queue);
+    }
+    else if (device->irq_state[DIO0] == DIO_PayloadReady)
+    {
+        printk("DIO0 irq: PayloadReady\n");
+        device->free_in_fifo = 0;
+        wake_up_interruptible(&device->fifo_wait_queue);
+    }
+
+    return (irq_handler_t) IRQ_HANDLED;
+}
+
+static irq_handler_t
+DIO1_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct pi433_device *device = dev_id;
+
+    if      (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1)
+    {
+        device->free_in_fifo = FIFO_SIZE;
+    }
+    else if (device->irq_state[DIO1] == DIO_FifoLevel)
+    {
+        if (device->rx_active)    device->free_in_fifo = FIFO_THRESHOLD - 1;
+        else            device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1;
+    }
+    printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO:
printk() should include KERN_ facility level
+    wake_up_interruptible(&device->fifo_wait_queue);
+
+    return (irq_handler_t) IRQ_HANDLED;
+}
+
+static void *DIO_irq_handler[NUM_DIO] = {
+    DIO0_irq_handler,
+    DIO1_irq_handler
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
+{
+    int payload_length;
+
+    /* receiver config */
+    SET_CHECKED(rf69_set_frequency    (dev->spi, rx_cfg->frequency)); // TODO:
Limit to 433MHz ISM-Band
+    SET_CHECKED(rf69_set_bit_rate    (dev->spi, rx_cfg->bit_rate));
+    SET_CHECKED(rf69_set_modulation    (dev->spi, rx_cfg->modulation));
+    SET_CHECKED(rf69_set_antenna_impedance     (dev->spi,
rx_cfg->antenna_impedance));
+    SET_CHECKED(rf69_set_rssi_threshold     (dev->spi,
rx_cfg->rssi_threshold));
+    SET_CHECKED(rf69_set_ook_threshold_dec     (dev->spi,
rx_cfg->thresholdDecrement));
+    SET_CHECKED(rf69_set_bandwidth          (dev->spi, rx_cfg->bw_mantisse,
rx_cfg->bw_exponent));
+    SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse,
rx_cfg->bw_exponent));
+    SET_CHECKED(rf69_set_dagc          (dev->spi, rx_cfg->dagc));
+
+    dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop;
+
+    /* packet config */
+    /* enable */
+    SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync));
+    if (rx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi,
afterSyncInterrupt));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always));
+    }
+    SET_CHECKED(rf69_set_packet_format  (dev->spi,
rx_cfg->enable_length_byte));
+    SET_CHECKED(rf69_set_adressFiltering(dev->spi,
rx_cfg->enable_address_filtering));
+    SET_CHECKED(rf69_set_crc_enable        (dev->spi, rx_cfg->enable_crc));
+    
+    /* lengths */
+    SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
+    if (rx_cfg->enable_length_byte == optionOn)
+    {
+        SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff));
+    }
+    else if (rx_cfg->fixed_message_length != 0)
+    {
+        payload_length = rx_cfg->fixed_message_length;
+        if (rx_cfg->enable_length_byte  == optionOn) payload_length++;
+        if (rx_cfg->enable_address_filtering != filteringOff) payload_length++;
+        SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
+    }
+    
+    /* values */
+    if (rx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern));
+    }
+    if (rx_cfg->enable_address_filtering != filteringOff)
+    {
+        SET_CHECKED(rf69_set_node_address     (dev->spi,
rx_cfg->node_address));
+        SET_CHECKED(rf69_set_broadcast_address(dev->spi,
rx_cfg->broadcast_address));
+    }
+
+    return 0;
+}
+
+static int
+rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
+{
+    SET_CHECKED(rf69_set_frequency    (dev->spi, tx_cfg->frequency));
+    SET_CHECKED(rf69_set_bit_rate    (dev->spi, tx_cfg->bit_rate));
+    SET_CHECKED(rf69_set_modulation    (dev->spi, tx_cfg->modulation));
+    SET_CHECKED(rf69_set_deviation    (dev->spi, tx_cfg->dev_frequency));
+    SET_CHECKED(rf69_set_pa_ramp    (dev->spi, tx_cfg->pa_ramp));
+    SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping));
+    SET_CHECKED(rf69_set_tx_start_condition(dev->spi,
tx_cfg->tx_start_condition));
+
+    /* packet format enable */
+    if (tx_cfg->enable_preamble == optionOn)
+    {
+        SET_CHECKED(rf69_set_preamble_length(dev->spi,
tx_cfg->preamble_length));
+    }    
+    else
+    {
+        SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
+    }
+    SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
+    SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
+    SET_CHECKED(rf69_set_crc_enable      (dev->spi, tx_cfg->enable_crc));
+    
+    /* configure sync, if enabled */
+    if (tx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length));
+        SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern));
+    }
+
+    return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pi433_start_rx(struct pi433_device *dev)
+{
+    int retval;
+
+    /* return without action, if no pending read request */
+    if (!dev->rx_active)
+        return 0;
+
+    /* setup for receiving */
+    retval = rf69_set_rx_cfg(dev, &dev->rx_cfg);
+    if (retval) return retval;
+
+    /* setup rssi irq */
+    SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0));
+    dev->irq_state[DIO0] = DIO_Rssi_DIO0;
+    irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+    /* setup fifo level interrupt */
+    SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD));
+    SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel));
+    dev->irq_state[DIO1] = DIO_FifoLevel;
+    irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING);
+
+    /* set module to receiving mode */
+    SET_CHECKED(rf69_set_mode(dev->spi, receive));
+
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int
+pi433_receive(void *data)
+{
+    struct pi433_device *dev = data;
+    struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */
+    int bytes_to_read, bytes_total;
+    int retval;
+
+    dev->interrupt_rx_allowed = false;
+
+    /* wait for any tx to finish */
+    dev_dbg(dev->dev,"rx: going to wait for any tx to finish");
+    retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
+    if(retval) /* wait was interrupted */
+    {
+        dev->interrupt_rx_allowed = true;
+        wake_up_interruptible(&dev->tx_wait_queue);
+        return retval;
+    }
+
+    /* prepare status vars */
+    dev->free_in_fifo = FIFO_SIZE;
+    dev->rx_position = 0;
+    dev->rx_bytes_dropped = 0;
+
+    /* setup radio module to listen for something "in the air" */
+    retval = pi433_start_rx(dev);
+    if (retval)
+        return retval;
+
+    /* now check RSSI, if low wait for getting high (RSSI interrupt) */
+    while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) )
+    {
+        /* allow tx to interrupt us while waiting for high RSSI */
+        dev->interrupt_rx_allowed = true;
+        wake_up_interruptible(&dev->tx_wait_queue);
+
+        /* wait for RSSI level to become high */
+        dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
+        retval = wait_event_interruptible(dev->rx_wait_queue,
+                                      rf69_get_flag(dev->spi,
+
                                                       rssiExceededThreshold));
+        if (retval) goto abort; /* wait was interrupted */
+        dev->interrupt_rx_allowed = false;
+
+        /* cross check for ongoing tx */
+        if (!dev->tx_active) break;
+    }
+
+    /* configure payload ready irq */
+    SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady));
+    dev->irq_state[DIO0] = DIO_PayloadReady;
+    irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+    /* fixed or unlimited length? */
+    if (dev->rx_cfg.fixed_message_length != 0)
+    {
+        if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size)
+        {
+            retval = -1;
+            goto abort;
+        }
+        bytes_total = dev->rx_cfg.fixed_message_length;
+        dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total);
+    }
+    else
+    {
+        bytes_total = dev->rx_buffer_size;
+        dev_dbg(dev->dev, "rx: msg len set to %d as requested by read",
bytes_total);
+    }
+
+    /* length byte enabled? */
+    if (dev->rx_cfg.enable_length_byte == optionOn)
+    {
+        retval = wait_event_interruptible(dev->fifo_wait_queue,
+                          dev->free_in_fifo < FIFO_SIZE);
+        if (retval) goto abort; /* wait was interrupted */
+
+        rf69_read_fifo(spi, (u8 *)&bytes_total, 1);
+        if (bytes_total > dev->rx_buffer_size)
+        {
+            retval = -1;
+            goto abort;
+        }
+        dev->free_in_fifo++;
+        dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte",
bytes_total);
+    }
+
+    /* address byte enabled? */
+    if (dev->rx_cfg.enable_address_filtering != filteringOff)
+    {
+        u8 dummy;
+
+        bytes_total--;
+
+        retval = wait_event_interruptible(dev->fifo_wait_queue,
+                          dev->free_in_fifo < FIFO_SIZE);
+        if (retval) goto abort; /* wait was interrupted */
+
+        rf69_read_fifo(spi, &dummy, 1);
+        dev->free_in_fifo++;
+        dev_dbg(dev->dev, "rx: address byte stripped off");
+    }
+
+    /* get payload */
+    while (dev->rx_position < bytes_total)
+    {
+        if ( !rf69_get_flag(dev->spi, payloadReady) )
+        {
+            retval = wait_event_interruptible(dev->fifo_wait_queue,
+                              dev->free_in_fifo < FIFO_SIZE);
+            if (retval) goto abort; /* wait was interrupted */
+        }
+
+        /* need to drop bytes or acquire? */
+        if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+            bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+        else
+            bytes_to_read = bytes_total - dev->rx_position;
+
+
+        /* access the fifo */
+        if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo)
+            bytes_to_read = FIFO_SIZE - dev->free_in_fifo;
+        retval = rf69_read_fifo(spi,
+                    &dev->rx_buffer[dev->rx_position],
+                    bytes_to_read);
+        if (retval) goto abort; /* read failed */
+        dev->free_in_fifo += bytes_to_read;
+
+        /* adjust status vars */
+        if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+            dev->rx_bytes_dropped += bytes_to_read;
+        else
+            dev->rx_position += bytes_to_read;
+    }
+
+
+    /* rx done, wait was interrupted or error occured */
+abort:
+    dev->interrupt_rx_allowed = true;
+    SET_CHECKED(rf69_set_mode(dev->spi, standby));
+    wake_up_interruptible(&dev->tx_wait_queue);
+
+    if (retval)
+        return retval;
+    else
+        return bytes_total;
+}
+
+int
+pi433_tx_thread(void *data)
+{
+    struct pi433_device *device = data;
+    struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
+    struct pi433_tx_cfg tx_cfg;
+    u8     buffer[MAX_MSG_SIZE];    
+    size_t size;
+    bool   rx_interrupted = false;
+    int    position, repetitions;
+    int    retval;
+
+    while (1)
+    {
+        /* wait for fifo to be populated or for request to terminate*/
+        dev_dbg(device->dev, "thread: going to wait for new messages");
+        wait_event_interruptible(device->tx_wait_queue,
+                     ( !kfifo_is_empty(&device->tx_fifo) ||
+                        kthread_should_stop() ));
+        if ( kthread_should_stop() )
+            return 0;
+
+        /* get data from fifo in the following order:
+           - tx_cfg
+           - size of message
+           - message */
+        mutex_lock(&device->tx_fifo_lock);
+
+        retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
+        if (retval != sizeof(tx_cfg))
+        {
+            dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d
byte(s), expected %d", retval, sizeof(tx_cfg) );
+            mutex_unlock(&device->tx_fifo_lock);
+            continue;
+        }
+
+        retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
+        if (retval != sizeof(size_t))
+        {
+            dev_dbg(device->dev, "reading msg size from fifo failed: got %d,
expected %d", retval, sizeof(size_t) );
+            mutex_unlock(&device->tx_fifo_lock);
+            continue;
+        }
+
+        /* use fixed message length, if requested */
+        if (tx_cfg.fixed_message_length != 0)
+            size = tx_cfg.fixed_message_length;
+
+        /* increase size, if len byte is requested */
+        if (tx_cfg.enable_length_byte == optionOn)
+            size++;
+
+        /* increase size, if adr byte is requested */
+        if (tx_cfg.enable_address_byte == optionOn)
+            size++;
+
+        /* prime buffer */
+        memset(buffer, 0, size);
+        position = 0;
+
+        /* add length byte, if requested */
+        if (tx_cfg.enable_length_byte  == optionOn)
+            buffer[position++] = size-1; /* according to spec length byte
itself must be excluded from the length calculation */
+
+        /* add adr byte, if requested */
+        if (tx_cfg.enable_address_byte == optionOn)
+            buffer[position++] = tx_cfg.address_byte;
+
+        /* finally get message data from fifo */
+        retval = kfifo_out(&device->tx_fifo, &buffer[position],
sizeof(buffer)-position );
+        dev_dbg(device->dev, "read %d message byte(s) from fifo queue.",
retval);
+        mutex_unlock(&device->tx_fifo_lock);
+
+        /* if rx is active, we need to interrupt the waiting for
+           incoming telegrams, to be able to send something.
+           We are only allowed, if currently no reception takes
+           place otherwise we need to  wait for the incoming telegram
+           to finish */
+        disable_irq(device->irq_num[DIO0]); /* prevent race conditions */
+        wait_event_interruptible(device->tx_wait_queue,
+                     !device->rx_active ||
+                      device->interrupt_rx_allowed == true);
+        device->tx_active = true;
+        /* irq will be reenabled after config to packet sent */
+
+        if (device->rx_active && rx_interrupted == false)
+        {
+            /* rx is currently waiting for a telegram;
+               we need to set the radio module to standby */
+            SET_CHECKED(rf69_set_mode(device->spi, standby));
+            rx_interrupted = true;
+        }
+
+        /* clear fifo, set fifo threshold, set payload length */
+        SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */
+        SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD));
+        if (tx_cfg.enable_length_byte == optionOn)
+        {
+            SET_CHECKED(rf69_set_payload_length(spi, size *
tx_cfg.repetitions));
+        }
+        else
+        {
+            SET_CHECKED(rf69_set_payload_length(spi, 0));
+        }
+
+        /* configure the rf chip */
+        rf69_set_tx_cfg(device, &tx_cfg);
+
+        /* enable fifo level interrupt */
+        SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel));
+        device->irq_state[DIO1] = DIO_FifoLevel;
+        irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING);
+
+        /* enable packet sent interrupt */
+        SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent));
+        device->irq_state[DIO0] = DIO_PacketSent;
+        irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+        enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check
*/
+        
+        /* enable transmission */
+        SET_CHECKED(rf69_set_mode(spi, transmit));
+
+        /* transfer this msg (and repetitions) to chip fifo */
+        device->free_in_fifo = FIFO_SIZE;
+        position = 0;
+        repetitions = tx_cfg.repetitions;
+        while( (repetitions > 0) && (size > position) )
+        {
+            if ( (size - position) > device->free_in_fifo)
+            {    /* msg to big for fifo - take a part */
+                int temp = device->free_in_fifo;
+                device->free_in_fifo = 0;
+                rf69_write_fifo(spi,
+                                &buffer[position],
+                                temp);
+                position +=temp;
+            }
+            else
+            {    /* msg fits into fifo - take all */
+                device->free_in_fifo -= size;
+                repetitions--;
+                rf69_write_fifo(spi,
+                        &buffer[position],
+                        (size - position) );
+                position = 0; /* reset for next repetition */
+            }
+
+            retval = wait_event_interruptible(device->fifo_wait_queue,
+                              device->free_in_fifo > 0);
+            if (retval) { printk("ABORT\n"); goto abort; }
+        }
+
+        /* we are done. Wait for packet to get sent */
+        dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be
empty");
+        wait_event_interruptible(device->fifo_wait_queue,
+                     device->free_in_fifo == FIFO_SIZE ||
+                     kthread_should_stop() );
+        if ( kthread_should_stop() )    printk("ABORT\n");
+
+
+        /* STOP_TRANSMISSION */
+        dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.");
+        SET_CHECKED(rf69_set_mode(spi, standby));
+
+        /* everything sent? */
+        if ( kfifo_is_empty(&device->tx_fifo) )
+        {
+abort:
+            if (rx_interrupted)
+            {
+                rx_interrupted = false;
+                pi433_start_rx(device);
+            }
+            device->tx_active = false;
+            wake_up_interruptible(&device->rx_wait_queue);
+        }
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t
+pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    unsigned int        bytes_received;
+    ssize_t            retval;
+
+    /* check, whether internal buffer is big enough for requested size */
+    if (size > bufsiz)
+        return -EMSGSIZE;
+
+    instance = filp->private_data;
+    device = instance->device;
+
+    /* just one read request at a time */
+    mutex_lock(&device->rx_lock);
+    if (device->rx_active)
+    {
+        mutex_unlock(&device->rx_lock);
+        return -EAGAIN;
+    }
+    else
+    {
+        device->rx_active = true;
+        mutex_unlock(&device->rx_lock);
+    }
+
+    /* start receiving */
+    /* will block until something was received*/
+    device->rx_buffer_size = size;
+    bytes_received = pi433_receive(device);
+
+    /* release rx */
+    mutex_lock(&device->rx_lock);
+    device->rx_active = false;
+    mutex_unlock(&device->rx_lock);
+
+    /* if read was successful copy to user space*/
+    if (bytes_received >= 0)
+    {
+        retval = copy_to_user(buf, device->rx_buffer, bytes_received);
+        if (retval)
+            return retval;
+    }
+
+    return bytes_received;
+}
+
+
+static ssize_t
+pi433_write(struct file *filp, const char __user *buf,
+        size_t count, loff_t *f_pos)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    int                     copied, retval;
+
+    instance = filp->private_data;
+    device = instance->device;
+
+    /* write the following sequence into fifo:
+       - tx_cfg
+       - size of message
+       - message */
+    mutex_lock(&device->tx_fifo_lock);
+    retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg,
sizeof(instance->tx_cfg));
+    if ( retval != sizeof(instance->tx_cfg) )
+        goto abort;
+
+    retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t));
+    if ( retval != sizeof(size_t) )
+        goto abort;
+
+    retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied);
+    if (retval || copied != count)
+        goto abort;
+
+    mutex_unlock(&device->tx_fifo_lock);
+
+    /* start transfer */
+    wake_up_interruptible(&device->tx_wait_queue);
+    dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied);
+
+    return 0;
+
+abort:
+    dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
+    kfifo_reset(&device->tx_fifo);
+    mutex_unlock(&device->tx_fifo_lock);
+    return -EAGAIN;
+}
+
+
+static long
+pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    int            err = 0;
+    int            retval = 0;
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    u32            tmp;
+
+    /* Check type and command number */
+    if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
+        return -ENOTTY;
+
+    /* Check access direction once here; don't repeat below.
+     * IOC_DIR is from the user perspective, while access_ok is
+     * from the kernel perspective; so they look reversed.
+     */
+    if (_IOC_DIR(cmd) & _IOC_READ)
+        err = !access_ok(VERIFY_WRITE,
+                 (void __user *)arg,
+                 _IOC_SIZE(cmd));
+
+    if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+        err = !access_ok(VERIFY_READ,
+                 (void __user *)arg,
+                 _IOC_SIZE(cmd));
+    if (err)
+        return -EFAULT;
+
+    /* TODO? guard against device removal before, or while,
+     * we issue this ioctl. --> device_get()
+     */
+    instance = filp->private_data;
+    device = instance->device;
+
+    if (device == NULL)
+        return -ESHUTDOWN;
+
+    switch (cmd) {
+    case PI433_IOC_RD_TX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_to_user((void __user *)arg,
+                    &instance->tx_cfg,
+                    tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+    case PI433_IOC_WR_TX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_from_user(&instance->tx_cfg,
+                     (void __user *)arg,
+                     tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+
+    case PI433_IOC_RD_RX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_to_user((void __user *)arg,
+                   &device->rx_cfg,
+                   tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+    case PI433_IOC_WR_RX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        mutex_lock(&device->rx_lock);
+
+        /* during pendig read request, change of config not allowed */
+        if (device->rx_active) {
+            retval = -EAGAIN;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+            retval = -EINVAL;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        if (__copy_from_user(&device->rx_cfg,
+                     (void __user *)arg,
+                     tmp))
+        {
+            retval = -EFAULT;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        mutex_unlock(&device->rx_lock);
+        break;
+    default:
+        retval = -EINVAL;
+    }
+
+    return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define pi433_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_open(struct inode *inode, struct file *filp)
+{
+    struct pi433_device    *device;
+    struct pi433_instance    *instance;
+
+    mutex_lock(&minor_lock);
+    device = idr_find(&pi433_idr, iminor(inode));
+
+    mutex_unlock(&minor_lock);
+    if (!device) {
+        dev_dbg(device->dev, "device: minor %d unknown.\n", iminor(inode));
+        return -ENODEV;
+    }
+
+    if (!device->rx_buffer) {
+        device->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);
+        if (!device->rx_buffer)
+        {
+            dev_dbg(device->dev, "open/ENOMEM\n");
+            return -ENOMEM;
+        }
+    }
+
+    device->users++;
+    instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+    if (!instance)
+    {
+        kfree(device->rx_buffer);
+        device->rx_buffer = NULL;
+        return -ENOMEM;
+    }
+
+    /* setup instance data*/
+    instance->device = device;
+    instance->tx_cfg.bit_rate = 4711;
+    // TODO: fill instance->tx_cfg;
+
+    /* instance data as context */
+    filp->private_data = instance;
+    nonseekable_open(inode, filp);
+
+    return 0;
+}
+
+static int pi433_release(struct inode *inode, struct file *filp)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+
+    instance = filp->private_data;
+    device = instance->device;
+    kfree(instance);
+    filp->private_data = NULL;
+
+    /* last close? */
+    device->users--;
+
+    if (!device->users) {
+        kfree(device->rx_buffer);
+        device->rx_buffer = NULL;
+        if (device->spi == NULL)
+            kfree(device);
+    }
+
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int setup_GPIOs(struct pi433_device *device)
+{
+    char     name[5];
+    int    retval;
+    int    i;
+
+    for (i=0; i<NUM_DIO; i++)
+    {
+        /* "construct" name and get the gpio descriptor */
+        snprintf(name, sizeof(name), "DIO%d", i);
+        device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+
+        if (device->gpiod[i] == ERR_PTR(-ENOENT))
+        {
+            dev_dbg(&device->spi->dev, "Could not find entry for %s.
Ignoring.", name);
+            continue;
+        }
+
+        if (device->gpiod[i] == ERR_PTR(-EBUSY))
+            dev_dbg(&device->spi->dev, "%s is busy.", name);
+
+        if ( IS_ERR(device->gpiod[i]) )
+        {
+            retval = PTR_ERR(device->gpiod[i]);
+            /* release already allocated gpios */
+            for (i--; i>=0; i--)
+            {
+                free_irq(device->irq_num[i], device);
+                gpiod_put(device->gpiod[i]);
+            }
+            return retval;
+        }
+
+
+        /* configure the pin */
+        gpiod_unexport(device->gpiod[i]);
+        retval = gpiod_direction_input(device->gpiod[i]);
+        if (retval) return retval;
+
+
+        /* configure irq */
+        device->irq_num[i] = gpiod_to_irq(device->gpiod[i]);
+        if (device->irq_num[i] < 0)
+        {
+            device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc
*)device->irq_num[i];
+            return device->irq_num[i];
+        }
+        retval = request_irq(device->irq_num[i],
+                     DIO_irq_handler[i],
+                     0, /* flags */
+                     name,
+                     device);
+
+        if (retval)
+            return retval;
+
+        dev_dbg(&device->spi->dev, "%s succesfully configured", name);
+    }
+
+    return 0;
+}
+
+static void free_GPIOs(struct pi433_device *device)
+{
+    int i;
+
+    for (i=0; i<NUM_DIO; i++)
+    {
+        /* check if gpiod is valid */
+        if ( IS_ERR(device->gpiod[i]) )
+            continue;
+
+        free_irq(device->irq_num[i], device);
+        gpiod_put(device->gpiod[i]);
+    }
+    return;
+}
+
+static int pi433_get_minor(struct pi433_device *device)
+{
+    int retval = -ENOMEM;
+
+    mutex_lock(&minor_lock);
+    retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL);
+    if (retval >= 0) {
+        device->minor = retval;
+        retval = 0;
+    } else if (retval == -ENOSPC) {
+        dev_err(device->dev, "too many pi433 devices\n");
+        retval = -EINVAL;
+    }
+    mutex_unlock(&minor_lock);
+    return retval;
+}
+
+static void pi433_free_minor(struct pi433_device *dev)
+{
+    mutex_lock(&minor_lock);
+    idr_remove(&pi433_idr, dev->minor);
+    mutex_unlock(&minor_lock);
+}
+/*-------------------------------------------------------------------------*/
+
+static const struct file_operations pi433_fops = {
+    .owner =    THIS_MODULE,
+    /* REVISIT switch to aio primitives, so that userspace
+     * gets more complete API coverage.  It'll simplify things
+     * too, except for the locking.
+     */
+    .write =    pi433_write,
+    .read =        pi433_read,
+    .unlocked_ioctl = pi433_ioctl,
+    .compat_ioctl = pi433_compat_ioctl,
+    .open =        pi433_open,
+    .release =    pi433_release,
+    .llseek =    no_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_probe(struct spi_device *spi)
+{
+    struct pi433_device    *device;
+    int            retval;
+
+    /* setup spi parameters */
+    spi->mode = 0x00;
+    spi->bits_per_word = 8;
+    /* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay
*/
+
+    retval = spi_setup(spi);
+    if (retval)
+    {
+        dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
+        return retval;
+    }
+    else
+    {    
+        dev_dbg(&spi->dev,
+            "spi interface setup: mode 0x%2x, %d bits per word, %dhz max
speed",
+            spi->mode, spi->bits_per_word, spi->max_speed_hz);
+    }
+
+    /* Ping the chip by reading the version register */
+    retval = spi_w8r8(spi, 0x10);
+    if (retval < 0)
+        return retval;
+
+    switch(retval)
+    {
+        case 0x24:
+            dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
+            break;
+        default:
+            dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
+            return -ENODEV;
+    }
+
+    /* Allocate driver data */
+    device = kzalloc(sizeof(*device), GFP_KERNEL);
+    if (!device)
+        return -ENOMEM;
+
+    /* Initialize the driver data */
+    device->spi = spi;
+    device->rx_active = false;
+    device->tx_active = false;
+    device->interrupt_rx_allowed = false;
+
+    /* init wait queues */
+    init_waitqueue_head(&device->tx_wait_queue);
+    init_waitqueue_head(&device->rx_wait_queue);
+    init_waitqueue_head(&device->fifo_wait_queue);
+
+    /* init fifo */
+    INIT_KFIFO(device->tx_fifo);
+
+    /* init mutexes and locks */
+    mutex_init(&device->tx_fifo_lock);
+    mutex_init(&device->rx_lock);
+
+    /* setup GPIO (including irq_handler) for the different DIOs */
+    retval = setup_GPIOs(device);
+    if (retval)
+    {
+        dev_dbg(&spi->dev, "setup of GPIOs failed");
+        goto GPIO_failed;
+    }
+
+    /* setup the radio module */
+    SET_CHECKED(rf69_set_mode        (spi, standby));
+    SET_CHECKED(rf69_set_data_mode        (spi, packet));
+    SET_CHECKED(rf69_set_amplifier_0    (spi, optionOn));
+    SET_CHECKED(rf69_set_amplifier_1    (spi, optionOff));
+    SET_CHECKED(rf69_set_amplifier_2    (spi, optionOff));
+    SET_CHECKED(rf69_set_output_power_level    (spi, 13));
+    SET_CHECKED(rf69_set_antenna_impedance    (spi, fiftyOhm));
+
+    /* start tx thread */
+    device->tx_task_struct = kthread_run(pi433_tx_thread,
+                         device,
+                         "pi433_tx_task");
+    if (device->tx_task_struct < 0)
+    {
+        dev_dbg(device->dev, "start of send thread failed");
+        goto send_thread_failed;
+    }
+
+    /* determ minor number */
+    retval = pi433_get_minor(device);
+    if (retval)
+    {
+        dev_dbg(device->dev, "get of minor number failed");
+        goto minor_failed;
+    }
+
+    /* create device */
+    device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
+    device->dev = device_create(pi433_class,
+                    &spi->dev,
+                    device->devt,
+                    device,
+                    "pi433");
+    if (IS_ERR(device->dev)) {
+        pr_err("pi433: device register failed\n");
+        retval = PTR_ERR(device->dev);
+        goto device_create_failed;
+    }
+    else {
+        dev_dbg(device->dev,
+            "created device for major %d, minor %d\n",
+            MAJOR(pi433_dev),
+            device->minor);
+    }
+
+    /* create cdev */
+    device->cdev = cdev_alloc();
+    device->cdev->owner = THIS_MODULE;
+    cdev_init(device->cdev, &pi433_fops);
+    retval = cdev_add(device->cdev, device->devt, 1);
+    if (retval)
+    {
+        dev_dbg(device->dev, "register of cdev failed");
+        goto cdev_failed;
+    }
+
+    /* spi setup */
+    spi_set_drvdata(spi, device);
+
+    return 0;
+
+cdev_failed:
+    device_destroy(pi433_class, device->devt);
+device_create_failed:
+    pi433_free_minor(device);
+minor_failed:
+    kthread_stop(device->tx_task_struct);
+send_thread_failed:
+    free_GPIOs(device);
+GPIO_failed:
+    kfree(device);
+
+    return retval;
+}
+
+static int pi433_remove(struct spi_device *spi)
+{
+    struct pi433_device    *device = spi_get_drvdata(spi);
+
+    /* free GPIOs */
+    free_GPIOs(device);
+
+    /* make sure ops on existing fds can abort cleanly */
+    device->spi = NULL;
+
+    kthread_stop(device->tx_task_struct);
+
+    device_destroy(pi433_class, device->devt);
+
+    cdev_del(device->cdev);
+
+    pi433_free_minor(device);
+
+    if (device->users == 0)
+        kfree(device);
+
+    return 0;
+}
+
+static const struct of_device_id pi433_dt_ids[] = {
+    { .compatible = "pi433" }, // TODO: DT compatible string "pi433" appears
un-documented -- check ./Documentation/devicetree/bindings/
+    {},
+};
+
+MODULE_DEVICE_TABLE(of, pi433_dt_ids);
+
+static struct spi_driver pi433_spi_driver = {
+    .driver = {
+        .name =        "pi433",
+        .owner =    THIS_MODULE,
+        .of_match_table = of_match_ptr(pi433_dt_ids),
+    },
+    .probe =    pi433_probe,
+    .remove =    pi433_remove,
+
+    /* NOTE:  suspend/resume methods are not necessary here.
+     * We don't do anything except pass the requests to/from
+     * the underlying controller.  The refrigerator handles
+     * most issues; the controller driver handles the rest.
+     */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init pi433_init(void)
+{
+    int status;
+
+    /* Claim device numbers.  Then register a class
+     * that will key udev/mdev to add/remove /dev nodes.  Last, register
+     * Last, register the driver which manages those device numbers.
+     */
+    status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS
/*count*/, "pi433" /*name*/);
+    if (status < 0)
+        return status;
+
+    pi433_class = class_create(THIS_MODULE, "pi433");
+    if (IS_ERR(pi433_class))
+    {
+        unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+        return PTR_ERR(pi433_class);
+    }
+
+    status = spi_register_driver(&pi433_spi_driver);
+    if (status < 0)
+    {
+        class_destroy(pi433_class);
+        unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+    }
+
+    return status;
+}
+
+module_init(pi433_init);
+
+static void __exit pi433_exit(void)
+{
+    spi_unregister_driver(&pi433_spi_driver);
+    class_destroy(pi433_class);
+    unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+}
+module_exit(pi433_exit);
+
+MODULE_AUTHOR("Marcus Wolf, <linux@wolf-entwicklungen.de>");
+MODULE_DESCRIPTION("Driver for Pi433");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:pi433");
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
new file mode 100644
index 0000000..a87c73c
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.h
@@ -0,0 +1,141 @@
+/*
+ * include/linux/TODO
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR     0
+struct pi433_tx_cfg
+{
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+    enum modulation        modulation;
+    enum modShaping        modShaping;
+
+    enum paRamp        pa_ramp;
+
+    enum txStartCondition    tx_start_condition;
+
+    __u16            repetitions;
+
+
+    /* packet format */
+    enum optionOnOff    enable_preamble;
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;
+    enum optionOnOff    enable_address_byte;
+    enum optionOnOff    enable_crc;
+
+    __u16            preamble_length;
+    __u8            sync_length;
+    __u8            fixed_message_length;
+
+    __u8            sync_pattern[8];
+    __u8            address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR     1
+struct pi433_rx_cfg {
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+
+    enum modulation        modulation;
+    
+    __u8            rssi_threshold;
+    enum thresholdDecrement    thresholdDecrement;
+    enum antennaImpedance    antenna_impedance;
+    enum lnaGain        lna_gain;
+    enum mantisse        bw_mantisse;    /* normal: 0x50 */
+    __u8            bw_exponent;    /* during AFC: 0x8b */
+    enum dagc        dagc;
+
+
+
+    /* packet format */
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;      /* should be used in
combination with sync, only */
+    enum addressFiltering    enable_address_filtering; /* operational with
sync, only */
+    enum optionOnOff    enable_crc;          /* only operational, if sync on
and fixed length or length byte is used */
+
+    __u8            sync_length;
+    __u8            fixed_message_length;
+    __u32            bytes_to_drop;
+
+    __u8            sync_pattern[8];
+    __u8            node_address;
+    __u8            broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC            'r'
+
+#define PI433_IOC_RD_TX_CFG    _IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG    _IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG    _IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG    _IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
new file mode 100644
index 0000000..b6bc45b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.c
@@ -0,0 +1,982 @@
+/*
+ * abstraction of the spi interface of HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* enable prosa debug info */
+#undef DEBUG
+/* enable print of values on reg access */
+#undef DEBUG_VALUES
+/* enable print of values on fifo access */
+#undef DEBUG_FIFO_ACCESS
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include "rf69.h"
+#include "rf69_registers.h"
+
+#define F_OSC      32000000 /* in Hz */
+#define FIFO_SIZE 66        /* in byte */
+
+/*-------------------------------------------------------------------------*/
+
+#define READ_REG(x)    rf69_read_reg (spi, x)
+#define WRITE_REG(x,y)    rf69_write_reg(spi, x, y)
+#define INVALID_PARAM \
+    { \
+        dev_dbg(&spi->dev, "set: illegal input param"); \
+        return -EINVAL; \
+    }
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: mode");
+    #endif
+
+    switch (mode){
+    case transmit:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT);
+    case receive:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE);
+    case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER);
+    case standby:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY);
+    case mode_sleep:  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP);
+    default:      INVALID_PARAM;
+    }
+
+    // we are using packet mode, so this check is not really needed
+    // but waiting for mode ready is necessary when going from sleep because
the FIFO may not be immediately available from previous mode
+    //while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) &
RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
+
+}
+
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: data mode");
+    #endif
+
+    switch (dataMode) {
+    case packet:        return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET);
+    case continuous:    return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS);
+    case continuousNoSync:  return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) |
DATAMODUL_MODE_CONTINUOUS_NOSYNC);
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: modulation");
+    #endif
+
+    switch (modulation) {
+    case OOK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) &
~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK);
+    case FSK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) &
~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK);
+    default:    INVALID_PARAM;
+    }
+}
+
+enum modulation rf69_get_modulation(struct spi_device *spi)
+{
+    u8 currentValue;    
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: mode");
+    #endif
+
+    currentValue = READ_REG(REG_DATAMODUL);
+
+    switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3)  // TODO
improvement: change 3 to define
+    {
+    case DATAMODUL_MODULATION_TYPE_OOK: return OOK;
+    case DATAMODUL_MODULATION_TYPE_FSK: return FSK;
+    default:                return undefined;
+    }
+}
+
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping
modShaping)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: mod shaping");
+    #endif
+
+    if (rf69_get_modulation(spi) == FSK)
+    {
+        switch (modShaping) {
+        case shapingOff: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_NONE);
+        case shaping1_0: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_1_0);
+        case shaping0_5: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_0_3);
+        case shaping0_3: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_0_5);
+        default:     INVALID_PARAM;
+        }
+    }
+    else
+    {
+        switch (modShaping) {
+        case shapingOff: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_NONE);
+        case shapingBR:     return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_BR);
+        case shaping2BR: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_2BR);
+        default:     INVALID_PARAM;
+        }
+    }
+}
+
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+{
+    int retval;
+    u32 bitRate_min;
+    u32 bitRate_reg;
+    u8 msb;
+    u8 lsb;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: bit rate");
+    #endif
+
+    // check input value
+    bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
+    if (bitRate < bitRate_min)
+    {
+        dev_dbg(&spi->dev, "setBitRate: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculate reg settings
+    bitRate_reg = (F_OSC / bitRate);
+
+    msb = (bitRate_reg&0xff00)   >>  8;
+    lsb = (bitRate_reg&0xff);
+
+    // transmit to RF 69
+    retval = WRITE_REG(REG_BITRATE_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_BITRATE_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_deviation(struct spi_device *spi, u32 deviation)
+{
+    int retval;
+//    u32 f_max; TODO: Abhängigkeit von Bitrate beachten!!
+    u64 f_reg;
+    u64 f_step;
+    u8 msb;
+    u8 lsb;
+    u64 factor = 1000000; // to improve precision of calculation
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: deviation");
+    #endif
+
+    if (deviation < 600 || deviation > 500000) //TODO: Abhängigkeit von Bitrate
beachten!!
+    {
+        dev_dbg(&spi->dev, "set_deviation: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculat f step
+    f_step = F_OSC * factor;
+    do_div(f_step, 524288); //  524288 = 2^19
+
+    // calculate register settings
+    f_reg = deviation * factor;
+    do_div(f_reg  , f_step);
+
+    msb = (f_reg&0xff00)   >>  8;
+    lsb = (f_reg&0xff);
+
+    // check msb
+    if (msb & !FDEVMASB_MASK)
+    {
+        dev_dbg(&spi->dev, "set_deviation: err in calc of msb");
+        INVALID_PARAM;
+    }
+
+    // write to chip
+    retval = WRITE_REG(REG_FDEV_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FDEV_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_frequency(struct spi_device *spi, u32 frequency)
+{
+    int retval;
+    u32 f_max;
+    u64 f_reg;
+    u64 f_step;
+    u8 msb;
+    u8 mid;
+    u8 lsb;
+    u64 factor = 1000000; // to improve precision of calculation
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: frequency");
+    #endif
+
+    // calculat f step
+    f_step = F_OSC * factor;
+    do_div(f_step, 524288); //  524288 = 2^19
+
+    // check input value
+    f_max = f_step * 8388608 / factor;
+    if (frequency > f_max)
+    {
+        dev_dbg(&spi->dev, "setFrequency: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculate reg settings
+    f_reg = frequency * factor;
+    do_div(f_reg  , f_step);
+
+    msb = (f_reg&0xff0000) >> 16;
+    mid = (f_reg&0xff00)   >>  8;
+    lsb = (f_reg&0xff);
+
+    // write to chip
+    retval = WRITE_REG(REG_FRF_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FRF_MID, mid);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FRF_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #0");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA0) );
+    case optionOff:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA0) );
+    default:    INVALID_PARAM;
+    }
+}    
+
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #1");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA1) );
+    case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA1) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #2");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA2) );
+    case optionOff:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA2) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: power level");
+    #endif
+
+    powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting
+
+    // check input value
+    if (powerLevel > 0x1f)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_OUTPUT_POWER) | powerLevel);
+}
+
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: pa ramp");
+    #endif
+
+    switch(paRamp) {
+    case ramp3400:    return WRITE_REG(REG_PARAMP, PARAMP_3400);
+    case ramp2000:    return WRITE_REG(REG_PARAMP, PARAMP_2000);
+    case ramp1000:    return WRITE_REG(REG_PARAMP, PARAMP_1000);
+    case ramp500:    return WRITE_REG(REG_PARAMP, PARAMP_500);
+    case ramp250:    return WRITE_REG(REG_PARAMP, PARAMP_250);
+    case ramp125:    return WRITE_REG(REG_PARAMP, PARAMP_125);
+    case ramp100:    return WRITE_REG(REG_PARAMP, PARAMP_100);
+    case ramp62:    return WRITE_REG(REG_PARAMP, PARAMP_62);
+    case ramp50:    return WRITE_REG(REG_PARAMP, PARAMP_50);
+    case ramp40:    return WRITE_REG(REG_PARAMP, PARAMP_40);
+    case ramp31:    return WRITE_REG(REG_PARAMP, PARAMP_31);
+    case ramp25:    return WRITE_REG(REG_PARAMP, PARAMP_25);
+    case ramp20:    return WRITE_REG(REG_PARAMP, PARAMP_20);
+    case ramp15:    return WRITE_REG(REG_PARAMP, PARAMP_15);
+    case ramp12:    return WRITE_REG(REG_PARAMP, PARAMP_12);
+    case ramp10:    return WRITE_REG(REG_PARAMP, PARAMP_10);
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance
antennaImpedance)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: antenna impedance");
+    #endif
+
+    switch(antennaImpedance) {
+    case fiftyOhm:        return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) &
~MASK_LNA_ZIN) );
+    case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) |
 MASK_LNA_ZIN) );
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: lna gain");
+    #endif
+
+    switch(lnaGain) {
+    case automatic:     return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_AUTO) );
+    case max:     return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX) );
+    case maxMinus6:  return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) );
+    case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) );
+    case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) );
+    case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) );
+    case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) );
+    default:     INVALID_PARAM;
+    }
+}
+
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi)
+{
+    u8 currentValue;    
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: lna gain");
+    #endif
+
+    currentValue = READ_REG(REG_LNA);
+
+    switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3)  // improvement: change
3 to define
+    {
+    case LNA_GAIN_AUTO:        return automatic;
+    case LNA_GAIN_MAX:        return max;
+    case LNA_GAIN_MAX_MINUS_6:  return maxMinus6;
+    case LNA_GAIN_MAX_MINUS_12: return maxMinus12;
+    case LNA_GAIN_MAX_MINUS_24: return maxMinus24;
+    case LNA_GAIN_MAX_MINUS_36: return maxMinus36;
+    case LNA_GAIN_MAX_MINUS_48: return maxMinus48;
+    default:            return undefined;
+    }
+}
+
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum
dccPercent dccPercent)
+{
+    switch (dccPercent) {
+    case dcc16Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) );
+    case dcc8Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) );
+    case dcc4Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) );
+    case dcc2Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) );
+    case dcc1Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) );
+    case dcc0_5Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) );
+    case dcc0_25Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) );
+    case dcc0_125Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) );
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent
dccPercent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: cut off freq");
+    #endif
+
+    return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent);
+}
+
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum
dccPercent dccPercent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: cut off freq during afc");
+    #endif
+
+    return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent);
+}
+
+int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse
mantisse, u8 exponent)
+{
+    u8 newValue;
+
+    // check value for mantisse and exponent
+    if (exponent > 7)   INVALID_PARAM;
+    if ( (mantisse!=mantisse16) &&
+         (mantisse!=mantisse20) &&
+             (mantisse!=mantisse24) ) INVALID_PARAM;
+
+    // read old value
+    newValue = READ_REG(reg);
+
+    // "delete" mantisse and exponent = just keep the DCC setting
+    newValue = newValue & MASK_BW_DCC_FREQ;
+
+    // add new mantisse
+    switch(mantisse) {
+    case mantisse16: newValue = newValue | BW_MANT_16;    break;
+    case mantisse20: newValue = newValue | BW_MANT_20;    break;
+    case mantisse24: newValue = newValue | BW_MANT_24;    break;
+    }
+
+    // add new exponent
+    newValue = newValue | exponent;
+
+    // write back
+    return WRITE_REG(reg, newValue);
+}
+
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8
exponent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: band width");
+    #endif
+
+    return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent);
+}
+
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse
mantisse, u8 exponent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: band width during afc");
+    #endif
+
+    return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
+}
+
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType
thresholdType)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold type");
+    #endif
+
+    switch (thresholdType)
+    {
+    case fixed:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) );
+    case peak:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) );
+    case average:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep
thresholdStep)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold step");
+    #endif
+
+    switch (thresholdStep) {
+    case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) );
+    case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) );
+    case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) );
+    case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) );
+    case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) );
+    case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) );
+    case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) );
+    case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) );
+    default:     INVALID_PARAM;
+    }
+}
+
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement
thresholdDecrement)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold decrement");
+    #endif
+
+    switch (thresholdDecrement) {
+    case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) );
+    case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) );
+    case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) );
+    case dec_once:       return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK)
& ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) );
+    case dec_twice:       return WRITE_REG(REG_OOKPEAK, (
(READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) );
+    case dec_4times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) );
+    case dec_8times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) );
+    case dec_16times:  return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) );
+    default:       INVALID_PARAM;
+    }
+}
+
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+{
+    u8 mask;
+    u8 shift;
+    u8 regaddr;
+    u8 regValue;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: DIO mapping");
+    #endif
+
+    // check DIO number
+    if (DIONumber > 5) INVALID_PARAM;
+
+    switch (DIONumber) {
+    case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break;
+    case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break;
+    case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break;
+    case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break;
+    case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break;
+    case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break;
+    }
+
+    // read reg
+    regValue=READ_REG(regaddr);
+    // delete old value
+    regValue = regValue & ~mask;
+    // add new value
+    regValue = regValue | value << shift;
+    // write back
+    return WRITE_REG(regaddr,regValue);
+}
+
+bool rf69_get_flag(struct spi_device *spi, enum flag flag)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: flag");
+    #endif
+
+    switch(flag) {
+    case modeSwitchCompleted:     return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_MODE_READY);
+    case readyToReceive:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_RX_READY);
+    case readyToSend:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_TX_READY);
+    case pllLocked:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_PLL_LOCK);
+    case rssiExceededThreshold:   return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_RSSI);
+    case timeout:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_TIMEOUT);
+    case automode:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_AUTOMODE);
+    case syncAddressMatch:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+    case fifoFull:              return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_FULL);
+/*    case fifoNotEmpty:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */
+    case fifoEmpty:              return !(READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_NOT_EMPTY);
+    case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_LEVEL);
+    case fifoOverrun:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_OVERRUN);
+    case packetSent:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_PACKET_SENT);
+    case payloadReady:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_PAYLOAD_READY);
+    case crcOk:              return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_CRC_OK);
+    case batteryLow:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_LOW_BAT);
+    default:              return false;
+    }
+}
+
+int rf69_reset_flag(struct spi_device *spi, enum flag flag)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "reset: flag");
+    #endif
+
+    switch(flag) {
+    case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1,
MASK_IRQFLAGS1_RSSI);
+    case syncAddressMatch:        return WRITE_REG(REG_IRQFLAGS1,
MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+    case fifoOverrun:        return WRITE_REG(REG_IRQFLAGS2,
MASK_IRQFLAGS2_FIFO_OVERRUN);
+    default:            INVALID_PARAM;
+    }
+}
+
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: rssi threshold");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RSSITHRESH, threshold);
+}
+
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: start timeout");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RXTIMEOUT1, timeout);
+}
+
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: rssi timeout");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RXTIMEOUT2, timeout);
+}
+
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+{
+    int retval;
+    u8 msb, lsb;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: preample length");
+    #endif
+
+    /* no value check needed - u16 exactly matches register size */
+
+    /* calculate reg settings */
+    msb = (preambleLength&0xff00)   >>  8;
+    lsb = (preambleLength&0xff);
+
+    /* transmit to chip */
+    retval = WRITE_REG(REG_PREAMBLE_MSB, msb);
+    if (retval) return retval;
+    retval = WRITE_REG(REG_PREAMBLE_LSB, lsb);
+
+    return retval;
+}
+
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync enable");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_SYNC_ON) );
+    case optionOff:    return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition
fifoFillCondition)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: fifo fill condition");
+    #endif
+
+    switch(fifoFillCondition) {
+    case always:         return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+    case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+    default:         INVALID_PARAM;
+    }
+}
+
+int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync size");
+    #endif
+
+    // check input value
+    if (syncSize > 0x07)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) &
~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) );
+}
+
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync tolerance");
+    #endif
+
+    // check input value
+    if (syncTolerance > 0x07)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) &
~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance);
+}
+
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+{
+    int retval = 0;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync values");
+    #endif
+
+    retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]);
+    retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]);
+    retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]);
+    retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]);
+    retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]);
+    retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]);
+    retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]);
+    retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]);
+
+    return retval;
+}
+
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat
packetFormat)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: packet format");
+    #endif
+
+    switch(packetFormat) {
+    case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+    case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+    default:          INVALID_PARAM;
+    }
+}
+
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: crc enable");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_CRC_ON) );
+    case optionOff:    return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering
addressFiltering)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: address filtering");
+    #endif
+
+    switch (addressFiltering) {
+    case filteringOff:         return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_OFF) );
+    case nodeAddress:         return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_NODE) );
+    case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) );
+    default:             INVALID_PARAM;
+    }
+}
+
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: payload length");
+    #endif
+
+    return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength);
+}
+
+u8  rf69_get_payload_length(struct spi_device *spi)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: payload length");
+    #endif
+
+    return (u8) READ_REG(REG_PAYLOAD_LENGTH);
+}
+
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: node address");
+    #endif
+
+    return WRITE_REG(REG_NODEADRS, nodeAddress);
+}
+
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: broadcast address");
+    #endif
+
+    return WRITE_REG(REG_BROADCASTADRS, broadcastAddress);
+}
+
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition
txStartCondition)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: start condition");
+    #endif
+
+    switch(txStartCondition) {
+    case fifoLevel:       return WRITE_REG(REG_FIFO_THRESH,
(READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) );
+    case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH,
(READ_REG(REG_FIFO_THRESH) |  MASK_FIFO_THRESH_TXSTART) );
+    default:       INVALID_PARAM;
+    }
+}
+
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
+{
+    int retval;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: fifo threshold");
+    #endif
+
+    // check input value
+    if (threshold & 0x80)
+        INVALID_PARAM;
+
+    // write value
+    retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) &
~MASK_FIFO_THRESH_VALUE) | threshold);
+    if (retval)
+        return retval;
+
+    // access the fifo to activate new threshold
+    return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer
+}
+
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: dagc");
+    #endif
+
+    switch(dagc) {
+    case normalMode:         return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL);
+    case improve:             return WRITE_REG(REG_TESTDAGC,
DAGC_IMPROVED_LOWBETA0);
+    case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC,
DAGC_IMPROVED_LOWBETA1);
+    default:             INVALID_PARAM;
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+    #ifdef DEBUG_FIFO_ACCESS    
+        int i;
+    #endif
+    struct spi_transfer transfer;
+    u8 local_buffer[FIFO_SIZE + 1];
+    int retval;
+
+    if (size > FIFO_SIZE)
+    {
+        #ifdef DEBUG
+            dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then
internal buffer \n");
+        #endif
+        return -EMSGSIZE;
+    }
+
+    /* prepare a bidirectional transfer */
+    local_buffer[0] = REG_FIFO;
+    memset(&transfer, 0, sizeof(transfer));
+      transfer.tx_buf = local_buffer;
+      transfer.rx_buf = local_buffer;
+    transfer.len    = size+1;
+
+    retval = spi_sync_transfer(spi, &transfer, 1);
+
+    #ifdef DEBUG_FIFO_ACCESS
+        for (i=0; i<size; i++)
+            dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]);
+    #endif
+
+    memcpy(buffer, &local_buffer[1], size);  // TODO: ohne memcopy wäre schöner
+
+    return retval;
+}
+
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+    #ifdef DEBUG_FIFO_ACCESS    
+        int i;
+    #endif
+    char spi_address = REG_FIFO | WRITE_BIT;
+    u8 local_buffer[FIFO_SIZE + 1];
+
+    if (size > FIFO_SIZE)
+    {
+        #ifdef DEBUG
+            dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then
internal buffer \n");
+        #endif
+        return -EMSGSIZE;
+    }
+
+    local_buffer[0] = spi_address;
+    memcpy(&local_buffer[1], buffer, size);  // TODO: ohne memcopy wäre schöner
+
+    #ifdef DEBUG_FIFO_ACCESS
+        for (i=0; i<size; i++)
+            dev_dbg(&spi->dev, "0x%x\n",buffer[i]);
+    #endif
+
+    return spi_write (spi, local_buffer, size + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+u8 rf69_read_reg(struct spi_device *spi, u8 addr)
+{
+    int retval;
+
+    retval = spi_w8r8(spi, addr);
+
+    #ifdef DEBUG_VALUES
+        if (retval < 0)
+            /* should never happen, since we already checked,
+               that module is connected. Therefore no error
+               handling, just an optional error message... */
+            dev_dbg(&spi->dev, "read 0x%x FAILED\n",
+                addr);
+        else
+            dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n",
+                retval,
+                addr);
+    #endif
+
+    return retval;
+}
+
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value)
+{
+    int retval;
+    char buffer[2];
+    
+    buffer[0] = addr | WRITE_BIT;
+    buffer[1] = value;
+
+    retval = spi_write(spi, &buffer, 2);
+
+    #ifdef DEBUG_VALUES
+        if (retval < 0)
+            /* should never happen, since we already checked,
+               that module is connected. Therefore no error
+               handling, just an optional error message... */
+            dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n",
+                value,
+                addr);
+        else
+            dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n",
+                value,
+                addr);
+    #endif
+
+    return retval;
+}
+
+
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
new file mode 100644
index 0000000..a6a99d4
--- /dev/null
+++ b/drivers/staging/pi433/rf69.h
@@ -0,0 +1,66 @@
+#ifndef RF69_H
+#define RF69_H
+
+#include "rf69_enum.h"
+#include "rf69_registers.h"
+
+#define F_OSC         32000000  /* in Hz */
+#define FREQUENCY    433920000 /* in Hz, modifying this value impacts CE
certification */
+#define FIFO_SIZE     66        /* in byte */
+#define FIFO_THRESHOLD    15       /* in byte */
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode);
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode);
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
+enum modulation rf69_get_modulation(struct spi_device *spi);
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping
modShaping);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_deviation(struct spi_device *spi, u32 deviation);
+int rf69_set_frequency(struct spi_device *spi, u32 frequency);
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance
antennaImpedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi);
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum
dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent
dccPercent);
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum
dccPercent dccPercent);
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8
exponent);
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse
mantisse, u8 exponent);
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType
thresholdType);
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep
thresholdStep);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement
thresholdDecrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+bool rf69_get_flag(struct spi_device *spi, enum flag flag);
+int rf69_reset_flag(struct spi_device *spi, enum flag flag);
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition
fifoFillCondition);
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance);
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat
packetFormat);
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering
addressFiltering);
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength);
+u8  rf69_get_payload_length(struct spi_device *spi);
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition
txStartCondition);
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size);
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size);
+
+u8  rf69_read_reg (struct spi_device *spi, u8 addr);
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value);
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_enum.h
b/drivers/staging/pi433/rf69_enum.h
new file mode 100644
index 0000000..7fec3b1
--- /dev/null
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -0,0 +1,186 @@
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+/* enums for configuration of the radio module */
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_registers.h
b/drivers/staging/pi433/rf69_registers.h
new file mode 100644
index 0000000..d0c4992
--- /dev/null
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -0,0 +1,489 @@
+/*
+ * register description for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*******************************************/
+/* RF69 register addresses           */
+/*******************************************/
+#define  REG_FIFO            0x00
+#define  REG_OPMODE            0x01
+#define  REG_DATAMODUL            0x02
+#define  REG_BITRATE_MSB        0x03
+#define  REG_BITRATE_LSB        0x04
+#define  REG_FDEV_MSB            0x05
+#define  REG_FDEV_LSB            0x06
+#define  REG_FRF_MSB            0x07
+#define  REG_FRF_MID            0x08
+#define  REG_FRF_LSB            0x09
+#define  REG_OSC1            0x0A
+#define  REG_AFCCTRL            0x0B
+#define  REG_LOWBAT            0x0C
+#define  REG_LISTEN1            0x0D
+#define  REG_LISTEN2            0x0E
+#define  REG_LISTEN3            0x0F
+#define  REG_VERSION            0x10
+#define  REG_PALEVEL            0x11
+#define  REG_PARAMP            0x12
+#define  REG_OCP            0x13
+#define  REG_AGCREF            0x14 /* not available on RF69 */
+#define  REG_AGCTHRESH1            0x15 /* not available on RF69 */
+#define  REG_AGCTHRESH2            0x16 /* not available on RF69 */
+#define  REG_AGCTHRESH3            0x17 /* not available on RF69 */
+#define  REG_LNA            0x18
+#define  REG_RXBW            0x19
+#define  REG_AFCBW            0x1A
+#define  REG_OOKPEAK            0x1B
+#define  REG_OOKAVG            0x1C
+#define  REG_OOKFIX            0x1D
+#define  REG_AFCFEI            0x1E
+#define  REG_AFCMSB            0x1F
+#define  REG_AFCLSB            0x20
+#define  REG_FEIMSB            0x21
+#define  REG_FEILSB            0x22
+#define  REG_RSSICONFIG            0x23
+#define  REG_RSSIVALUE            0x24
+#define  REG_DIOMAPPING1        0x25
+#define  REG_DIOMAPPING2        0x26
+#define  REG_IRQFLAGS1            0x27
+#define  REG_IRQFLAGS2            0x28
+#define  REG_RSSITHRESH            0x29
+#define  REG_RXTIMEOUT1            0x2A
+#define  REG_RXTIMEOUT2            0x2B
+#define  REG_PREAMBLE_MSB        0x2C
+#define  REG_PREAMBLE_LSB        0x2D
+#define  REG_SYNC_CONFIG        0x2E
+#define  REG_SYNCVALUE1            0x2F
+#define  REG_SYNCVALUE2            0x30
+#define  REG_SYNCVALUE3            0x31
+#define  REG_SYNCVALUE4            0x32
+#define  REG_SYNCVALUE5            0x33
+#define  REG_SYNCVALUE6            0x34
+#define  REG_SYNCVALUE7            0x35
+#define  REG_SYNCVALUE8            0x36
+#define  REG_PACKETCONFIG1        0x37
+#define  REG_PAYLOAD_LENGTH        0x38
+#define  REG_NODEADRS            0x39
+#define  REG_BROADCASTADRS        0x3A
+#define  REG_AUTOMODES            0x3B
+#define  REG_FIFO_THRESH        0x3C
+#define  REG_PACKETCONFIG2        0x3D
+#define  REG_AESKEY1            0x3E
+#define  REG_AESKEY2            0x3F
+#define  REG_AESKEY3            0x40
+#define  REG_AESKEY4            0x41
+#define  REG_AESKEY5            0x42
+#define  REG_AESKEY6            0x43
+#define  REG_AESKEY7            0x44
+#define  REG_AESKEY8            0x45
+#define  REG_AESKEY9            0x46
+#define  REG_AESKEY10            0x47
+#define  REG_AESKEY11            0x48
+#define  REG_AESKEY12            0x49
+#define  REG_AESKEY13            0x4A
+#define  REG_AESKEY14            0x4B
+#define  REG_AESKEY15            0x4C
+#define  REG_AESKEY16            0x4D
+#define  REG_TEMP1            0x4E
+#define  REG_TEMP2            0x4F
+#define  REG_TESTPA1            0x5A /* only present on RFM69HW */
+#define  REG_TESTPA2            0x5C /* only present on RFM69HW */
+#define  REG_TESTDAGC            0x6F
+
+/******************************************************/
+/* RF69/SX1231 bit definition                */
+/******************************************************/
+/* write bit */
+#define WRITE_BIT                0x80
+
+/* RegOpMode */
+#define  MASK_OPMODE_SEQUENCER_OFF        0x80
+#define  MASK_OPMODE_LISTEN_ON            0x40
+#define  MASK_OPMODE_LISTEN_ABORT        0x20
+#define  MASK_OPMODE_MODE            0x1C
+
+#define  OPMODE_MODE_SLEEP            0x00
+#define  OPMODE_MODE_STANDBY            0x04 /* default */
+#define  OPMODE_MODE_SYNTHESIZER        0x08
+#define  OPMODE_MODE_TRANSMIT            0x0C
+#define  OPMODE_MODE_RECEIVE            0x10
+
+/* RegDataModul */
+#define  MASK_DATAMODUL_MODE            0x06
+#define  MASK_DATAMODUL_MODULATION_TYPE        0x18
+#define  MASK_DATAMODUL_MODULATION_SHAPE    0x03
+
+#define  DATAMODUL_MODE_PACKET            0x00 /* default */
+#define  DATAMODUL_MODE_CONTINUOUS        0x40
+#define  DATAMODUL_MODE_CONTINUOUS_NOSYNC    0x60
+
+#define  DATAMODUL_MODULATION_TYPE_FSK        0x00 /* default */
+#define  DATAMODUL_MODULATION_TYPE_OOK        0x08
+
+#define  DATAMODUL_MODULATION_SHAPE_NONE    0x00 /* default */
+#define  DATAMODUL_MODULATION_SHAPE_1_0        0x01
+#define  DATAMODUL_MODULATION_SHAPE_0_5        0x02
+#define  DATAMODUL_MODULATION_SHAPE_0_3        0x03
+#define  DATAMODUL_MODULATION_SHAPE_BR        0x01
+#define  DATAMODUL_MODULATION_SHAPE_2BR        0x02
+
+/* RegFDevMsb (0x05)*/
+#define FDEVMASB_MASK                0x3f
+
+/*
+// RegOsc1
+#define  OSC1_RCCAL_START            0x80
+#define  OSC1_RCCAL_DONE            0x40
+
+// RegLowBat
+#define  LOWBAT_MONITOR                0x10
+#define  LOWBAT_ON                0x08
+#define  LOWBAT_OFF                0x00  // Default
+
+#define  LOWBAT_TRIM_1695            0x00
+#define  LOWBAT_TRIM_1764            0x01
+#define  LOWBAT_TRIM_1835            0x02  // Default
+#define  LOWBAT_TRIM_1905            0x03
+#define  LOWBAT_TRIM_1976            0x04
+#define  LOWBAT_TRIM_2045            0x05
+#define  LOWBAT_TRIM_2116            0x06
+#define  LOWBAT_TRIM_2185            0x07
+
+
+// RegListen1
+#define  LISTEN1_RESOL_64            0x50
+#define  LISTEN1_RESOL_4100            0xA0  // Default
+#define  LISTEN1_RESOL_262000            0xF0
+
+#define  LISTEN1_CRITERIA_RSSI            0x00  // Default
+#define  LISTEN1_CRITERIA_RSSIANDSYNC        0x08
+
+#define  LISTEN1_END_00                0x00
+#define  LISTEN1_END_01                0x02  // Default
+#define  LISTEN1_END_10                0x04
+
+
+// RegListen2
+#define  LISTEN2_COEFIDLE_VALUE            0xF5 // Default
+
+// RegListen3
+#define  LISTEN3_COEFRX_VALUE            0x20 // Default
+*/
+
+// RegPaLevel
+#define  MASK_PALEVEL_PA0            0x80
+#define  MASK_PALEVEL_PA1            0x40
+#define  MASK_PALEVEL_PA2            0x20
+#define  MASK_PALEVEL_OUTPUT_POWER        0x1F
+
+
+
+// RegPaRamp
+#define  PARAMP_3400                0x00
+#define  PARAMP_2000                0x01
+#define  PARAMP_1000                0x02
+#define  PARAMP_500                0x03
+#define  PARAMP_250                0x04
+#define  PARAMP_125                0x05
+#define  PARAMP_100                0x06
+#define  PARAMP_62                0x07
+#define  PARAMP_50                0x08
+#define  PARAMP_40                0x09 /* default */
+#define  PARAMP_31                0x0A
+#define  PARAMP_25                0x0B
+#define  PARAMP_20                0x0C
+#define  PARAMP_15                0x0D
+#define  PARAMP_12                0x0E
+#define  PARAMP_10                0x0F
+
+#define  MASK_PARAMP                0x0F
+
+/*
+// RegOcp
+#define  OCP_OFF                0x0F
+#define  OCP_ON                    0x1A  // Default
+
+#define  OCP_TRIM_45                0x00
+#define  OCP_TRIM_50                0x01
+#define  OCP_TRIM_55                0x02
+#define  OCP_TRIM_60                0x03
+#define  OCP_TRIM_65                0x04
+#define  OCP_TRIM_70                0x05
+#define  OCP_TRIM_75                0x06
+#define  OCP_TRIM_80                0x07
+#define  OCP_TRIM_85                0x08
+#define  OCP_TRIM_90                0x09
+#define  OCP_TRIM_95                0x0A
+#define  OCP_TRIM_100                0x0B  // Default
+#define  OCP_TRIM_105                0x0C
+#define  OCP_TRIM_110                0x0D
+#define  OCP_TRIM_115                0x0E
+#define  OCP_TRIM_120                0x0F
+*/
+
+/* RegLna (0x18) */
+#define  MASK_LNA_ZIN                0x80
+#define  MASK_LNA_CURRENT_GAIN            0x38
+#define  MASK_LNA_GAIN                0x07
+
+#define  LNA_GAIN_AUTO                0x00 /* default */
+#define  LNA_GAIN_MAX                0x01
+#define  LNA_GAIN_MAX_MINUS_6            0x02
+#define  LNA_GAIN_MAX_MINUS_12            0x03
+#define  LNA_GAIN_MAX_MINUS_24            0x04
+#define  LNA_GAIN_MAX_MINUS_36            0x05
+#define  LNA_GAIN_MAX_MINUS_48            0x06
+
+
+/* RegRxBw (0x19) and RegAfcBw (0x1A) */
+#define  MASK_BW_DCC_FREQ            0xE0
+#define  MASK_BW_MANTISSE            0x18
+#define  MASK_BW_EXPONENT            0x07
+
+#define  BW_DCC_16_PERCENT            0x00
+#define  BW_DCC_8_PERCENT            0x20
+#define  BW_DCC_4_PERCENT            0x40 /* default */
+#define  BW_DCC_2_PERCENT            0x60
+#define  BW_DCC_1_PERCENT            0x80
+#define  BW_DCC_0_5_PERCENT            0xA0
+#define  BW_DCC_0_25_PERCENT            0xC0
+#define  BW_DCC_0_125_PERCENT            0xE0
+
+#define  BW_MANT_16                0x00
+#define  BW_MANT_20                0x08
+#define  BW_MANT_24                0x10 /* default */
+
+
+/* RegOokPeak (0x1B) */
+#define  MASK_OOKPEAK_THRESTYPE            0xc0
+#define  MASK_OOKPEAK_THRESSTEP            0x38
+#define  MASK_OOKPEAK_THRESDEC            0x07
+
+#define  OOKPEAK_THRESHTYPE_FIXED        0x00
+#define  OOKPEAK_THRESHTYPE_PEAK        0x40 /* default */
+#define  OOKPEAK_THRESHTYPE_AVERAGE        0x80
+
+#define  OOKPEAK_THRESHSTEP_0_5_DB        0x00 /* default */
+#define  OOKPEAK_THRESHSTEP_1_0_DB        0x08
+#define  OOKPEAK_THRESHSTEP_1_5_DB        0x10
+#define  OOKPEAK_THRESHSTEP_2_0_DB        0x18
+#define  OOKPEAK_THRESHSTEP_3_0_DB        0x20
+#define  OOKPEAK_THRESHSTEP_4_0_DB        0x28
+#define  OOKPEAK_THRESHSTEP_5_0_DB        0x30
+#define  OOKPEAK_THRESHSTEP_6_0_DB        0x38
+
+#define  OOKPEAK_THRESHDEC_ONCE            0x00 /* default */
+#define  OOKPEAK_THRESHDEC_EVERY_2ND        0x01
+#define  OOKPEAK_THRESHDEC_EVERY_4TH        0x02
+#define  OOKPEAK_THRESHDEC_EVERY_8TH        0x03
+#define  OOKPEAK_THRESHDEC_TWICE        0x04
+#define  OOKPEAK_THRESHDEC_4_TIMES        0x05
+#define  OOKPEAK_THRESHDEC_8_TIMES        0x06
+#define  OOKPEAK_THRESHDEC_16_TIMES        0x07
+
+/*
+// RegOokAvg
+#define  OOKAVG_AVERAGETHRESHFILT_00        0x00
+#define  OOKAVG_AVERAGETHRESHFILT_01        0x40
+#define  OOKAVG_AVERAGETHRESHFILT_10        0x80  // Default
+#define  OOKAVG_AVERAGETHRESHFILT_11        0xC0
+
+
+// RegAfcFei
+#define  AFCFEI_FEI_DONE            0x40
+#define  AFCFEI_FEI_START            0x20
+#define  AFCFEI_AFC_DONE            0x10
+#define  AFCFEI_AFCAUTOCLEAR_ON            0x08
+#define  AFCFEI_AFCAUTOCLEAR_OFF        0x00  // Default
+
+#define  AFCFEI_AFCAUTO_ON            0x04
+#define  AFCFEI_AFCAUTO_OFF            0x00  // Default
+
+#define  AFCFEI_AFC_CLEAR            0x02
+#define  AFCFEI_AFC_START            0x01
+
+// RegRssiConfig
+#define  RSSI_FASTRX_ON                0x08
+#define  RSSI_FASTRX_OFF            0x00  // Default
+#define  RSSI_DONE                0x02
+#define  RSSI_START                0x01
+*/
+
+/* RegDioMapping1 */
+#define  MASK_DIO0                0xC0
+#define  MASK_DIO1                0x30
+#define  MASK_DIO2                0x0C
+#define  MASK_DIO3                0x03
+#define  SHIFT_DIO0                6
+#define  SHIFT_DIO1                4
+#define  SHIFT_DIO2                2
+#define  SHIFT_DIO3                0
+
+/* RegDioMapping2 */
+#define  MASK_DIO4                0xC0
+#define  MASK_DIO5                0x30
+#define  SHIFT_DIO4                6
+#define  SHIFT_DIO5                4
+
+/* DIO numbers */
+#define  DIO0                    0
+#define  DIO1                    1
+#define  DIO2                    2
+#define  DIO3                    3
+#define  DIO4                    4
+#define  DIO5                    5
+
+/* DIO Mapping values (packet mode) */
+#define  DIO_ModeReady_DIO4            0x00
+#define  DIO_ModeReady_DIO5            0x03
+#define  DIO_ClkOut                0x00
+#define  DIO_Data                0x01
+#define  DIO_TimeOut_DIO1            0x03
+#define  DIO_TimeOut_DIO4            0x00
+#define  DIO_Rssi_DIO0                0x03
+#define  DIO_Rssi_DIO3_4            0x01
+#define  DIO_RxReady                0x02
+#define  DIO_PLLLock                0x03
+#define  DIO_TxReady                0x01
+#define  DIO_FifoFull_DIO1            0x01
+#define  DIO_FifoFull_DIO3            0x00
+#define  DIO_SyncAddress            0x02
+#define  DIO_FifoNotEmpty_DIO1            0x02
+#define  DIO_FifoNotEmpty_FIO2            0x00
+#define  DIO_Automode                0x04
+#define  DIO_FifoLevel                0x00
+#define  DIO_CrcOk                0x00
+#define  DIO_PayloadReady            0x01
+#define  DIO_PacketSent                0x00
+#define  DIO_Dclk                0x00
+
+/* RegDioMapping2 CLK_OUT part */
+#define  MASK_DIOMAPPING2_CLK_OUT        0x07
+
+#define  DIOMAPPING2_CLK_OUT_NO_DIV        0x00
+#define  DIOMAPPING2_CLK_OUT_DIV_2        0x01
+#define  DIOMAPPING2_CLK_OUT_DIV_4        0x02
+#define  DIOMAPPING2_CLK_OUT_DIV_8        0x03
+#define  DIOMAPPING2_CLK_OUT_DIV_16        0x04
+#define  DIOMAPPING2_CLK_OUT_DIV_32        0x05
+#define  DIOMAPPING2_CLK_OUT_RC            0x06
+#define  DIOMAPPING2_CLK_OUT_OFF        0x07 /* default */
+
+/* RegIrqFlags1 */
+#define  MASK_IRQFLAGS1_MODE_READY        0x80
+#define  MASK_IRQFLAGS1_RX_READY        0x40
+#define  MASK_IRQFLAGS1_TX_READY        0x20
+#define  MASK_IRQFLAGS1_PLL_LOCK        0x10
+#define  MASK_IRQFLAGS1_RSSI            0x08
+#define  MASK_IRQFLAGS1_TIMEOUT            0x04
+#define  MASK_IRQFLAGS1_AUTOMODE        0x02
+#define  MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH    0x01
+
+/* RegIrqFlags2 */
+#define  MASK_IRQFLAGS2_FIFO_FULL        0x80
+#define  MASK_IRQFLAGS2_FIFO_NOT_EMPTY        0x40
+#define  MASK_IRQFLAGS2_FIFO_LEVEL        0x20
+#define  MASK_IRQFLAGS2_FIFO_OVERRUN        0x10
+#define  MASK_IRQFLAGS2_PACKET_SENT        0x08
+#define  MASK_IRQFLAGS2_PAYLOAD_READY        0x04
+#define  MASK_IRQFLAGS2_CRC_OK            0x02
+#define  MASK_IRQFLAGS2_LOW_BAT            0x01
+
+/* RegSyncConfig */
+#define  MASK_SYNC_CONFIG_SYNC_ON        0x80 /* default */
+#define  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION    0x40
+#define  MASK_SYNC_CONFIG_SYNC_SIZE        0x38
+#define  MASK_SYNC_CONFIG_SYNC_TOLERANCE    0x07
+
+/* RegPacketConfig1 */
+#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE    0x80
+#define  MASK_PACKETCONFIG1_DCFREE            0x60
+#define  MASK_PACKETCONFIG1_CRC_ON            0x10 /* default */
+#define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF        0x08
+#define  MASK_PACKETCONFIG1_ADDRESSFILTERING        0x06
+
+#define  PACKETCONFIG1_DCFREE_OFF            0x00 /* default */
+#define  PACKETCONFIG1_DCFREE_MANCHESTER        0x20
+#define  PACKETCONFIG1_DCFREE_WHITENING            0x40
+#define  PACKETCONFIG1_ADDRESSFILTERING_OFF        0x00 /* default */
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODE        0x02
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST    0x04
+
+/*
+// RegAutoModes
+#define  AUTOMODES_ENTER_OFF            0x00  // Default
+#define  AUTOMODES_ENTER_FIFONOTEMPTY        0x20
+#define  AUTOMODES_ENTER_FIFOLEVEL        0x40
+#define  AUTOMODES_ENTER_CRCOK            0x60
+#define  AUTOMODES_ENTER_PAYLOADREADY        0x80
+#define  AUTOMODES_ENTER_SYNCADRSMATCH        0xA0
+#define  AUTOMODES_ENTER_PACKETSENT        0xC0
+#define  AUTOMODES_ENTER_FIFOEMPTY        0xE0
+
+#define  AUTOMODES_EXIT_OFF            0x00  // Default
+#define  AUTOMODES_EXIT_FIFOEMPTY        0x04
+#define  AUTOMODES_EXIT_FIFOLEVEL        0x08
+#define  AUTOMODES_EXIT_CRCOK            0x0C
+#define  AUTOMODES_EXIT_PAYLOADREADY        0x10
+#define  AUTOMODES_EXIT_SYNCADRSMATCH        0x14
+#define  AUTOMODES_EXIT_PACKETSENT        0x18
+#define  AUTOMODES_EXIT_RXTIMEOUT        0x1C
+
+#define  AUTOMODES_INTERMEDIATE_SLEEP        0x00  // Default
+#define  AUTOMODES_INTERMEDIATE_STANDBY        0x01
+#define  AUTOMODES_INTERMEDIATE_RECEIVER    0x02
+#define  AUTOMODES_INTERMEDIATE_TRANSMITTER    0x03
+
+*/
+/* RegFifoThresh (0x3c) */
+#define  MASK_FIFO_THRESH_TXSTART        0x80
+#define  MASK_FIFO_THRESH_VALUE            0x7F
+
+/*
+
+// RegPacketConfig2
+#define  PACKET2_RXRESTARTDELAY_1BIT        0x00  // Default
+#define  PACKET2_RXRESTARTDELAY_2BITS        0x10
+#define  PACKET2_RXRESTARTDELAY_4BITS        0x20
+#define  PACKET2_RXRESTARTDELAY_8BITS        0x30
+#define  PACKET2_RXRESTARTDELAY_16BITS        0x40
+#define  PACKET2_RXRESTARTDELAY_32BITS        0x50
+#define  PACKET2_RXRESTARTDELAY_64BITS        0x60
+#define  PACKET2_RXRESTARTDELAY_128BITS        0x70
+#define  PACKET2_RXRESTARTDELAY_256BITS        0x80
+#define  PACKET2_RXRESTARTDELAY_512BITS        0x90
+#define  PACKET2_RXRESTARTDELAY_1024BITS    0xA0
+#define  PACKET2_RXRESTARTDELAY_2048BITS    0xB0
+#define  PACKET2_RXRESTARTDELAY_NONE        0xC0
+#define  PACKET2_RXRESTART            0x04
+
+#define  PACKET2_AUTORXRESTART_ON        0x02  // Default
+#define  PACKET2_AUTORXRESTART_OFF        0x00
+
+#define  PACKET2_AES_ON                0x01
+#define  PACKET2_AES_OFF            0x00  // Default
+
+
+// RegTemp1
+#define  TEMP1_MEAS_START            0x08
+#define  TEMP1_MEAS_RUNNING            0x04
+#define  TEMP1_ADCLOWPOWER_ON            0x01  // Default
+#define  TEMP1_ADCLOWPOWER_OFF            0x00
+*/
+
+// RegTestDagc (0x6F)
+#define  DAGC_NORMAL                0x00 /* Reset value */
+#define  DAGC_IMPROVED_LOWBETA1            0x20
+#define  DAGC_IMPROVED_LOWBETA0            0x30 /* Recommended val */
--
1.7.10.4


>From 911beb40ba0f7a0809e4f51eb9835e48ae6639ce Mon Sep 17 00:00:00 2001
From: Marcus Wolf <linux@Wolf-Entwicklungen.de>
Date: Sat, 8 Jul 2017 17:14:37 +0100
Subject: [PATCH 2/3] several enhancements regarding codingstyle, warnings and
 stability

---
 drivers/staging/pi433/Kconfig     |   11 ++++-
 drivers/staging/pi433/pi433_if.c  |   99 ++++++++++++++++++++++---------------
 drivers/staging/pi433/pi433_if.h  |   15 +++++-
 drivers/staging/pi433/rf69.h      |   16 ++++++
 drivers/staging/pi433/rf69_enum.h |   19 ++++++-
 5 files changed, 115 insertions(+), 45 deletions(-)

diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
index a0b1bea..61b4b4e 100644
--- a/drivers/staging/pi433/Kconfig
+++ b/drivers/staging/pi433/Kconfig
@@ -4,4 +4,13 @@ config PI433
         ---help---
           This option allows you to enable support for the radio module Pi433.
 
-          If in doubt, say N here.
+          Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi
+          or compatible. It extends the Raspberry Pi with the option, to
+          send and receive data in the 433MHz ISM band - for example to
+          communicate between two systems without using ethernet or bluetooth
+          or for control or read sockets, actors, sensors, widely available
+          for low price.
+
+          For details or the option to buy, please visit
https://pi433.de/en.html
+
+          If in doubt, say N here, but saying yes most probably won't hurt
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
index f7fbd08..57edf91 100644
--- a/drivers/staging/pi433/pi433_if.c
+++ b/drivers/staging/pi433/pi433_if.c
@@ -1,6 +1,16 @@
 /*
  * userspace interface for pi433 radio module
  *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ *
  * Copyright (C) 2016 Wolf-Entwicklungen
  *    Marcus Wolf <linux@wolf-entwicklungen.de>
  *
@@ -15,7 +25,7 @@
  * GNU General Public License for more details.
  */
 
-#define DEBUG
+#undef DEBUG
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -37,13 +47,16 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/spi/spi.h>
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+#endif
 
 #include "pi433_if.h"
 #include "rf69.h"
 
 
 #define N_PI433_MINORS            (1U << MINORBITS) /*32*/    /* ... up to 256
*/
-#define MAX_MSG_SIZE            900
+#define MAX_MSG_SIZE            900    /* min: FIFO_SIZE! */
 #define MSG_FIFO_SIZE            65536   /* 65536 = 2^16  */
 #define NUM_DIO                2
 
@@ -53,7 +66,7 @@
 
 static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
 
-/* tx config is instance specific
+/* tx config is instance specific
     so with each open a new tx config struct is needed */
 /* rx config is device specific
     so we have just one rx config, ebedded in device struct */
@@ -73,7 +86,7 @@ struct pi433_device {
 
     /* tx related values */
     STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
-    struct mutex        tx_fifo_lock;
+    struct mutex        tx_fifo_lock; // TODO: check, whether necessary or
obsolete
     struct task_struct    *tx_task_struct;
     wait_queue_head_t    tx_wait_queue;
     u8            free_in_fifo;
@@ -103,11 +116,6 @@ struct pi433_instance {
     struct pi433_tx_cfg    tx_cfg;
 };
 
-// TODO: folgende Zeilen benötigt?
-static unsigned bufsiz = 4096;
-module_param(bufsiz, uint, S_IRUGO);
-MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI msg");
-
 /*-------------------------------------------------------------------------*/
 
 /* macro for checked access of registers of radio module */
@@ -203,7 +211,7 @@ struct pi433_instance {
     SET_CHECKED(rf69_set_packet_format  (dev->spi,
rx_cfg->enable_length_byte));
     SET_CHECKED(rf69_set_adressFiltering(dev->spi,
rx_cfg->enable_address_filtering));
     SET_CHECKED(rf69_set_crc_enable        (dev->spi, rx_cfg->enable_crc));
-    
+
     /* lengths */
     SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
     if (rx_cfg->enable_length_byte == optionOn)
@@ -221,7 +229,7 @@ struct pi433_instance {
     {
         SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
     }
-    
+
     /* values */
     if (rx_cfg->enable_sync == optionOn)
     {
@@ -251,7 +259,7 @@ struct pi433_instance {
     if (tx_cfg->enable_preamble == optionOn)
     {
         SET_CHECKED(rf69_set_preamble_length(dev->spi,
tx_cfg->preamble_length));
-    }    
+    }
     else
     {
         SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
@@ -259,7 +267,7 @@ struct pi433_instance {
     SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
     SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
     SET_CHECKED(rf69_set_crc_enable      (dev->spi, tx_cfg->enable_crc));
-    
+
     /* configure sync, if enabled */
     if (tx_cfg->enable_sync == optionOn)
     {
@@ -461,7 +469,7 @@ struct pi433_instance {
     struct pi433_device *device = data;
     struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
     struct pi433_tx_cfg tx_cfg;
-    u8     buffer[MAX_MSG_SIZE];    
+    u8     buffer[MAX_MSG_SIZE];
     size_t size;
     bool   rx_interrupted = false;
     int    position, repetitions;
@@ -486,7 +494,7 @@ struct pi433_instance {
         retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
         if (retval != sizeof(tx_cfg))
         {
-            dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d
byte(s), expected %d", retval, sizeof(tx_cfg) );
+            dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d
byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) );
             mutex_unlock(&device->tx_fifo_lock);
             continue;
         }
@@ -494,7 +502,7 @@ struct pi433_instance {
         retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
         if (retval != sizeof(size_t))
         {
-            dev_dbg(device->dev, "reading msg size from fifo failed: got %d,
expected %d", retval, sizeof(size_t) );
+            dev_dbg(device->dev, "reading msg size from fifo failed: got %d,
expected %d", retval, (unsigned int)sizeof(size_t) );
             mutex_unlock(&device->tx_fifo_lock);
             continue;
         }
@@ -528,17 +536,19 @@ struct pi433_instance {
         dev_dbg(device->dev, "read %d message byte(s) from fifo queue.",
retval);
         mutex_unlock(&device->tx_fifo_lock);
 
-        /* if rx is active, we need to interrupt the waiting for
-           incoming telegrams, to be able to send something.
-           We are only allowed, if currently no reception takes
-           place otherwise we need to  wait for the incoming telegram
+        /* if rx is active, we need to interrupt the waiting for
+           incoming telegrams, to be able to send something.
+           We are only allowed, if currently no reception takes
+           place otherwise we need to  wait for the incoming telegram
            to finish */
-        disable_irq(device->irq_num[DIO0]); /* prevent race conditions */
         wait_event_interruptible(device->tx_wait_queue,
                      !device->rx_active ||
                       device->interrupt_rx_allowed == true);
+
+        /* prevent race conditions
+           irq will be reenabled after tx config is set */
+        disable_irq(device->irq_num[DIO0]);
         device->tx_active = true;
-        /* irq will be reenabled after config to packet sent */
 
         if (device->rx_active && rx_interrupted == false)
         {
@@ -573,7 +583,7 @@ struct pi433_instance {
         device->irq_state[DIO0] = DIO_PacketSent;
         irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
         enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check
*/
-        
+
         /* enable transmission */
         SET_CHECKED(rf69_set_mode(spi, transmit));
 
@@ -588,7 +598,7 @@ struct pi433_instance {
                 int temp = device->free_in_fifo;
                 device->free_in_fifo = 0;
                 rf69_write_fifo(spi,
-                                &buffer[position],
+                                &buffer[position],
                                 temp);
                 position +=temp;
             }
@@ -597,7 +607,7 @@ struct pi433_instance {
                 device->free_in_fifo -= size;
                 repetitions--;
                 rf69_write_fifo(spi,
-                        &buffer[position],
+                        &buffer[position],
                         (size - position) );
                 position = 0; /* reset for next repetition */
             }
@@ -609,7 +619,7 @@ struct pi433_instance {
 
         /* we are done. Wait for packet to get sent */
         dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be
empty");
-        wait_event_interruptible(device->fifo_wait_queue,
+        wait_event_interruptible(device->fifo_wait_queue,
                      device->free_in_fifo == FIFO_SIZE ||
                      kthread_should_stop() );
         if ( kthread_should_stop() )    printk("ABORT\n");
@@ -645,7 +655,7 @@ struct pi433_instance {
     ssize_t            retval;
 
     /* check, whether internal buffer is big enough for requested size */
-    if (size > bufsiz)
+    if (size > MAX_MSG_SIZE)
         return -EMSGSIZE;
 
     instance = filp->private_data;
@@ -697,6 +707,10 @@ struct pi433_instance {
     instance = filp->private_data;
     device = instance->device;
 
+    /* check, whether internal buffer (tx thread) is big enough for requested
size */
+    if (count > MAX_MSG_SIZE)
+        return -EMSGSIZE;
+
     /* write the following sequence into fifo:
        - tx_cfg
        - size of message
@@ -724,7 +738,7 @@ struct pi433_instance {
 
 abort:
     dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
-    kfifo_reset(&device->tx_fifo);
+    kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to
discard already stored, valid entries
     mutex_unlock(&device->tx_fifo_lock);
     return -EAGAIN;
 }
@@ -771,15 +785,15 @@ struct pi433_instance {
     switch (cmd) {
     case PI433_IOC_RD_TX_CFG:
         tmp = _IOC_SIZE(cmd);
-        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
         {
             retval = -EINVAL;
             break;
         }
 
         if (__copy_to_user((void __user *)arg,
-                    &instance->tx_cfg,
-                    tmp))
+                    &instance->tx_cfg,
+                    tmp))
         {
             retval = -EFAULT;
             break;
@@ -788,7 +802,7 @@ struct pi433_instance {
         break;
     case PI433_IOC_WR_TX_CFG:
         tmp = _IOC_SIZE(cmd);
-        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
         {
             retval = -EINVAL;
             break;
@@ -796,7 +810,7 @@ struct pi433_instance {
 
         if (__copy_from_user(&instance->tx_cfg,
                      (void __user *)arg,
-                     tmp))
+                     tmp))
         {
             retval = -EFAULT;
             break;
@@ -813,7 +827,7 @@ struct pi433_instance {
 
         if (__copy_to_user((void __user *)arg,
                    &device->rx_cfg,
-                   tmp))
+                   tmp))
         {
             retval = -EFAULT;
             break;
@@ -839,7 +853,7 @@ struct pi433_instance {
 
         if (__copy_from_user(&device->rx_cfg,
                      (void __user *)arg,
-                     tmp))
+                     tmp))
         {
             retval = -EFAULT;
             mutex_unlock(&device->rx_lock);
@@ -882,7 +896,7 @@ static int pi433_open(struct inode *inode, struct file
*filp)
     }
 
     if (!device->rx_buffer) {
-        device->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);
+        device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL);
         if (!device->rx_buffer)
         {
             dev_dbg(device->dev, "open/ENOMEM\n");
@@ -990,7 +1004,7 @@ static int setup_GPIOs(struct pi433_device *device)
                      name,
                      device);
 
-        if (retval)
+        if (retval)
             return retval;
 
         dev_dbg(&device->spi->dev, "%s succesfully configured", name);
@@ -1074,8 +1088,8 @@ static int pi433_probe(struct spi_device *spi)
         return retval;
     }
     else
-    {    
-        dev_dbg(&spi->dev,
+    {
+        dev_dbg(&spi->dev,
             "spi interface setup: mode 0x%2x, %d bits per word, %dhz max
speed",
             spi->mode, spi->bits_per_word, spi->max_speed_hz);
     }
@@ -1227,7 +1241,7 @@ static int pi433_remove(struct spi_device *spi)
 }
 
 static const struct of_device_id pi433_dt_ids[] = {
-    { .compatible = "pi433" }, // TODO: DT compatible string "pi433" appears
un-documented -- check ./Documentation/devicetree/bindings/
+    { .compatible = "Smarthome-Wolf,pi433" },
     {},
 };
 
@@ -1255,6 +1269,11 @@ static int __init pi433_init(void)
 {
     int status;
 
+    /* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't
+           work stable - risk of buffer overflow */
+    if (MAX_MSG_SIZE < FIFO_SIZE)
+        return -EINVAL;
+
     /* Claim device numbers.  Then register a class
      * that will key udev/mdev to add/remove /dev nodes.  Last, register
      * Last, register the driver which manages those device numbers.
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
index a87c73c..e6ed3cd 100644
--- a/drivers/staging/pi433/pi433_if.h
+++ b/drivers/staging/pi433/pi433_if.h
@@ -1,6 +1,17 @@
 /*
  * include/linux/TODO
  *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
  * Copyright (C) 2016 Wolf-Entwicklungen
  *    Marcus Wolf <linux@wolf-entwicklungen.de>
  *
@@ -86,7 +97,7 @@ struct pi433_tx_cfg
  * @data_mode:
  * @preamble_length:
  * @sync_pattern:
- * @tx_start_condition:
+ * @tx_start_condition:
  * @payload_length:
  * @repetitions:
  *
@@ -103,7 +114,7 @@ struct pi433_rx_cfg {
     __u32            dev_frequency;
 
     enum modulation        modulation;
-    
+
     __u8            rssi_threshold;
     enum thresholdDecrement    thresholdDecrement;
     enum antennaImpedance    antenna_impedance;
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
index a6a99d4..6a6841b 100644
--- a/drivers/staging/pi433/rf69.h
+++ b/drivers/staging/pi433/rf69.h
@@ -1,3 +1,19 @@
+/*
+ * hardware abstraction/register access for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
 #ifndef RF69_H
 #define RF69_H
 
diff --git a/drivers/staging/pi433/rf69_enum.h
b/drivers/staging/pi433/rf69_enum.h
index 7fec3b1..fbfb59b 100644
--- a/drivers/staging/pi433/rf69_enum.h
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -1,8 +1,23 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
 #ifndef RF69_ENUM_H
 #define RF69_ENUM_H
 
-/* enums for configuration of the radio module */
-
 enum optionOnOff
 {
     optionOff,
--
1.7.10.4


>From 25a879e23cdb83b6e6a4ec557dab66390abb16af Mon Sep 17 00:00:00 2001
From: Marcus Wolf <linux@wolf-entwicklungen.de>
Date: Mon, 10 Jul 2017 18:24:59 +0100
Subject: [PATCH 3/3] moved headers related to ioctl to
 include/uapi/linux/pi433

---
 drivers/staging/pi433/pi433_if.c     |    2 +-
 drivers/staging/pi433/pi433_if.h     |  152 -------------------------
 drivers/staging/pi433/rf69.h         |    2 +-
 drivers/staging/pi433/rf69_enum.h    |  201 ----------------------------------
 include/uapi/linux/pi433/pi433.h     |  152 +++++++++++++++++++++++++
 include/uapi/linux/pi433/rf69_enum.h |  201 ++++++++++++++++++++++++++++++++++
 6 files changed, 355 insertions(+), 355 deletions(-)
 delete mode 100644 drivers/staging/pi433/pi433_if.h
 delete mode 100644 drivers/staging/pi433/rf69_enum.h
 create mode 100644 include/uapi/linux/pi433/pi433.h
 create mode 100644 include/uapi/linux/pi433/rf69_enum.h

diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
index 57edf91..a31eed7 100644
--- a/drivers/staging/pi433/pi433_if.c
+++ b/drivers/staging/pi433/pi433_if.c
@@ -51,7 +51,7 @@
 #include <asm/compat.h>
 #endif
 
-#include "pi433_if.h"
+#include <linux/pi433/pi433.h>
 #include "rf69.h"
 
 
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
deleted file mode 100644
index e6ed3cd..0000000
--- a/drivers/staging/pi433/pi433_if.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * include/linux/TODO
- *
- * userspace interface for pi433 radio module
- *
- * Pi433 is a 433MHz radio module for the Raspberry Pi.
- * It is based on the HopeRf Module RFM69CW. Therefore inside of this
- * driver, you'll find an abstraction of the rf69 chip.
- *
- * If needed, this driver could be extended, to also support other
- * devices, basing on HopeRfs rf69.
- *
- * The driver can also be extended, to support other modules of
- * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
- * Copyright (C) 2016 Wolf-Entwicklungen
- *    Marcus Wolf <linux@wolf-entwicklungen.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef PI433_H
-#define PI433_H
-
-#include <linux/types.h>
-#include "rf69_enum.h"
-
-/*---------------------------------------------------------------------------*/
-
-
-/*---------------------------------------------------------------------------*/
-
-/* IOCTL structs and commands */
-
-/**
- * struct pi433_tx_config - describes the configuration of the radio module for
sending
- * @frequency:
- * @bit_rate:
- * @modulation:
- * @data_mode:
- * @preamble_length:
- * @sync_pattern:
- * @tx_start_condition:
- * @payload_length:
- * @repetitions:
- *
- * ATTENTION:
- * If the contents of 'pi433_tx_config' ever change
- * incompatibly, then the ioctl number (see define below) must change.
- *
- * NOTE: struct layout is the same in 64bit and 32bit userspace.
- */
-#define PI433_TX_CFG_IOCTL_NR     0
-struct pi433_tx_cfg
-{
-    __u32            frequency;
-    __u16            bit_rate;
-    __u32            dev_frequency;
-    enum modulation        modulation;
-    enum modShaping        modShaping;
-
-    enum paRamp        pa_ramp;
-
-    enum txStartCondition    tx_start_condition;
-
-    __u16            repetitions;
-
-
-    /* packet format */
-    enum optionOnOff    enable_preamble;
-    enum optionOnOff    enable_sync;
-    enum optionOnOff    enable_length_byte;
-    enum optionOnOff    enable_address_byte;
-    enum optionOnOff    enable_crc;
-
-    __u16            preamble_length;
-    __u8            sync_length;
-    __u8            fixed_message_length;
-
-    __u8            sync_pattern[8];
-    __u8            address_byte;
-};
-
-
-/**
- * struct pi433_rx_config - describes the configuration of the radio module for
sending
- * @frequency:
- * @bit_rate:
- * @modulation:
- * @data_mode:
- * @preamble_length:
- * @sync_pattern:
- * @tx_start_condition:
- * @payload_length:
- * @repetitions:
- *
- * ATTENTION:
- * If the contents of 'pi433_rx_config' ever change
- * incompatibly, then the ioctl number (see define below) must change
- *
- * NOTE: struct layout is the same in 64bit and 32bit userspace.
- */
-#define PI433_RX_CFG_IOCTL_NR     1
-struct pi433_rx_cfg {
-    __u32            frequency;
-    __u16            bit_rate;
-    __u32            dev_frequency;
-
-    enum modulation        modulation;
-
-    __u8            rssi_threshold;
-    enum thresholdDecrement    thresholdDecrement;
-    enum antennaImpedance    antenna_impedance;
-    enum lnaGain        lna_gain;
-    enum mantisse        bw_mantisse;    /* normal: 0x50 */
-    __u8            bw_exponent;    /* during AFC: 0x8b */
-    enum dagc        dagc;
-
-
-
-    /* packet format */
-    enum optionOnOff    enable_sync;
-    enum optionOnOff    enable_length_byte;      /* should be used in
combination with sync, only */
-    enum addressFiltering    enable_address_filtering; /* operational with
sync, only */
-    enum optionOnOff    enable_crc;          /* only operational, if sync on
and fixed length or length byte is used */
-
-    __u8            sync_length;
-    __u8            fixed_message_length;
-    __u32            bytes_to_drop;
-
-    __u8            sync_pattern[8];
-    __u8            node_address;
-    __u8            broadcast_address;
-};
-
-
-#define PI433_IOC_MAGIC            'r'
-
-#define PI433_IOC_RD_TX_CFG    _IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
-#define PI433_IOC_WR_TX_CFG    _IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
-
-#define PI433_IOC_RD_RX_CFG    _IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
-#define PI433_IOC_WR_RX_CFG    _IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
-
-#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
index 6a6841b..eb493e2 100644
--- a/drivers/staging/pi433/rf69.h
+++ b/drivers/staging/pi433/rf69.h
@@ -17,7 +17,7 @@
 #ifndef RF69_H
 #define RF69_H
 
-#include "rf69_enum.h"
+#include <linux/pi433/rf69_enum.h>
 #include "rf69_registers.h"
 
 #define F_OSC         32000000  /* in Hz */
diff --git a/drivers/staging/pi433/rf69_enum.h
b/drivers/staging/pi433/rf69_enum.h
deleted file mode 100644
index fbfb59b..0000000
--- a/drivers/staging/pi433/rf69_enum.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * enumerations for HopeRf rf69 radio module
- *
- * Copyright (C) 2016 Wolf-Entwicklungen
- *    Marcus Wolf <linux@wolf-entwicklungen.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef RF69_ENUM_H
-#define RF69_ENUM_H
-
-enum optionOnOff
-{
-    optionOff,
-    optionOn
-};
-
-enum mode
-{
-    mode_sleep,
-    standby,
-    synthesizer,
-    transmit,
-    receive
-};
-
-enum dataMode
-{
-    packet,
-    continuous,
-    continuousNoSync
-};
-
-enum modulation
-{
-    OOK,
-    FSK
-};
-
-enum modShaping
-{
-    shapingOff,
-    shaping1_0,
-    shaping0_5,
-    shaping0_3,
-    shapingBR,
-    shaping2BR
-};
-
-enum paRamp
-{
-    ramp3400,
-    ramp2000,
-    ramp1000,
-    ramp500,
-    ramp250,
-    ramp125,
-    ramp100,
-    ramp62,
-    ramp50,
-    ramp40,
-    ramp31,
-    ramp25,
-    ramp20,
-    ramp15,
-    ramp12,
-    ramp10
-};
-
-enum antennaImpedance
-{
-    fiftyOhm,
-    twohundretOhm
-};
-
-enum lnaGain
-{
-    automatic,
-    max,
-    maxMinus6,
-    maxMinus12,
-    maxMinus24,
-    maxMinus36,
-    maxMinus48,
-    undefined
-};
-
-enum dccPercent
-{
-    dcc16Percent,
-    dcc8Percent,
-    dcc4Percent,
-    dcc2Percent,
-    dcc1Percent,
-    dcc0_5Percent,
-    dcc0_25Percent,
-    dcc0_125Percent
-};
-
-enum mantisse
-{
-    mantisse16,
-    mantisse20,
-    mantisse24
-};
-
-enum thresholdType
-{
-    fixed,
-    peak,
-    average
-};
-
-enum thresholdStep
-{
-    step_0_5db,
-    step_1_0db,
-    step_1_5db,
-    step_2_0db,
-    step_3_0db,
-    step_4_0db,
-    step_5_0db,
-    step_6_0db
-};
-
-enum thresholdDecrement
-{
-    dec_every8th,
-    dec_every4th,
-    dec_every2nd,
-    dec_once,
-    dec_twice,
-    dec_4times,
-    dec_8times,
-    dec_16times
-};
-
-enum flag
-{
-    modeSwitchCompleted,
-    readyToReceive,
-    readyToSend,
-    pllLocked,
-    rssiExceededThreshold,
-    timeout,
-    automode,
-    syncAddressMatch,
-    fifoFull,
-//    fifoNotEmpty, collision with next enum; replaced by following enum...
-    fifoEmpty,
-    fifoLevelBelowThreshold,
-    fifoOverrun,
-    packetSent,
-    payloadReady,
-    crcOk,
-    batteryLow
-};
-
-enum fifoFillCondition
-{
-    afterSyncInterrupt,
-    always
-};
-
-enum packetFormat
-{
-    packetLengthFix,
-    packetLengthVar
-};
-
-enum txStartCondition
-{
-    fifoLevel,
-    fifoNotEmpty
-};
-
-enum addressFiltering
-{
-    filteringOff,
-    nodeAddress,
-    nodeOrBroadcastAddress
-};
-
-enum dagc
-{
-    normalMode,
-    improve,
-    improve4LowModulationIndex
-};
-
-
-#endif
diff --git a/include/uapi/linux/pi433/pi433.h b/include/uapi/linux/pi433/pi433.h
new file mode 100644
index 0000000..451c9b6
--- /dev/null
+++ b/include/uapi/linux/pi433/pi433.h
@@ -0,0 +1,152 @@
+/*
+ * include/uapi/linux/pi433
+ *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR     0
+struct pi433_tx_cfg
+{
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+    enum modulation        modulation;
+    enum modShaping        modShaping;
+
+    enum paRamp        pa_ramp;
+
+    enum txStartCondition    tx_start_condition;
+
+    __u16            repetitions;
+
+
+    /* packet format */
+    enum optionOnOff    enable_preamble;
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;
+    enum optionOnOff    enable_address_byte;
+    enum optionOnOff    enable_crc;
+
+    __u16            preamble_length;
+    __u8            sync_length;
+    __u8            fixed_message_length;
+
+    __u8            sync_pattern[8];
+    __u8            address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR     1
+struct pi433_rx_cfg {
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+
+    enum modulation        modulation;
+
+    __u8            rssi_threshold;
+    enum thresholdDecrement    thresholdDecrement;
+    enum antennaImpedance    antenna_impedance;
+    enum lnaGain        lna_gain;
+    enum mantisse        bw_mantisse;    /* normal: 0x50 */
+    __u8            bw_exponent;    /* during AFC: 0x8b */
+    enum dagc        dagc;
+
+
+
+    /* packet format */
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;      /* should be used in
combination with sync, only */
+    enum addressFiltering    enable_address_filtering; /* operational with
sync, only */
+    enum optionOnOff    enable_crc;          /* only operational, if sync on
and fixed length or length byte is used */
+
+    __u8            sync_length;
+    __u8            fixed_message_length;
+    __u32            bytes_to_drop;
+
+    __u8            sync_pattern[8];
+    __u8            node_address;
+    __u8            broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC            'r'
+
+#define PI433_IOC_RD_TX_CFG    _IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG    _IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG    _IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG    _IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/include/uapi/linux/pi433/rf69_enum.h
b/include/uapi/linux/pi433/rf69_enum.h
new file mode 100644
index 0000000..fbfb59b
--- /dev/null
+++ b/include/uapi/linux/pi433/rf69_enum.h
@@ -0,0 +1,201 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
--
1.7.10.4


 

[-- Attachment #2: Type: text/html, Size: 277438 bytes --]

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
  2017-07-11 16:02 Submit of a driver for Pi433 - a radio module for Raspberry Pi Marcus Wolf
@ 2017-07-12  7:43 ` Greg KH
  2017-07-15 11:15   ` Marcus Wolf
  0 siblings, 1 reply; 49+ messages in thread
From: Greg KH @ 2017-07-12  7:43 UTC (permalink / raw)
  To: Marcus Wolf; +Cc: grant.likely, robh+dt, linux-kernel, devel, devicetree

On Tue, Jul 11, 2017 at 06:02:09PM +0200, Marcus Wolf wrote:
> Hi folks,
> 
> I developed a radio shield for the 433MHz ISM band [0] for the Raspberry Pi.
> This shield is called Pi433 [1]. It can be used to communicate between two
> Raspberries or to control third party equipment e. g. cheap radio sockets [2].
> The base of this radio shield is a radio module from HopeRf - a rfm69cw-433s2.
>  
> In the beginning, I conrolled the rf69 chip by direct access via SPI, but I
> figured out, that several tasks were hard to handle. Especially the following
> points were annoying:
> * Just one process could open the SPI interface so just one process was
>   able to access the module
> * A simultaneous send and receive was very hard to implement
> 
> Therefore I started to implement a driver.
> The drivers features:
> * simple access/nice abstraction of spi registers via open, close,
>   read, write and ioctl
> * multiple applications can open
> * tx requests are queued, so every app can send a tx request at any time
> * first app asking for rx will block other apps, also asking for rx until one
> rx
>   cycle is complete
> * rx cycle means listening on the air until something appears
> * if an app wants to tx during the driver is waiting in rx cycle, rx will be
>   shortly interrupted to do the tx task
> * for each tx task a seperate configuration of the rf chip (bitrate,
> modulation, ...)
>   can be chosen
> * wrtten in modular architecture, allowing to extend for other products with
>   rf69 chip (e.g. rfm69hcw, ...) or even to support other HopeRf chips with
> similar
>   interface (e. g. rfm12, rfm95, ...)
>  
> In principle the driver was intended to be used by my project (Smarthome-Pi),
> only.
> But while having all this nice features, I was asked, whether I could offer the
> driver to the community. I never did that before, so I started reading about
> submitting drivers and figured out, that there is a lot of work to do, to meet
> all
> concepts and ideas of complying to kernel code. I spend some days and modified
> a lot, but still, a lot of things aren't perfect.
> Already known tasks are:
> 
> * coding style does not fully comply with the kernel style guide.
> * still TODOs, annotated in the code
> * currently the code introduces new IOCTLs. I'm afraid this is a bad idea.
>   Replace this with another interface, hints are welcome!
>  
> I tested the patch on Raspbian with Kernel v4.12 and applied the patch on
> mainline Linux v4.12
>  
> Is it posibble to integrate into the staging area to ease further development?

Sure, I'm always glad to take new drivers, but can you submit it as just
a single patch, and keep it self-contained (i.e. nothing outside of
drivers/staging/YOUR_DRIVER/)?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
  2017-07-12  7:43 ` Greg KH
@ 2017-07-15 11:15   ` Marcus Wolf
  2017-07-15 11:24       ` Greg KH
  0 siblings, 1 reply; 49+ messages in thread
From: Marcus Wolf @ 2017-07-15 11:15 UTC (permalink / raw)
  To: Greg KH; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

[-- Attachment #1: Type: text/plain, Size: 134199 bytes --]

Hi Greg,
 
thanks for your reply :-)
 
Today I moved the documentation and header files to drivers/staging/pi433 and
fromated it as a single patch.
 
Cheers,
 
Marcus
 
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 268d4e6..fdf060c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"
 
 source "drivers/staging/typec/Kconfig"
 
+source "drivers/staging/pi433/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b93e6f5..998f644 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)        += ks7010/
 obj-$(CONFIG_GREYBUS)        += greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)    += vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)    += ccree/
+obj-$(CONFIG_PI433)        += pi433/
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
new file mode 100644
index 0000000..004b502
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
@@ -0,0 +1,53 @@
+// Definitions for Pi433
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+    fragment@1 {
+        target = <&gpio>;
+        __overlay__ {
+            pi433_pins: pi433_pins {
+                brcm,pins = <7 25 24>;
+                brcm,function = <0 0 0>; // in in in
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&spi0>;
+        __overlay__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            status = "okay";
+
+            pi433: pi433@0 {
+                compatible = "Smarthome-Wolf,pi433";
+                reg = <0>;
+                spi-max-frequency = <10000000>;
+                status = "okay";
+
+                pinctrl-0 = <&pi433_pins>;
+                DIO0-gpio = <&gpio 24 0>;
+                DIO1-gpio = <&gpio 25 0>;
+                DIO2-gpio = <&gpio  7 0>;
+            };
+        };
+    };
+};
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt
b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
new file mode 100644
index 0000000..14197c6
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
@@ -0,0 +1,62 @@
+* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see
www.pi433.de)
+
+Required properties:
+- compatible: must be "Smarthome-Wolf,pi433"
+- reg: chip select of SPI Interface
+- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69
module
+
+
+Example:
+
+With the following lines in gpio-section, the gpio pins, connected with pi433
are
+reserved/declared.
+
+&gpio{
+    [...]
+
+    pi433_pins: pi433_pins {
+        brcm,pins = <7 25 24>;
+        brcm,function = <0 0 0>; // in in in
+    };
+
+    [...]
+}
+
+With the following lines in spi section, the device pi433 is declared.
+It consists of the three gpio pins and an spi interface (here chip select 0)
+
+&spi0{
+    [...]
+
+    pi433: pi433@0 {
+        compatible = "Smarthome-Wolf,pi433";
+        reg = <0>; /* CE 0 */
+        #address-cells = <1>;
+        #size-cells = <0>;
+        spi-max-frequency = <10000000>;
+
+        pinctrl-0 = <&pi433_pins>;
+        DIO0-gpio = <&gpio 24 0>;
+        DIO1-gpio = <&gpio 25 0>;
+        DIO2-gpio = <&gpio  7 0>;
+    };
+}
+
+
+
+For Raspbian users only
+=======================
+Since Raspbian supports device tree overlays, you may use and overlay, instead
+of editing your boards device tree.
+For using the overlay, you need to compile the file pi433-overlay.dts you can
+find aside to this documentation.
+The file needs to be compiled - either manually or by integration in your
kernel
+source tree. For a manual compile, you may use a command line like the
following:
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+arch/arm/boot/dts/overlays and you need to add the file to the list of files
+in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
+kernel make files compile the device tree overlay for you.
+
+
diff --git a/drivers/staging/pi433/Documentation/pi433.txt
b/drivers/staging/pi433/Documentation/pi433.txt
new file mode 100644
index 0000000..860dd0f
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -0,0 +1,274 @@
+=====
+Pi433
+=====
+
+
+Introduction
+============
+This driver is for controlling pi433, a radio module for the Raspberry Pi
+(www.pi433.de). It supports transmission and reception. It can be opened
+by multiple applications for transmission and reception. While transmit
+jobs were queued and process automatically in the background, the first  
+application asking for reception will block out all other applications  
+until something gets received terminates the read request.  
+The driver supports on the fly reloading of the hardware fifo of the rf
+chip, thus enabling for much longer telegrams then hardware fifo size.
+
+Discription of driver operation
+===============================
+
+a) transmission
+
+Each transmission can take place with a different configuration of the rf
+module. Therfore each application can set its own set of parameters. The driver
+takes care, that each transmission takes place with the parameterset of the
+application, that requests the transmission. To allow the transmission to take
+place in the background, a tx thread is introduced.
+The transfer of data from the main thread to the tx thread is realised by a
+kfifo. With each write request of an application, the passed in data and the
+corresponding parameter set gets written to the kfifo.  
+On the other "side" of the kfifo, the tx thread continuously checks, whether
the
+kfifo is empty. If not, it gets one set of config and data from the kfifo. If  
+there is no receive request or the receiver is still waiting for something in
+the air, the rf module is set to standby, the parameters for transmission gets
+set, the hardware fifo of the rf chip gets preloaded and the transmission gets
+started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling
+much longer telegrams then hardware fifo size. If the telegram is send and
there
+is more data available in the kfifo, the procedure is repeated. If not the
+transmission cycle ends.
+
+b) reception
+
+Since there is only one application allowed to receive data at a time, for
+reception there is only one configuration set.
+As soon as an application sets an request for receiving a telegram, the
reception
+configuration set is written to the rf module and it gets set into receiving
mode.  
+Now the driver is waiting, that a predefined RSSI level (signal strength at the
+receiver) is reached. Until this hasn't happened, the reception can be
+interrupted by the transmission thread at any time to insert a transmission
cycle.
+As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar
+as described for the transmission cycle the read out of the hardware fifo is
done
+dynamically. Upon each hardware fifo threshold interrupt, a portion of data
gets
+read. So also for reception it is possible to receive more data then the
hardware
+fifo can hold.
+
+
+Driver API
+==========
+
+The driver is currently implemented as a character device. Therefore it
supports
+the calls open, ioctl, read, write and close.
+
+
+params for ioctl
+----------------
+
+There are four options:  
+PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver
+PI433_IOC_WR_TX_CFG - set the transmission parameters
+PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver
+PI433_IOC_WR_RX_CFG - set the receiving parameters  
+
+The tx configuration is transfered via struct pi433_tx_cfg, the parameterset
for transmission.  
+It is devided into two sections: rf parameters and packet format.
+
+rf params:
+    frequency
+        frequency used for transmission.  
+        Allowed values: 433050000...434790000
+    bit_rate
+        bit rate used for transmission.  
+        Allowed values: #####
+    dev_frequency
+        frequency deviation in case of FSK.  
+        Allowed values: 600...500000
+    modulation
+        FSK - frequency shift key
+        OOK - On-Off-key
+    modShaping
+        shapingOff    - no shaping
+        shaping1_0    - gauss filter with BT 1 (FSK only)
+        shaping0_5    - gauss filter with BT 0.5 (FSK only)
+        shaping0_3    - gauss filter with BT 0.3 (FSK only)
+        shapingBR    - filter cut off at BR (OOK only)
+        shaping2BR    - filter cut off at 2*BR (OOK only)
+    paRamp (FSK only)
+        ramp3400    - amp ramps up in 3.4ms
+        ramp2000    - amp ramps up in 2.0ms
+        ramp1000    - amp ramps up in 1ms
+        ramp500        - amp ramps up in 500us
+        ramp250        - amp ramps up in 250us
+        ramp125        - amp ramps up in 125us
+        ramp100        - amp ramps up in 100us
+        ramp62        - amp ramps up in 62us
+        ramp50        - amp ramps up in 50us
+        ramp40        - amp ramps up in 40us
+        ramp31        - amp ramps up in 31us
+        ramp25        - amp ramps up in 25us
+        ramp20        - amp ramps up in 20us
+        ramp15        - amp ramps up in 15us
+        ramp12        - amp ramps up in 12us
+        ramp10        - amp ramps up in 10us
+    tx_start_condition
+        fifoLevel    - transmission starts, if fifo is filled to
+                  threshold level
+        fifoNotEmpty    - transmission starts, as soon as there is one
+                  byte in internal fifo
+    repetitions
+        This gives the option, to send a telegram multiple times. Default: 1
+
+packet format:
+    enable_preamble
+        optionOn    - a preamble will be automatically generated
+        optionOff    - no preamble will be generated
+    enable_sync
+        optionOn    - a sync word will be automatically added to
+                  the telegram after preamble
+        optionOff    - no sync word will be added
+        Attention: While possible to generate sync without preamble, the
+        receiver won't be able to detect the sync without preamble.
+    enable_length_byte
+        optionOn    - the length of the telegram will be automatically
+                  added to the telegram. It's part of the payload
+        optionOff    - no length information will be automatically added
+                  to the telegram.
+        Attention: For telegram length over 255 bytes, this option can't be
used
+        Attention: should be used in combination with sync, only
+    enable_address_byte
+        optionOn    - the address byte will be automatically added to the
+                  telgram. It's part of the payload
+        optionOff    - the address byte will not be added to the telegram.
+        The address byte can be used for address filtering, so the receiver
+        will only receive telegrams with a given address byte.
+        Attention: should be used in combination with sync, only
+    enable_crc
+        optionOn    - an crc will be automatically calculated over the
+                  payload of the telegram and added to the telegram
+                  after payload.
+        optionOff    - no crc will be calculated        
+    preamble_length
+        length of the preamble. Allowed values: 0...65536
+    sync_length
+        length of the sync word. Allowed values: 0...8
+    fixed_message_length
+        length of the payload of the telegram. Will override the length
+        given by the buffer, passed in with the write command. Will be
+        ignored if set to zero.
+    sync_pattern[8]
+        contains up to eight values, that are used as the sync pattern
+        on sync option
+    address_byte
+        one byte, used as address byte on address byte option.
+
+
+The rx configuration is transfered via struct pi433_rx_cfg, the parameterset
for receiving. It is devided into two sections: rf parameters and packet format.
+
+rf params:
+    frequency
+        frequency used for transmission.  
+        Allowed values: 433050000...434790000
+    bit_rate
+        bit rate used for transmission.
+        Allowed values: #####
+    dev_frequency
+        frequency deviation in case of FSK.
+        Allowed values: 600...500000
+    modulation
+        FSK - frequency shift key
+        OOK - on off key
+    rssi_threshold
+        threshold value for the signal strength on the receiver input.
+        If this value is exeeded, a reception cycle starts
+        Allowed values: 0...255
+    thresholdDecrement
+        in order to adapt to different levels of singnal strength, over
+        time the receiver gets more and more sensitive. This value  
+        determs, how fast the sensitivity increases.
+        step_0_5db    - increase in 0,5dB steps
+        step_1_0db    - increase in 1 db steps
+        step_1_5db    - increase in 1,5dB steps
+        step_2_0db    - increase in 2 db steps
+        step_3_0db    - increase in 3 db steps
+        step_4_0db    - increase in 4 db steps
+        step_5_0db    - increase in 5 db steps
+        step_6_0db    - increase in 6 db steps
+    antennaImpedance
+        sets the electrical adoption of the antenna
+        fiftyOhm    - for antennas with an impedance of 50Ohm
+        twohundretOhm    - for antennas with an impedance of 200Ohm
+    lnaGain
+        sets the gain of the low noise amp
+        automatic    - lna gain is determed by an agc
+        max        - lna gain is set to maximum
+        maxMinus6    - lna gain is set to  6db below max
+        maxMinus12    - lna gain is set to 12db below max
+        maxMinus24    - lna gain is set to 24db below max
+        maxMinus36    - lna gain is set to 36db below max
+        maxMinus48    - lna gain is set to 48db below max
+    bw_mantisse
+        sets the bandwidth of the channel filter - part one: mantisse.  
+        mantisse16    - mantisse is set to 16
+        mantisse20    - mantisse is set to 20
+        mantisse24    - mantisse is set to 24
+    bw_exponent
+        sets the bandwidth of the channel filter - part two: exponent.  
+        Allowd values: 0...7
+    dagc;
+        operation mode of the digital automatic gain control
+        normalMode
+        improve
+        improve4LowModulationIndex
+
+ packet format:
+    enable_sync
+        optionOn  - sync detection is enabled. If configured sync pattern
+                isn't found, telegram will be internally discarded  
+        optionOff - sync detection is disabled.
+    enable_length_byte
+        optionOn   - First byte of payload will be used as length byte,  
+                 regardless of the amount of bytes that were requested  
+                 by the read request.
+        optionOff  - Number of bytes to be read will be set according to
+                 amount of bytes that were requested by the read request.
+        Attention: should be used in combination with sync, only
+    enable_address_filtering;
+        filteringOff        - no adress filtering will take place
+        nodeAddress        - all telegrams, not matching the node  
+                      address will be internally discarded
+        nodeOrBroadcastAddress    - all telegrams, neither matching the
+                      node, nor the broadcast address will
+                      be internally discarded
+        Attention: Sync option must be enabled in order to use this feature
+    enable_crc
+        optionOn    - a crc will be calculated over the payload of
+                  the telegram, that was received. If the
+                  calculated crc doesn't match to two bytes,
+                  that follow the payload, the telegram will be
+                  internally discarded.
+        Attention: This option is only operational, if sync on and fixed length
+        or length byte is used
+    sync_length
+        Gives the length of the payload.  
+        Attention: This setting must meet the setting of the transmitter,
+        if sync option is used.
+    fixed_message_length
+        Overrides the telegram length either given by the first byte of
+        payload or by the read request.
+    bytes_to_drop
+        gives the number of bytes, that will be dropped before transfering
+        data to the read buffer
+        This option is only usefull, if all packet helper are switched
+        off and the rf chip is used in raw receiving mode. This may be
+        needed, if a telegram of a third party device should be received,
+        using a protocol not compatible with the packet engine of the rf69
chip.
+    sync_pattern[8]
+        contains up to eight values, that are used as the sync pattern
+        on sync option.
+        This setting must meet the configuration of the transmitting device,
+        if sync option is enabled.
+    node_address
+        one byte, used as node address byte on address byte option.
+    broadcast_address
+        one byte, used as broadcast address byte on address byte option.
+        
+
diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
new file mode 100644
index 0000000..61b4b4e
--- /dev/null
+++ b/drivers/staging/pi433/Kconfig
@@ -0,0 +1,16 @@
+config PI433
+        tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
+        default n
+        ---help---
+          This option allows you to enable support for the radio module Pi433.
+
+          Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi
+          or compatible. It extends the Raspberry Pi with the option, to
+          send and receive data in the 433MHz ISM band - for example to
+          communicate between two systems without using ethernet or bluetooth
+          or for control or read sockets, actors, sensors, widely available
+          for low price.
+
+          For details or the option to buy, please visit
https://pi433.de/en.html
+
+          If in doubt, say N here, but saying yes most probably won't hurt
diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile
new file mode 100644
index 0000000..417f3e4
--- /dev/null
+++ b/drivers/staging/pi433/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PI433) += pi433.o
+
+pi433-objs := pi433_if.o rf69.o
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
new file mode 100644
index 0000000..57edf91
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.c
@@ -0,0 +1,1315 @@
+/*
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+#endif
+
+#include "pi433_if.h"
+#include "rf69.h"
+
+
+#define N_PI433_MINORS            (1U << MINORBITS) /*32*/    /* ... up to 256
*/
+#define MAX_MSG_SIZE            900    /* min: FIFO_SIZE! */
+#define MSG_FIFO_SIZE            65536   /* 65536 = 2^16  */
+#define NUM_DIO                2
+
+static dev_t pi433_dev;
+static DEFINE_IDR(pi433_idr);
+static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+
+static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
+
+/* tx config is instance specific
+    so with each open a new tx config struct is needed */
+/* rx config is device specific
+    so we have just one rx config, ebedded in device struct */
+struct pi433_device {
+    /* device handling related values */
+    dev_t            devt;
+    int            minor;
+    struct device        *dev;
+    struct cdev        *cdev;
+    struct spi_device    *spi;
+    unsigned        users;
+
+    /* irq related values */
+    struct gpio_desc    *gpiod[NUM_DIO];
+    int            irq_num[NUM_DIO];
+    u8            irq_state[NUM_DIO];
+
+    /* tx related values */
+    STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
+    struct mutex        tx_fifo_lock; // TODO: check, whether necessary or
obsolete
+    struct task_struct    *tx_task_struct;
+    wait_queue_head_t    tx_wait_queue;
+    u8            free_in_fifo;
+
+    /* rx related values */
+    struct pi433_rx_cfg    rx_cfg;
+    u8            *rx_buffer;
+    unsigned int        rx_buffer_size;
+    u32            rx_bytes_to_drop;
+    u32            rx_bytes_dropped;
+    unsigned int        rx_position;
+    struct mutex        rx_lock;
+    wait_queue_head_t    rx_wait_queue;
+
+    /* fifo wait queue */
+    struct task_struct    *fifo_task_struct;
+    wait_queue_head_t    fifo_wait_queue;
+
+    /* flags */
+    bool            rx_active;
+    bool            tx_active;
+    bool            interrupt_rx_allowed;
+};
+
+struct pi433_instance {
+    struct pi433_device    *device;
+    struct pi433_tx_cfg    tx_cfg;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* macro for checked access of registers of radio module */
+#define SET_CHECKED(retval) \
+    if (retval < 0) \
+        return retval;
+
+/*-------------------------------------------------------------------------*/
+
+/* GPIO interrupt handlers */
+static irq_handler_t
+DIO0_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct pi433_device *device = dev_id;
+
+    if      (device->irq_state[DIO0] == DIO_PacketSent)
+    {
+        device->free_in_fifo = FIFO_SIZE;
+        printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include
KERN_ facility level
+        wake_up_interruptible(&device->fifo_wait_queue);
+    }
+    else if (device->irq_state[DIO0] == DIO_Rssi_DIO0)
+    {
+        printk("DIO0 irq: RSSI level over threshold\n");
+        wake_up_interruptible(&device->rx_wait_queue);
+    }
+    else if (device->irq_state[DIO0] == DIO_PayloadReady)
+    {
+        printk("DIO0 irq: PayloadReady\n");
+        device->free_in_fifo = 0;
+        wake_up_interruptible(&device->fifo_wait_queue);
+    }
+
+    return (irq_handler_t) IRQ_HANDLED;
+}
+
+static irq_handler_t
+DIO1_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct pi433_device *device = dev_id;
+
+    if      (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1)
+    {
+        device->free_in_fifo = FIFO_SIZE;
+    }
+    else if (device->irq_state[DIO1] == DIO_FifoLevel)
+    {
+        if (device->rx_active)    device->free_in_fifo = FIFO_THRESHOLD - 1;
+        else            device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1;
+    }
+    printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO:
printk() should include KERN_ facility level
+    wake_up_interruptible(&device->fifo_wait_queue);
+
+    return (irq_handler_t) IRQ_HANDLED;
+}
+
+static void *DIO_irq_handler[NUM_DIO] = {
+    DIO0_irq_handler,
+    DIO1_irq_handler
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
+{
+    int payload_length;
+
+    /* receiver config */
+    SET_CHECKED(rf69_set_frequency    (dev->spi, rx_cfg->frequency));
+    SET_CHECKED(rf69_set_bit_rate    (dev->spi, rx_cfg->bit_rate));
+    SET_CHECKED(rf69_set_modulation    (dev->spi, rx_cfg->modulation));
+    SET_CHECKED(rf69_set_antenna_impedance     (dev->spi,
rx_cfg->antenna_impedance));
+    SET_CHECKED(rf69_set_rssi_threshold     (dev->spi,
rx_cfg->rssi_threshold));
+    SET_CHECKED(rf69_set_ook_threshold_dec     (dev->spi,
rx_cfg->thresholdDecrement));
+    SET_CHECKED(rf69_set_bandwidth          (dev->spi, rx_cfg->bw_mantisse,
rx_cfg->bw_exponent));
+    SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse,
rx_cfg->bw_exponent));
+    SET_CHECKED(rf69_set_dagc          (dev->spi, rx_cfg->dagc));
+
+    dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop;
+
+    /* packet config */
+    /* enable */
+    SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync));
+    if (rx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi,
afterSyncInterrupt));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always));
+    }
+    SET_CHECKED(rf69_set_packet_format  (dev->spi,
rx_cfg->enable_length_byte));
+    SET_CHECKED(rf69_set_adressFiltering(dev->spi,
rx_cfg->enable_address_filtering));
+    SET_CHECKED(rf69_set_crc_enable        (dev->spi, rx_cfg->enable_crc));
+
+    /* lengths */
+    SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
+    if (rx_cfg->enable_length_byte == optionOn)
+    {
+        SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff));
+    }
+    else if (rx_cfg->fixed_message_length != 0)
+    {
+        payload_length = rx_cfg->fixed_message_length;
+        if (rx_cfg->enable_length_byte  == optionOn) payload_length++;
+        if (rx_cfg->enable_address_filtering != filteringOff) payload_length++;
+        SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
+    }
+
+    /* values */
+    if (rx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern));
+    }
+    if (rx_cfg->enable_address_filtering != filteringOff)
+    {
+        SET_CHECKED(rf69_set_node_address     (dev->spi,
rx_cfg->node_address));
+        SET_CHECKED(rf69_set_broadcast_address(dev->spi,
rx_cfg->broadcast_address));
+    }
+
+    return 0;
+}
+
+static int
+rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
+{
+    SET_CHECKED(rf69_set_frequency    (dev->spi, tx_cfg->frequency));
+    SET_CHECKED(rf69_set_bit_rate    (dev->spi, tx_cfg->bit_rate));
+    SET_CHECKED(rf69_set_modulation    (dev->spi, tx_cfg->modulation));
+    SET_CHECKED(rf69_set_deviation    (dev->spi, tx_cfg->dev_frequency));
+    SET_CHECKED(rf69_set_pa_ramp    (dev->spi, tx_cfg->pa_ramp));
+    SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping));
+    SET_CHECKED(rf69_set_tx_start_condition(dev->spi,
tx_cfg->tx_start_condition));
+
+    /* packet format enable */
+    if (tx_cfg->enable_preamble == optionOn)
+    {
+        SET_CHECKED(rf69_set_preamble_length(dev->spi,
tx_cfg->preamble_length));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
+    }
+    SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
+    SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
+    SET_CHECKED(rf69_set_crc_enable      (dev->spi, tx_cfg->enable_crc));
+
+    /* configure sync, if enabled */
+    if (tx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length));
+        SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern));
+    }
+
+    return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pi433_start_rx(struct pi433_device *dev)
+{
+    int retval;
+
+    /* return without action, if no pending read request */
+    if (!dev->rx_active)
+        return 0;
+
+    /* setup for receiving */
+    retval = rf69_set_rx_cfg(dev, &dev->rx_cfg);
+    if (retval) return retval;
+
+    /* setup rssi irq */
+    SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0));
+    dev->irq_state[DIO0] = DIO_Rssi_DIO0;
+    irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+    /* setup fifo level interrupt */
+    SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD));
+    SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel));
+    dev->irq_state[DIO1] = DIO_FifoLevel;
+    irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING);
+
+    /* set module to receiving mode */
+    SET_CHECKED(rf69_set_mode(dev->spi, receive));
+
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int
+pi433_receive(void *data)
+{
+    struct pi433_device *dev = data;
+    struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */
+    int bytes_to_read, bytes_total;
+    int retval;
+
+    dev->interrupt_rx_allowed = false;
+
+    /* wait for any tx to finish */
+    dev_dbg(dev->dev,"rx: going to wait for any tx to finish");
+    retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
+    if(retval) /* wait was interrupted */
+    {
+        dev->interrupt_rx_allowed = true;
+        wake_up_interruptible(&dev->tx_wait_queue);
+        return retval;
+    }
+
+    /* prepare status vars */
+    dev->free_in_fifo = FIFO_SIZE;
+    dev->rx_position = 0;
+    dev->rx_bytes_dropped = 0;
+
+    /* setup radio module to listen for something "in the air" */
+    retval = pi433_start_rx(dev);
+    if (retval)
+        return retval;
+
+    /* now check RSSI, if low wait for getting high (RSSI interrupt) */
+    while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) )
+    {
+        /* allow tx to interrupt us while waiting for high RSSI */
+        dev->interrupt_rx_allowed = true;
+        wake_up_interruptible(&dev->tx_wait_queue);
+
+        /* wait for RSSI level to become high */
+        dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
+        retval = wait_event_interruptible(dev->rx_wait_queue,
+                                      rf69_get_flag(dev->spi,
+
                                                       rssiExceededThreshold));
+        if (retval) goto abort; /* wait was interrupted */
+        dev->interrupt_rx_allowed = false;
+
+        /* cross check for ongoing tx */
+        if (!dev->tx_active) break;
+    }
+
+    /* configure payload ready irq */
+    SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady));
+    dev->irq_state[DIO0] = DIO_PayloadReady;
+    irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+    /* fixed or unlimited length? */
+    if (dev->rx_cfg.fixed_message_length != 0)
+    {
+        if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size)
+        {
+            retval = -1;
+            goto abort;
+        }
+        bytes_total = dev->rx_cfg.fixed_message_length;
+        dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total);
+    }
+    else
+    {
+        bytes_total = dev->rx_buffer_size;
+        dev_dbg(dev->dev, "rx: msg len set to %d as requested by read",
bytes_total);
+    }
+
+    /* length byte enabled? */
+    if (dev->rx_cfg.enable_length_byte == optionOn)
+    {
+        retval = wait_event_interruptible(dev->fifo_wait_queue,
+                          dev->free_in_fifo < FIFO_SIZE);
+        if (retval) goto abort; /* wait was interrupted */
+
+        rf69_read_fifo(spi, (u8 *)&bytes_total, 1);
+        if (bytes_total > dev->rx_buffer_size)
+        {
+            retval = -1;
+            goto abort;
+        }
+        dev->free_in_fifo++;
+        dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte",
bytes_total);
+    }
+
+    /* address byte enabled? */
+    if (dev->rx_cfg.enable_address_filtering != filteringOff)
+    {
+        u8 dummy;
+
+        bytes_total--;
+
+        retval = wait_event_interruptible(dev->fifo_wait_queue,
+                          dev->free_in_fifo < FIFO_SIZE);
+        if (retval) goto abort; /* wait was interrupted */
+
+        rf69_read_fifo(spi, &dummy, 1);
+        dev->free_in_fifo++;
+        dev_dbg(dev->dev, "rx: address byte stripped off");
+    }
+
+    /* get payload */
+    while (dev->rx_position < bytes_total)
+    {
+        if ( !rf69_get_flag(dev->spi, payloadReady) )
+        {
+            retval = wait_event_interruptible(dev->fifo_wait_queue,
+                              dev->free_in_fifo < FIFO_SIZE);
+            if (retval) goto abort; /* wait was interrupted */
+        }
+
+        /* need to drop bytes or acquire? */
+        if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+            bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+        else
+            bytes_to_read = bytes_total - dev->rx_position;
+
+
+        /* access the fifo */
+        if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo)
+            bytes_to_read = FIFO_SIZE - dev->free_in_fifo;
+        retval = rf69_read_fifo(spi,
+                    &dev->rx_buffer[dev->rx_position],
+                    bytes_to_read);
+        if (retval) goto abort; /* read failed */
+        dev->free_in_fifo += bytes_to_read;
+
+        /* adjust status vars */
+        if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+            dev->rx_bytes_dropped += bytes_to_read;
+        else
+            dev->rx_position += bytes_to_read;
+    }
+
+
+    /* rx done, wait was interrupted or error occured */
+abort:
+    dev->interrupt_rx_allowed = true;
+    SET_CHECKED(rf69_set_mode(dev->spi, standby));
+    wake_up_interruptible(&dev->tx_wait_queue);
+
+    if (retval)
+        return retval;
+    else
+        return bytes_total;
+}
+
+int
+pi433_tx_thread(void *data)
+{
+    struct pi433_device *device = data;
+    struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
+    struct pi433_tx_cfg tx_cfg;
+    u8     buffer[MAX_MSG_SIZE];
+    size_t size;
+    bool   rx_interrupted = false;
+    int    position, repetitions;
+    int    retval;
+
+    while (1)
+    {
+        /* wait for fifo to be populated or for request to terminate*/
+        dev_dbg(device->dev, "thread: going to wait for new messages");
+        wait_event_interruptible(device->tx_wait_queue,
+                     ( !kfifo_is_empty(&device->tx_fifo) ||
+                        kthread_should_stop() ));
+        if ( kthread_should_stop() )
+            return 0;
+
+        /* get data from fifo in the following order:
+           - tx_cfg
+           - size of message
+           - message */
+        mutex_lock(&device->tx_fifo_lock);
+
+        retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
+        if (retval != sizeof(tx_cfg))
+        {
+            dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d
byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) );
+            mutex_unlock(&device->tx_fifo_lock);
+            continue;
+        }
+
+        retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
+        if (retval != sizeof(size_t))
+        {
+            dev_dbg(device->dev, "reading msg size from fifo failed: got %d,
expected %d", retval, (unsigned int)sizeof(size_t) );
+            mutex_unlock(&device->tx_fifo_lock);
+            continue;
+        }
+
+        /* use fixed message length, if requested */
+        if (tx_cfg.fixed_message_length != 0)
+            size = tx_cfg.fixed_message_length;
+
+        /* increase size, if len byte is requested */
+        if (tx_cfg.enable_length_byte == optionOn)
+            size++;
+
+        /* increase size, if adr byte is requested */
+        if (tx_cfg.enable_address_byte == optionOn)
+            size++;
+
+        /* prime buffer */
+        memset(buffer, 0, size);
+        position = 0;
+
+        /* add length byte, if requested */
+        if (tx_cfg.enable_length_byte  == optionOn)
+            buffer[position++] = size-1; /* according to spec length byte
itself must be excluded from the length calculation */
+
+        /* add adr byte, if requested */
+        if (tx_cfg.enable_address_byte == optionOn)
+            buffer[position++] = tx_cfg.address_byte;
+
+        /* finally get message data from fifo */
+        retval = kfifo_out(&device->tx_fifo, &buffer[position],
sizeof(buffer)-position );
+        dev_dbg(device->dev, "read %d message byte(s) from fifo queue.",
retval);
+        mutex_unlock(&device->tx_fifo_lock);
+
+        /* if rx is active, we need to interrupt the waiting for
+           incoming telegrams, to be able to send something.
+           We are only allowed, if currently no reception takes
+           place otherwise we need to  wait for the incoming telegram
+           to finish */
+        wait_event_interruptible(device->tx_wait_queue,
+                     !device->rx_active ||
+                      device->interrupt_rx_allowed == true);
+
+        /* prevent race conditions
+           irq will be reenabled after tx config is set */
+        disable_irq(device->irq_num[DIO0]);
+        device->tx_active = true;
+
+        if (device->rx_active && rx_interrupted == false)
+        {
+            /* rx is currently waiting for a telegram;
+               we need to set the radio module to standby */
+            SET_CHECKED(rf69_set_mode(device->spi, standby));
+            rx_interrupted = true;
+        }
+
+        /* clear fifo, set fifo threshold, set payload length */
+        SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */
+        SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD));
+        if (tx_cfg.enable_length_byte == optionOn)
+        {
+            SET_CHECKED(rf69_set_payload_length(spi, size *
tx_cfg.repetitions));
+        }
+        else
+        {
+            SET_CHECKED(rf69_set_payload_length(spi, 0));
+        }
+
+        /* configure the rf chip */
+        rf69_set_tx_cfg(device, &tx_cfg);
+
+        /* enable fifo level interrupt */
+        SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel));
+        device->irq_state[DIO1] = DIO_FifoLevel;
+        irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING);
+
+        /* enable packet sent interrupt */
+        SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent));
+        device->irq_state[DIO0] = DIO_PacketSent;
+        irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+        enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check
*/
+
+        /* enable transmission */
+        SET_CHECKED(rf69_set_mode(spi, transmit));
+
+        /* transfer this msg (and repetitions) to chip fifo */
+        device->free_in_fifo = FIFO_SIZE;
+        position = 0;
+        repetitions = tx_cfg.repetitions;
+        while( (repetitions > 0) && (size > position) )
+        {
+            if ( (size - position) > device->free_in_fifo)
+            {    /* msg to big for fifo - take a part */
+                int temp = device->free_in_fifo;
+                device->free_in_fifo = 0;
+                rf69_write_fifo(spi,
+                                &buffer[position],
+                                temp);
+                position +=temp;
+            }
+            else
+            {    /* msg fits into fifo - take all */
+                device->free_in_fifo -= size;
+                repetitions--;
+                rf69_write_fifo(spi,
+                        &buffer[position],
+                        (size - position) );
+                position = 0; /* reset for next repetition */
+            }
+
+            retval = wait_event_interruptible(device->fifo_wait_queue,
+                              device->free_in_fifo > 0);
+            if (retval) { printk("ABORT\n"); goto abort; }
+        }
+
+        /* we are done. Wait for packet to get sent */
+        dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be
empty");
+        wait_event_interruptible(device->fifo_wait_queue,
+                     device->free_in_fifo == FIFO_SIZE ||
+                     kthread_should_stop() );
+        if ( kthread_should_stop() )    printk("ABORT\n");
+
+
+        /* STOP_TRANSMISSION */
+        dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.");
+        SET_CHECKED(rf69_set_mode(spi, standby));
+
+        /* everything sent? */
+        if ( kfifo_is_empty(&device->tx_fifo) )
+        {
+abort:
+            if (rx_interrupted)
+            {
+                rx_interrupted = false;
+                pi433_start_rx(device);
+            }
+            device->tx_active = false;
+            wake_up_interruptible(&device->rx_wait_queue);
+        }
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t
+pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    unsigned int        bytes_received;
+    ssize_t            retval;
+
+    /* check, whether internal buffer is big enough for requested size */
+    if (size > MAX_MSG_SIZE)
+        return -EMSGSIZE;
+
+    instance = filp->private_data;
+    device = instance->device;
+
+    /* just one read request at a time */
+    mutex_lock(&device->rx_lock);
+    if (device->rx_active)
+    {
+        mutex_unlock(&device->rx_lock);
+        return -EAGAIN;
+    }
+    else
+    {
+        device->rx_active = true;
+        mutex_unlock(&device->rx_lock);
+    }
+
+    /* start receiving */
+    /* will block until something was received*/
+    device->rx_buffer_size = size;
+    bytes_received = pi433_receive(device);
+
+    /* release rx */
+    mutex_lock(&device->rx_lock);
+    device->rx_active = false;
+    mutex_unlock(&device->rx_lock);
+
+    /* if read was successful copy to user space*/
+    if (bytes_received >= 0)
+    {
+        retval = copy_to_user(buf, device->rx_buffer, bytes_received);
+        if (retval)
+            return retval;
+    }
+
+    return bytes_received;
+}
+
+
+static ssize_t
+pi433_write(struct file *filp, const char __user *buf,
+        size_t count, loff_t *f_pos)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    int                     copied, retval;
+
+    instance = filp->private_data;
+    device = instance->device;
+
+    /* check, whether internal buffer (tx thread) is big enough for requested
size */
+    if (count > MAX_MSG_SIZE)
+        return -EMSGSIZE;
+
+    /* write the following sequence into fifo:
+       - tx_cfg
+       - size of message
+       - message */
+    mutex_lock(&device->tx_fifo_lock);
+    retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg,
sizeof(instance->tx_cfg));
+    if ( retval != sizeof(instance->tx_cfg) )
+        goto abort;
+
+    retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t));
+    if ( retval != sizeof(size_t) )
+        goto abort;
+
+    retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied);
+    if (retval || copied != count)
+        goto abort;
+
+    mutex_unlock(&device->tx_fifo_lock);
+
+    /* start transfer */
+    wake_up_interruptible(&device->tx_wait_queue);
+    dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied);
+
+    return 0;
+
+abort:
+    dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
+    kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to
discard already stored, valid entries
+    mutex_unlock(&device->tx_fifo_lock);
+    return -EAGAIN;
+}
+
+
+static long
+pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    int            err = 0;
+    int            retval = 0;
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    u32            tmp;
+
+    /* Check type and command number */
+    if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
+        return -ENOTTY;
+
+    /* Check access direction once here; don't repeat below.
+     * IOC_DIR is from the user perspective, while access_ok is
+     * from the kernel perspective; so they look reversed.
+     */
+    if (_IOC_DIR(cmd) & _IOC_READ)
+        err = !access_ok(VERIFY_WRITE,
+                 (void __user *)arg,
+                 _IOC_SIZE(cmd));
+
+    if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+        err = !access_ok(VERIFY_READ,
+                 (void __user *)arg,
+                 _IOC_SIZE(cmd));
+    if (err)
+        return -EFAULT;
+
+    /* TODO? guard against device removal before, or while,
+     * we issue this ioctl. --> device_get()
+     */
+    instance = filp->private_data;
+    device = instance->device;
+
+    if (device == NULL)
+        return -ESHUTDOWN;
+
+    switch (cmd) {
+    case PI433_IOC_RD_TX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_to_user((void __user *)arg,
+                    &instance->tx_cfg,
+                    tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+    case PI433_IOC_WR_TX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_from_user(&instance->tx_cfg,
+                     (void __user *)arg,
+                     tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+
+    case PI433_IOC_RD_RX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_to_user((void __user *)arg,
+                   &device->rx_cfg,
+                   tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+    case PI433_IOC_WR_RX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        mutex_lock(&device->rx_lock);
+
+        /* during pendig read request, change of config not allowed */
+        if (device->rx_active) {
+            retval = -EAGAIN;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+            retval = -EINVAL;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        if (__copy_from_user(&device->rx_cfg,
+                     (void __user *)arg,
+                     tmp))
+        {
+            retval = -EFAULT;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        mutex_unlock(&device->rx_lock);
+        break;
+    default:
+        retval = -EINVAL;
+    }
+
+    return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define pi433_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_open(struct inode *inode, struct file *filp)
+{
+    struct pi433_device    *device;
+    struct pi433_instance    *instance;
+
+    mutex_lock(&minor_lock);
+    device = idr_find(&pi433_idr, iminor(inode));
+
+    mutex_unlock(&minor_lock);
+    if (!device) {
+        dev_dbg(device->dev, "device: minor %d unknown.\n", iminor(inode));
+        return -ENODEV;
+    }
+
+    if (!device->rx_buffer) {
+        device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL);
+        if (!device->rx_buffer)
+        {
+            dev_dbg(device->dev, "open/ENOMEM\n");
+            return -ENOMEM;
+        }
+    }
+
+    device->users++;
+    instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+    if (!instance)
+    {
+        kfree(device->rx_buffer);
+        device->rx_buffer = NULL;
+        return -ENOMEM;
+    }
+
+    /* setup instance data*/
+    instance->device = device;
+    instance->tx_cfg.bit_rate = 4711;
+    // TODO: fill instance->tx_cfg;
+
+    /* instance data as context */
+    filp->private_data = instance;
+    nonseekable_open(inode, filp);
+
+    return 0;
+}
+
+static int pi433_release(struct inode *inode, struct file *filp)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+
+    instance = filp->private_data;
+    device = instance->device;
+    kfree(instance);
+    filp->private_data = NULL;
+
+    /* last close? */
+    device->users--;
+
+    if (!device->users) {
+        kfree(device->rx_buffer);
+        device->rx_buffer = NULL;
+        if (device->spi == NULL)
+            kfree(device);
+    }
+
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int setup_GPIOs(struct pi433_device *device)
+{
+    char     name[5];
+    int    retval;
+    int    i;
+
+    for (i=0; i<NUM_DIO; i++)
+    {
+        /* "construct" name and get the gpio descriptor */
+        snprintf(name, sizeof(name), "DIO%d", i);
+        device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+
+        if (device->gpiod[i] == ERR_PTR(-ENOENT))
+        {
+            dev_dbg(&device->spi->dev, "Could not find entry for %s.
Ignoring.", name);
+            continue;
+        }
+
+        if (device->gpiod[i] == ERR_PTR(-EBUSY))
+            dev_dbg(&device->spi->dev, "%s is busy.", name);
+
+        if ( IS_ERR(device->gpiod[i]) )
+        {
+            retval = PTR_ERR(device->gpiod[i]);
+            /* release already allocated gpios */
+            for (i--; i>=0; i--)
+            {
+                free_irq(device->irq_num[i], device);
+                gpiod_put(device->gpiod[i]);
+            }
+            return retval;
+        }
+
+
+        /* configure the pin */
+        gpiod_unexport(device->gpiod[i]);
+        retval = gpiod_direction_input(device->gpiod[i]);
+        if (retval) return retval;
+
+
+        /* configure irq */
+        device->irq_num[i] = gpiod_to_irq(device->gpiod[i]);
+        if (device->irq_num[i] < 0)
+        {
+            device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc
*)device->irq_num[i];
+            return device->irq_num[i];
+        }
+        retval = request_irq(device->irq_num[i],
+                     DIO_irq_handler[i],
+                     0, /* flags */
+                     name,
+                     device);
+
+        if (retval)
+            return retval;
+
+        dev_dbg(&device->spi->dev, "%s succesfully configured", name);
+    }
+
+    return 0;
+}
+
+static void free_GPIOs(struct pi433_device *device)
+{
+    int i;
+
+    for (i=0; i<NUM_DIO; i++)
+    {
+        /* check if gpiod is valid */
+        if ( IS_ERR(device->gpiod[i]) )
+            continue;
+
+        free_irq(device->irq_num[i], device);
+        gpiod_put(device->gpiod[i]);
+    }
+    return;
+}
+
+static int pi433_get_minor(struct pi433_device *device)
+{
+    int retval = -ENOMEM;
+
+    mutex_lock(&minor_lock);
+    retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL);
+    if (retval >= 0) {
+        device->minor = retval;
+        retval = 0;
+    } else if (retval == -ENOSPC) {
+        dev_err(device->dev, "too many pi433 devices\n");
+        retval = -EINVAL;
+    }
+    mutex_unlock(&minor_lock);
+    return retval;
+}
+
+static void pi433_free_minor(struct pi433_device *dev)
+{
+    mutex_lock(&minor_lock);
+    idr_remove(&pi433_idr, dev->minor);
+    mutex_unlock(&minor_lock);
+}
+/*-------------------------------------------------------------------------*/
+
+static const struct file_operations pi433_fops = {
+    .owner =    THIS_MODULE,
+    /* REVISIT switch to aio primitives, so that userspace
+     * gets more complete API coverage.  It'll simplify things
+     * too, except for the locking.
+     */
+    .write =    pi433_write,
+    .read =        pi433_read,
+    .unlocked_ioctl = pi433_ioctl,
+    .compat_ioctl = pi433_compat_ioctl,
+    .open =        pi433_open,
+    .release =    pi433_release,
+    .llseek =    no_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_probe(struct spi_device *spi)
+{
+    struct pi433_device    *device;
+    int            retval;
+
+    /* setup spi parameters */
+    spi->mode = 0x00;
+    spi->bits_per_word = 8;
+    /* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay
*/
+
+    retval = spi_setup(spi);
+    if (retval)
+    {
+        dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
+        return retval;
+    }
+    else
+    {
+        dev_dbg(&spi->dev,
+            "spi interface setup: mode 0x%2x, %d bits per word, %dhz max
speed",
+            spi->mode, spi->bits_per_word, spi->max_speed_hz);
+    }
+
+    /* Ping the chip by reading the version register */
+    retval = spi_w8r8(spi, 0x10);
+    if (retval < 0)
+        return retval;
+
+    switch(retval)
+    {
+        case 0x24:
+            dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
+            break;
+        default:
+            dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
+            return -ENODEV;
+    }
+
+    /* Allocate driver data */
+    device = kzalloc(sizeof(*device), GFP_KERNEL);
+    if (!device)
+        return -ENOMEM;
+
+    /* Initialize the driver data */
+    device->spi = spi;
+    device->rx_active = false;
+    device->tx_active = false;
+    device->interrupt_rx_allowed = false;
+
+    /* init wait queues */
+    init_waitqueue_head(&device->tx_wait_queue);
+    init_waitqueue_head(&device->rx_wait_queue);
+    init_waitqueue_head(&device->fifo_wait_queue);
+
+    /* init fifo */
+    INIT_KFIFO(device->tx_fifo);
+
+    /* init mutexes and locks */
+    mutex_init(&device->tx_fifo_lock);
+    mutex_init(&device->rx_lock);
+
+    /* setup GPIO (including irq_handler) for the different DIOs */
+    retval = setup_GPIOs(device);
+    if (retval)
+    {
+        dev_dbg(&spi->dev, "setup of GPIOs failed");
+        goto GPIO_failed;
+    }
+
+    /* setup the radio module */
+    SET_CHECKED(rf69_set_mode        (spi, standby));
+    SET_CHECKED(rf69_set_data_mode        (spi, packet));
+    SET_CHECKED(rf69_set_amplifier_0    (spi, optionOn));
+    SET_CHECKED(rf69_set_amplifier_1    (spi, optionOff));
+    SET_CHECKED(rf69_set_amplifier_2    (spi, optionOff));
+    SET_CHECKED(rf69_set_output_power_level    (spi, 13));
+    SET_CHECKED(rf69_set_antenna_impedance    (spi, fiftyOhm));
+
+    /* start tx thread */
+    device->tx_task_struct = kthread_run(pi433_tx_thread,
+                         device,
+                         "pi433_tx_task");
+    if (device->tx_task_struct < 0)
+    {
+        dev_dbg(device->dev, "start of send thread failed");
+        goto send_thread_failed;
+    }
+
+    /* determ minor number */
+    retval = pi433_get_minor(device);
+    if (retval)
+    {
+        dev_dbg(device->dev, "get of minor number failed");
+        goto minor_failed;
+    }
+
+    /* create device */
+    device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
+    device->dev = device_create(pi433_class,
+                    &spi->dev,
+                    device->devt,
+                    device,
+                    "pi433");
+    if (IS_ERR(device->dev)) {
+        pr_err("pi433: device register failed\n");
+        retval = PTR_ERR(device->dev);
+        goto device_create_failed;
+    }
+    else {
+        dev_dbg(device->dev,
+            "created device for major %d, minor %d\n",
+            MAJOR(pi433_dev),
+            device->minor);
+    }
+
+    /* create cdev */
+    device->cdev = cdev_alloc();
+    device->cdev->owner = THIS_MODULE;
+    cdev_init(device->cdev, &pi433_fops);
+    retval = cdev_add(device->cdev, device->devt, 1);
+    if (retval)
+    {
+        dev_dbg(device->dev, "register of cdev failed");
+        goto cdev_failed;
+    }
+
+    /* spi setup */
+    spi_set_drvdata(spi, device);
+
+    return 0;
+
+cdev_failed:
+    device_destroy(pi433_class, device->devt);
+device_create_failed:
+    pi433_free_minor(device);
+minor_failed:
+    kthread_stop(device->tx_task_struct);
+send_thread_failed:
+    free_GPIOs(device);
+GPIO_failed:
+    kfree(device);
+
+    return retval;
+}
+
+static int pi433_remove(struct spi_device *spi)
+{
+    struct pi433_device    *device = spi_get_drvdata(spi);
+
+    /* free GPIOs */
+    free_GPIOs(device);
+
+    /* make sure ops on existing fds can abort cleanly */
+    device->spi = NULL;
+
+    kthread_stop(device->tx_task_struct);
+
+    device_destroy(pi433_class, device->devt);
+
+    cdev_del(device->cdev);
+
+    pi433_free_minor(device);
+
+    if (device->users == 0)
+        kfree(device);
+
+    return 0;
+}
+
+static const struct of_device_id pi433_dt_ids[] = {
+    { .compatible = "Smarthome-Wolf,pi433" },
+    {},
+};
+
+MODULE_DEVICE_TABLE(of, pi433_dt_ids);
+
+static struct spi_driver pi433_spi_driver = {
+    .driver = {
+        .name =        "pi433",
+        .owner =    THIS_MODULE,
+        .of_match_table = of_match_ptr(pi433_dt_ids),
+    },
+    .probe =    pi433_probe,
+    .remove =    pi433_remove,
+
+    /* NOTE:  suspend/resume methods are not necessary here.
+     * We don't do anything except pass the requests to/from
+     * the underlying controller.  The refrigerator handles
+     * most issues; the controller driver handles the rest.
+     */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init pi433_init(void)
+{
+    int status;
+
+    /* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't
+           work stable - risk of buffer overflow */
+    if (MAX_MSG_SIZE < FIFO_SIZE)
+        return -EINVAL;
+
+    /* Claim device numbers.  Then register a class
+     * that will key udev/mdev to add/remove /dev nodes.  Last, register
+     * Last, register the driver which manages those device numbers.
+     */
+    status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS
/*count*/, "pi433" /*name*/);
+    if (status < 0)
+        return status;
+
+    pi433_class = class_create(THIS_MODULE, "pi433");
+    if (IS_ERR(pi433_class))
+    {
+        unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+        return PTR_ERR(pi433_class);
+    }
+
+    status = spi_register_driver(&pi433_spi_driver);
+    if (status < 0)
+    {
+        class_destroy(pi433_class);
+        unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+    }
+
+    return status;
+}
+
+module_init(pi433_init);
+
+static void __exit pi433_exit(void)
+{
+    spi_unregister_driver(&pi433_spi_driver);
+    class_destroy(pi433_class);
+    unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+}
+module_exit(pi433_exit);
+
+MODULE_AUTHOR("Marcus Wolf, <linux@wolf-entwicklungen.de>");
+MODULE_DESCRIPTION("Driver for Pi433");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:pi433");
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
new file mode 100644
index 0000000..e6ed3cd
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.h
@@ -0,0 +1,152 @@
+/*
+ * include/linux/TODO
+ *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR     0
+struct pi433_tx_cfg
+{
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+    enum modulation        modulation;
+    enum modShaping        modShaping;
+
+    enum paRamp        pa_ramp;
+
+    enum txStartCondition    tx_start_condition;
+
+    __u16            repetitions;
+
+
+    /* packet format */
+    enum optionOnOff    enable_preamble;
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;
+    enum optionOnOff    enable_address_byte;
+    enum optionOnOff    enable_crc;
+
+    __u16            preamble_length;
+    __u8            sync_length;
+    __u8            fixed_message_length;
+
+    __u8            sync_pattern[8];
+    __u8            address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR     1
+struct pi433_rx_cfg {
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+
+    enum modulation        modulation;
+
+    __u8            rssi_threshold;
+    enum thresholdDecrement    thresholdDecrement;
+    enum antennaImpedance    antenna_impedance;
+    enum lnaGain        lna_gain;
+    enum mantisse        bw_mantisse;    /* normal: 0x50 */
+    __u8            bw_exponent;    /* during AFC: 0x8b */
+    enum dagc        dagc;
+
+
+
+    /* packet format */
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;      /* should be used in
combination with sync, only */
+    enum addressFiltering    enable_address_filtering; /* operational with
sync, only */
+    enum optionOnOff    enable_crc;          /* only operational, if sync on
and fixed length or length byte is used */
+
+    __u8            sync_length;
+    __u8            fixed_message_length;
+    __u32            bytes_to_drop;
+
+    __u8            sync_pattern[8];
+    __u8            node_address;
+    __u8            broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC            'r'
+
+#define PI433_IOC_RD_TX_CFG    _IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG    _IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG    _IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG    _IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
new file mode 100644
index 0000000..b6bc45b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.c
@@ -0,0 +1,982 @@
+/*
+ * abstraction of the spi interface of HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* enable prosa debug info */
+#undef DEBUG
+/* enable print of values on reg access */
+#undef DEBUG_VALUES
+/* enable print of values on fifo access */
+#undef DEBUG_FIFO_ACCESS
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include "rf69.h"
+#include "rf69_registers.h"
+
+#define F_OSC      32000000 /* in Hz */
+#define FIFO_SIZE 66        /* in byte */
+
+/*-------------------------------------------------------------------------*/
+
+#define READ_REG(x)    rf69_read_reg (spi, x)
+#define WRITE_REG(x,y)    rf69_write_reg(spi, x, y)
+#define INVALID_PARAM \
+    { \
+        dev_dbg(&spi->dev, "set: illegal input param"); \
+        return -EINVAL; \
+    }
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: mode");
+    #endif
+
+    switch (mode){
+    case transmit:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT);
+    case receive:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE);
+    case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER);
+    case standby:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY);
+    case mode_sleep:  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP);
+    default:      INVALID_PARAM;
+    }
+
+    // we are using packet mode, so this check is not really needed
+    // but waiting for mode ready is necessary when going from sleep because
the FIFO may not be immediately available from previous mode
+    //while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) &
RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
+
+}
+
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: data mode");
+    #endif
+
+    switch (dataMode) {
+    case packet:        return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET);
+    case continuous:    return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS);
+    case continuousNoSync:  return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) |
DATAMODUL_MODE_CONTINUOUS_NOSYNC);
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: modulation");
+    #endif
+
+    switch (modulation) {
+    case OOK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) &
~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK);
+    case FSK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) &
~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK);
+    default:    INVALID_PARAM;
+    }
+}
+
+enum modulation rf69_get_modulation(struct spi_device *spi)
+{
+    u8 currentValue;    
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: mode");
+    #endif
+
+    currentValue = READ_REG(REG_DATAMODUL);
+
+    switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3)  // TODO
improvement: change 3 to define
+    {
+    case DATAMODUL_MODULATION_TYPE_OOK: return OOK;
+    case DATAMODUL_MODULATION_TYPE_FSK: return FSK;
+    default:                return undefined;
+    }
+}
+
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping
modShaping)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: mod shaping");
+    #endif
+
+    if (rf69_get_modulation(spi) == FSK)
+    {
+        switch (modShaping) {
+        case shapingOff: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_NONE);
+        case shaping1_0: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_1_0);
+        case shaping0_5: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_0_3);
+        case shaping0_3: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_0_5);
+        default:     INVALID_PARAM;
+        }
+    }
+    else
+    {
+        switch (modShaping) {
+        case shapingOff: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_NONE);
+        case shapingBR:     return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_BR);
+        case shaping2BR: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_2BR);
+        default:     INVALID_PARAM;
+        }
+    }
+}
+
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+{
+    int retval;
+    u32 bitRate_min;
+    u32 bitRate_reg;
+    u8 msb;
+    u8 lsb;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: bit rate");
+    #endif
+
+    // check input value
+    bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
+    if (bitRate < bitRate_min)
+    {
+        dev_dbg(&spi->dev, "setBitRate: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculate reg settings
+    bitRate_reg = (F_OSC / bitRate);
+
+    msb = (bitRate_reg&0xff00)   >>  8;
+    lsb = (bitRate_reg&0xff);
+
+    // transmit to RF 69
+    retval = WRITE_REG(REG_BITRATE_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_BITRATE_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_deviation(struct spi_device *spi, u32 deviation)
+{
+    int retval;
+//    u32 f_max; TODO: Abhängigkeit von Bitrate beachten!!
+    u64 f_reg;
+    u64 f_step;
+    u8 msb;
+    u8 lsb;
+    u64 factor = 1000000; // to improve precision of calculation
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: deviation");
+    #endif
+
+    if (deviation < 600 || deviation > 500000) //TODO: Abhängigkeit von Bitrate
beachten!!
+    {
+        dev_dbg(&spi->dev, "set_deviation: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculat f step
+    f_step = F_OSC * factor;
+    do_div(f_step, 524288); //  524288 = 2^19
+
+    // calculate register settings
+    f_reg = deviation * factor;
+    do_div(f_reg  , f_step);
+
+    msb = (f_reg&0xff00)   >>  8;
+    lsb = (f_reg&0xff);
+
+    // check msb
+    if (msb & !FDEVMASB_MASK)
+    {
+        dev_dbg(&spi->dev, "set_deviation: err in calc of msb");
+        INVALID_PARAM;
+    }
+
+    // write to chip
+    retval = WRITE_REG(REG_FDEV_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FDEV_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_frequency(struct spi_device *spi, u32 frequency)
+{
+    int retval;
+    u32 f_max;
+    u64 f_reg;
+    u64 f_step;
+    u8 msb;
+    u8 mid;
+    u8 lsb;
+    u64 factor = 1000000; // to improve precision of calculation
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: frequency");
+    #endif
+
+    // calculat f step
+    f_step = F_OSC * factor;
+    do_div(f_step, 524288); //  524288 = 2^19
+
+    // check input value
+    f_max = f_step * 8388608 / factor;
+    if (frequency > f_max)
+    {
+        dev_dbg(&spi->dev, "setFrequency: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculate reg settings
+    f_reg = frequency * factor;
+    do_div(f_reg  , f_step);
+
+    msb = (f_reg&0xff0000) >> 16;
+    mid = (f_reg&0xff00)   >>  8;
+    lsb = (f_reg&0xff);
+
+    // write to chip
+    retval = WRITE_REG(REG_FRF_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FRF_MID, mid);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FRF_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #0");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA0) );
+    case optionOff:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA0) );
+    default:    INVALID_PARAM;
+    }
+}    
+
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #1");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA1) );
+    case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA1) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #2");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA2) );
+    case optionOff:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA2) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: power level");
+    #endif
+
+    powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting
+
+    // check input value
+    if (powerLevel > 0x1f)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_OUTPUT_POWER) | powerLevel);
+}
+
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: pa ramp");
+    #endif
+
+    switch(paRamp) {
+    case ramp3400:    return WRITE_REG(REG_PARAMP, PARAMP_3400);
+    case ramp2000:    return WRITE_REG(REG_PARAMP, PARAMP_2000);
+    case ramp1000:    return WRITE_REG(REG_PARAMP, PARAMP_1000);
+    case ramp500:    return WRITE_REG(REG_PARAMP, PARAMP_500);
+    case ramp250:    return WRITE_REG(REG_PARAMP, PARAMP_250);
+    case ramp125:    return WRITE_REG(REG_PARAMP, PARAMP_125);
+    case ramp100:    return WRITE_REG(REG_PARAMP, PARAMP_100);
+    case ramp62:    return WRITE_REG(REG_PARAMP, PARAMP_62);
+    case ramp50:    return WRITE_REG(REG_PARAMP, PARAMP_50);
+    case ramp40:    return WRITE_REG(REG_PARAMP, PARAMP_40);
+    case ramp31:    return WRITE_REG(REG_PARAMP, PARAMP_31);
+    case ramp25:    return WRITE_REG(REG_PARAMP, PARAMP_25);
+    case ramp20:    return WRITE_REG(REG_PARAMP, PARAMP_20);
+    case ramp15:    return WRITE_REG(REG_PARAMP, PARAMP_15);
+    case ramp12:    return WRITE_REG(REG_PARAMP, PARAMP_12);
+    case ramp10:    return WRITE_REG(REG_PARAMP, PARAMP_10);
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance
antennaImpedance)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: antenna impedance");
+    #endif
+
+    switch(antennaImpedance) {
+    case fiftyOhm:        return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) &
~MASK_LNA_ZIN) );
+    case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) |
 MASK_LNA_ZIN) );
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: lna gain");
+    #endif
+
+    switch(lnaGain) {
+    case automatic:     return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_AUTO) );
+    case max:     return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX) );
+    case maxMinus6:  return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) );
+    case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) );
+    case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) );
+    case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) );
+    case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) );
+    default:     INVALID_PARAM;
+    }
+}
+
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi)
+{
+    u8 currentValue;    
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: lna gain");
+    #endif
+
+    currentValue = READ_REG(REG_LNA);
+
+    switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3)  // improvement: change
3 to define
+    {
+    case LNA_GAIN_AUTO:        return automatic;
+    case LNA_GAIN_MAX:        return max;
+    case LNA_GAIN_MAX_MINUS_6:  return maxMinus6;
+    case LNA_GAIN_MAX_MINUS_12: return maxMinus12;
+    case LNA_GAIN_MAX_MINUS_24: return maxMinus24;
+    case LNA_GAIN_MAX_MINUS_36: return maxMinus36;
+    case LNA_GAIN_MAX_MINUS_48: return maxMinus48;
+    default:            return undefined;
+    }
+}
+
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum
dccPercent dccPercent)
+{
+    switch (dccPercent) {
+    case dcc16Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) );
+    case dcc8Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) );
+    case dcc4Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) );
+    case dcc2Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) );
+    case dcc1Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) );
+    case dcc0_5Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) );
+    case dcc0_25Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) );
+    case dcc0_125Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) );
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent
dccPercent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: cut off freq");
+    #endif
+
+    return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent);
+}
+
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum
dccPercent dccPercent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: cut off freq during afc");
+    #endif
+
+    return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent);
+}
+
+int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse
mantisse, u8 exponent)
+{
+    u8 newValue;
+
+    // check value for mantisse and exponent
+    if (exponent > 7)   INVALID_PARAM;
+    if ( (mantisse!=mantisse16) &&
+         (mantisse!=mantisse20) &&
+             (mantisse!=mantisse24) ) INVALID_PARAM;
+
+    // read old value
+    newValue = READ_REG(reg);
+
+    // "delete" mantisse and exponent = just keep the DCC setting
+    newValue = newValue & MASK_BW_DCC_FREQ;
+
+    // add new mantisse
+    switch(mantisse) {
+    case mantisse16: newValue = newValue | BW_MANT_16;    break;
+    case mantisse20: newValue = newValue | BW_MANT_20;    break;
+    case mantisse24: newValue = newValue | BW_MANT_24;    break;
+    }
+
+    // add new exponent
+    newValue = newValue | exponent;
+
+    // write back
+    return WRITE_REG(reg, newValue);
+}
+
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8
exponent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: band width");
+    #endif
+
+    return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent);
+}
+
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse
mantisse, u8 exponent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: band width during afc");
+    #endif
+
+    return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
+}
+
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType
thresholdType)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold type");
+    #endif
+
+    switch (thresholdType)
+    {
+    case fixed:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) );
+    case peak:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) );
+    case average:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep
thresholdStep)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold step");
+    #endif
+
+    switch (thresholdStep) {
+    case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) );
+    case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) );
+    case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) );
+    case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) );
+    case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) );
+    case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) );
+    case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) );
+    case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) );
+    default:     INVALID_PARAM;
+    }
+}
+
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement
thresholdDecrement)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold decrement");
+    #endif
+
+    switch (thresholdDecrement) {
+    case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) );
+    case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) );
+    case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) );
+    case dec_once:       return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK)
& ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) );
+    case dec_twice:       return WRITE_REG(REG_OOKPEAK, (
(READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) );
+    case dec_4times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) );
+    case dec_8times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) );
+    case dec_16times:  return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) );
+    default:       INVALID_PARAM;
+    }
+}
+
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+{
+    u8 mask;
+    u8 shift;
+    u8 regaddr;
+    u8 regValue;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: DIO mapping");
+    #endif
+
+    // check DIO number
+    if (DIONumber > 5) INVALID_PARAM;
+
+    switch (DIONumber) {
+    case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break;
+    case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break;
+    case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break;
+    case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break;
+    case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break;
+    case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break;
+    }
+
+    // read reg
+    regValue=READ_REG(regaddr);
+    // delete old value
+    regValue = regValue & ~mask;
+    // add new value
+    regValue = regValue | value << shift;
+    // write back
+    return WRITE_REG(regaddr,regValue);
+}
+
+bool rf69_get_flag(struct spi_device *spi, enum flag flag)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: flag");
+    #endif
+
+    switch(flag) {
+    case modeSwitchCompleted:     return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_MODE_READY);
+    case readyToReceive:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_RX_READY);
+    case readyToSend:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_TX_READY);
+    case pllLocked:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_PLL_LOCK);
+    case rssiExceededThreshold:   return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_RSSI);
+    case timeout:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_TIMEOUT);
+    case automode:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_AUTOMODE);
+    case syncAddressMatch:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+    case fifoFull:              return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_FULL);
+/*    case fifoNotEmpty:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */
+    case fifoEmpty:              return !(READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_NOT_EMPTY);
+    case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_LEVEL);
+    case fifoOverrun:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_OVERRUN);
+    case packetSent:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_PACKET_SENT);
+    case payloadReady:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_PAYLOAD_READY);
+    case crcOk:              return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_CRC_OK);
+    case batteryLow:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_LOW_BAT);
+    default:              return false;
+    }
+}
+
+int rf69_reset_flag(struct spi_device *spi, enum flag flag)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "reset: flag");
+    #endif
+
+    switch(flag) {
+    case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1,
MASK_IRQFLAGS1_RSSI);
+    case syncAddressMatch:        return WRITE_REG(REG_IRQFLAGS1,
MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+    case fifoOverrun:        return WRITE_REG(REG_IRQFLAGS2,
MASK_IRQFLAGS2_FIFO_OVERRUN);
+    default:            INVALID_PARAM;
+    }
+}
+
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: rssi threshold");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RSSITHRESH, threshold);
+}
+
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: start timeout");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RXTIMEOUT1, timeout);
+}
+
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: rssi timeout");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RXTIMEOUT2, timeout);
+}
+
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+{
+    int retval;
+    u8 msb, lsb;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: preample length");
+    #endif
+
+    /* no value check needed - u16 exactly matches register size */
+
+    /* calculate reg settings */
+    msb = (preambleLength&0xff00)   >>  8;
+    lsb = (preambleLength&0xff);
+
+    /* transmit to chip */
+    retval = WRITE_REG(REG_PREAMBLE_MSB, msb);
+    if (retval) return retval;
+    retval = WRITE_REG(REG_PREAMBLE_LSB, lsb);
+
+    return retval;
+}
+
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync enable");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_SYNC_ON) );
+    case optionOff:    return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition
fifoFillCondition)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: fifo fill condition");
+    #endif
+
+    switch(fifoFillCondition) {
+    case always:         return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+    case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+    default:         INVALID_PARAM;
+    }
+}
+
+int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync size");
+    #endif
+
+    // check input value
+    if (syncSize > 0x07)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) &
~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) );
+}
+
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync tolerance");
+    #endif
+
+    // check input value
+    if (syncTolerance > 0x07)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) &
~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance);
+}
+
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+{
+    int retval = 0;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync values");
+    #endif
+
+    retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]);
+    retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]);
+    retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]);
+    retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]);
+    retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]);
+    retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]);
+    retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]);
+    retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]);
+
+    return retval;
+}
+
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat
packetFormat)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: packet format");
+    #endif
+
+    switch(packetFormat) {
+    case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+    case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+    default:          INVALID_PARAM;
+    }
+}
+
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: crc enable");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_CRC_ON) );
+    case optionOff:    return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering
addressFiltering)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: address filtering");
+    #endif
+
+    switch (addressFiltering) {
+    case filteringOff:         return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_OFF) );
+    case nodeAddress:         return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_NODE) );
+    case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) );
+    default:             INVALID_PARAM;
+    }
+}
+
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: payload length");
+    #endif
+
+    return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength);
+}
+
+u8  rf69_get_payload_length(struct spi_device *spi)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: payload length");
+    #endif
+
+    return (u8) READ_REG(REG_PAYLOAD_LENGTH);
+}
+
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: node address");
+    #endif
+
+    return WRITE_REG(REG_NODEADRS, nodeAddress);
+}
+
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: broadcast address");
+    #endif
+
+    return WRITE_REG(REG_BROADCASTADRS, broadcastAddress);
+}
+
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition
txStartCondition)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: start condition");
+    #endif
+
+    switch(txStartCondition) {
+    case fifoLevel:       return WRITE_REG(REG_FIFO_THRESH,
(READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) );
+    case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH,
(READ_REG(REG_FIFO_THRESH) |  MASK_FIFO_THRESH_TXSTART) );
+    default:       INVALID_PARAM;
+    }
+}
+
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
+{
+    int retval;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: fifo threshold");
+    #endif
+
+    // check input value
+    if (threshold & 0x80)
+        INVALID_PARAM;
+
+    // write value
+    retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) &
~MASK_FIFO_THRESH_VALUE) | threshold);
+    if (retval)
+        return retval;
+
+    // access the fifo to activate new threshold
+    return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer
+}
+
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: dagc");
+    #endif
+
+    switch(dagc) {
+    case normalMode:         return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL);
+    case improve:             return WRITE_REG(REG_TESTDAGC,
DAGC_IMPROVED_LOWBETA0);
+    case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC,
DAGC_IMPROVED_LOWBETA1);
+    default:             INVALID_PARAM;
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+    #ifdef DEBUG_FIFO_ACCESS    
+        int i;
+    #endif
+    struct spi_transfer transfer;
+    u8 local_buffer[FIFO_SIZE + 1];
+    int retval;
+
+    if (size > FIFO_SIZE)
+    {
+        #ifdef DEBUG
+            dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then
internal buffer \n");
+        #endif
+        return -EMSGSIZE;
+    }
+
+    /* prepare a bidirectional transfer */
+    local_buffer[0] = REG_FIFO;
+    memset(&transfer, 0, sizeof(transfer));
+      transfer.tx_buf = local_buffer;
+      transfer.rx_buf = local_buffer;
+    transfer.len    = size+1;
+
+    retval = spi_sync_transfer(spi, &transfer, 1);
+
+    #ifdef DEBUG_FIFO_ACCESS
+        for (i=0; i<size; i++)
+            dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]);
+    #endif
+
+    memcpy(buffer, &local_buffer[1], size);  // TODO: ohne memcopy wäre schöner
+
+    return retval;
+}
+
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+    #ifdef DEBUG_FIFO_ACCESS    
+        int i;
+    #endif
+    char spi_address = REG_FIFO | WRITE_BIT;
+    u8 local_buffer[FIFO_SIZE + 1];
+
+    if (size > FIFO_SIZE)
+    {
+        #ifdef DEBUG
+            dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then
internal buffer \n");
+        #endif
+        return -EMSGSIZE;
+    }
+
+    local_buffer[0] = spi_address;
+    memcpy(&local_buffer[1], buffer, size);  // TODO: ohne memcopy wäre schöner
+
+    #ifdef DEBUG_FIFO_ACCESS
+        for (i=0; i<size; i++)
+            dev_dbg(&spi->dev, "0x%x\n",buffer[i]);
+    #endif
+
+    return spi_write (spi, local_buffer, size + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+u8 rf69_read_reg(struct spi_device *spi, u8 addr)
+{
+    int retval;
+
+    retval = spi_w8r8(spi, addr);
+
+    #ifdef DEBUG_VALUES
+        if (retval < 0)
+            /* should never happen, since we already checked,
+               that module is connected. Therefore no error
+               handling, just an optional error message... */
+            dev_dbg(&spi->dev, "read 0x%x FAILED\n",
+                addr);
+        else
+            dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n",
+                retval,
+                addr);
+    #endif
+
+    return retval;
+}
+
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value)
+{
+    int retval;
+    char buffer[2];
+    
+    buffer[0] = addr | WRITE_BIT;
+    buffer[1] = value;
+
+    retval = spi_write(spi, &buffer, 2);
+
+    #ifdef DEBUG_VALUES
+        if (retval < 0)
+            /* should never happen, since we already checked,
+               that module is connected. Therefore no error
+               handling, just an optional error message... */
+            dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n",
+                value,
+                addr);
+        else
+            dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n",
+                value,
+                addr);
+    #endif
+
+    return retval;
+}
+
+
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
new file mode 100644
index 0000000..6a6841b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.h
@@ -0,0 +1,82 @@
+/*
+ * hardware abstraction/register access for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef RF69_H
+#define RF69_H
+
+#include "rf69_enum.h"
+#include "rf69_registers.h"
+
+#define F_OSC         32000000  /* in Hz */
+#define FREQUENCY    433920000 /* in Hz, modifying this value impacts CE
certification */
+#define FIFO_SIZE     66        /* in byte */
+#define FIFO_THRESHOLD    15       /* in byte */
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode);
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode);
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
+enum modulation rf69_get_modulation(struct spi_device *spi);
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping
modShaping);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_deviation(struct spi_device *spi, u32 deviation);
+int rf69_set_frequency(struct spi_device *spi, u32 frequency);
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance
antennaImpedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi);
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum
dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent
dccPercent);
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum
dccPercent dccPercent);
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8
exponent);
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse
mantisse, u8 exponent);
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType
thresholdType);
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep
thresholdStep);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement
thresholdDecrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+bool rf69_get_flag(struct spi_device *spi, enum flag flag);
+int rf69_reset_flag(struct spi_device *spi, enum flag flag);
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition
fifoFillCondition);
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance);
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat
packetFormat);
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering
addressFiltering);
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength);
+u8  rf69_get_payload_length(struct spi_device *spi);
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition
txStartCondition);
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size);
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size);
+
+u8  rf69_read_reg (struct spi_device *spi, u8 addr);
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value);
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_enum.h
b/drivers/staging/pi433/rf69_enum.h
new file mode 100644
index 0000000..fbfb59b
--- /dev/null
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -0,0 +1,201 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_registers.h
b/drivers/staging/pi433/rf69_registers.h
new file mode 100644
index 0000000..d0c4992
--- /dev/null
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -0,0 +1,489 @@
+/*
+ * register description for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*******************************************/
+/* RF69 register addresses           */
+/*******************************************/
+#define  REG_FIFO            0x00
+#define  REG_OPMODE            0x01
+#define  REG_DATAMODUL            0x02
+#define  REG_BITRATE_MSB        0x03
+#define  REG_BITRATE_LSB        0x04
+#define  REG_FDEV_MSB            0x05
+#define  REG_FDEV_LSB            0x06
+#define  REG_FRF_MSB            0x07
+#define  REG_FRF_MID            0x08
+#define  REG_FRF_LSB            0x09
+#define  REG_OSC1            0x0A
+#define  REG_AFCCTRL            0x0B
+#define  REG_LOWBAT            0x0C
+#define  REG_LISTEN1            0x0D
+#define  REG_LISTEN2            0x0E
+#define  REG_LISTEN3            0x0F
+#define  REG_VERSION            0x10
+#define  REG_PALEVEL            0x11
+#define  REG_PARAMP            0x12
+#define  REG_OCP            0x13
+#define  REG_AGCREF            0x14 /* not available on RF69 */
+#define  REG_AGCTHRESH1            0x15 /* not available on RF69 */
+#define  REG_AGCTHRESH2            0x16 /* not available on RF69 */
+#define  REG_AGCTHRESH3            0x17 /* not available on RF69 */
+#define  REG_LNA            0x18
+#define  REG_RXBW            0x19
+#define  REG_AFCBW            0x1A
+#define  REG_OOKPEAK            0x1B
+#define  REG_OOKAVG            0x1C
+#define  REG_OOKFIX            0x1D
+#define  REG_AFCFEI            0x1E
+#define  REG_AFCMSB            0x1F
+#define  REG_AFCLSB            0x20
+#define  REG_FEIMSB            0x21
+#define  REG_FEILSB            0x22
+#define  REG_RSSICONFIG            0x23
+#define  REG_RSSIVALUE            0x24
+#define  REG_DIOMAPPING1        0x25
+#define  REG_DIOMAPPING2        0x26
+#define  REG_IRQFLAGS1            0x27
+#define  REG_IRQFLAGS2            0x28
+#define  REG_RSSITHRESH            0x29
+#define  REG_RXTIMEOUT1            0x2A
+#define  REG_RXTIMEOUT2            0x2B
+#define  REG_PREAMBLE_MSB        0x2C
+#define  REG_PREAMBLE_LSB        0x2D
+#define  REG_SYNC_CONFIG        0x2E
+#define  REG_SYNCVALUE1            0x2F
+#define  REG_SYNCVALUE2            0x30
+#define  REG_SYNCVALUE3            0x31
+#define  REG_SYNCVALUE4            0x32
+#define  REG_SYNCVALUE5            0x33
+#define  REG_SYNCVALUE6            0x34
+#define  REG_SYNCVALUE7            0x35
+#define  REG_SYNCVALUE8            0x36
+#define  REG_PACKETCONFIG1        0x37
+#define  REG_PAYLOAD_LENGTH        0x38
+#define  REG_NODEADRS            0x39
+#define  REG_BROADCASTADRS        0x3A
+#define  REG_AUTOMODES            0x3B
+#define  REG_FIFO_THRESH        0x3C
+#define  REG_PACKETCONFIG2        0x3D
+#define  REG_AESKEY1            0x3E
+#define  REG_AESKEY2            0x3F
+#define  REG_AESKEY3            0x40
+#define  REG_AESKEY4            0x41
+#define  REG_AESKEY5            0x42
+#define  REG_AESKEY6            0x43
+#define  REG_AESKEY7            0x44
+#define  REG_AESKEY8            0x45
+#define  REG_AESKEY9            0x46
+#define  REG_AESKEY10            0x47
+#define  REG_AESKEY11            0x48
+#define  REG_AESKEY12            0x49
+#define  REG_AESKEY13            0x4A
+#define  REG_AESKEY14            0x4B
+#define  REG_AESKEY15            0x4C
+#define  REG_AESKEY16            0x4D
+#define  REG_TEMP1            0x4E
+#define  REG_TEMP2            0x4F
+#define  REG_TESTPA1            0x5A /* only present on RFM69HW */
+#define  REG_TESTPA2            0x5C /* only present on RFM69HW */
+#define  REG_TESTDAGC            0x6F
+
+/******************************************************/
+/* RF69/SX1231 bit definition                */
+/******************************************************/
+/* write bit */
+#define WRITE_BIT                0x80
+
+/* RegOpMode */
+#define  MASK_OPMODE_SEQUENCER_OFF        0x80
+#define  MASK_OPMODE_LISTEN_ON            0x40
+#define  MASK_OPMODE_LISTEN_ABORT        0x20
+#define  MASK_OPMODE_MODE            0x1C
+
+#define  OPMODE_MODE_SLEEP            0x00
+#define  OPMODE_MODE_STANDBY            0x04 /* default */
+#define  OPMODE_MODE_SYNTHESIZER        0x08
+#define  OPMODE_MODE_TRANSMIT            0x0C
+#define  OPMODE_MODE_RECEIVE            0x10
+
+/* RegDataModul */
+#define  MASK_DATAMODUL_MODE            0x06
+#define  MASK_DATAMODUL_MODULATION_TYPE        0x18
+#define  MASK_DATAMODUL_MODULATION_SHAPE    0x03
+
+#define  DATAMODUL_MODE_PACKET            0x00 /* default */
+#define  DATAMODUL_MODE_CONTINUOUS        0x40
+#define  DATAMODUL_MODE_CONTINUOUS_NOSYNC    0x60
+
+#define  DATAMODUL_MODULATION_TYPE_FSK        0x00 /* default */
+#define  DATAMODUL_MODULATION_TYPE_OOK        0x08
+
+#define  DATAMODUL_MODULATION_SHAPE_NONE    0x00 /* default */
+#define  DATAMODUL_MODULATION_SHAPE_1_0        0x01
+#define  DATAMODUL_MODULATION_SHAPE_0_5        0x02
+#define  DATAMODUL_MODULATION_SHAPE_0_3        0x03
+#define  DATAMODUL_MODULATION_SHAPE_BR        0x01
+#define  DATAMODUL_MODULATION_SHAPE_2BR        0x02
+
+/* RegFDevMsb (0x05)*/
+#define FDEVMASB_MASK                0x3f
+
+/*
+// RegOsc1
+#define  OSC1_RCCAL_START            0x80
+#define  OSC1_RCCAL_DONE            0x40
+
+// RegLowBat
+#define  LOWBAT_MONITOR                0x10
+#define  LOWBAT_ON                0x08
+#define  LOWBAT_OFF                0x00  // Default
+
+#define  LOWBAT_TRIM_1695            0x00
+#define  LOWBAT_TRIM_1764            0x01
+#define  LOWBAT_TRIM_1835            0x02  // Default
+#define  LOWBAT_TRIM_1905            0x03
+#define  LOWBAT_TRIM_1976            0x04
+#define  LOWBAT_TRIM_2045            0x05
+#define  LOWBAT_TRIM_2116            0x06
+#define  LOWBAT_TRIM_2185            0x07
+
+
+// RegListen1
+#define  LISTEN1_RESOL_64            0x50
+#define  LISTEN1_RESOL_4100            0xA0  // Default
+#define  LISTEN1_RESOL_262000            0xF0
+
+#define  LISTEN1_CRITERIA_RSSI            0x00  // Default
+#define  LISTEN1_CRITERIA_RSSIANDSYNC        0x08
+
+#define  LISTEN1_END_00                0x00
+#define  LISTEN1_END_01                0x02  // Default
+#define  LISTEN1_END_10                0x04
+
+
+// RegListen2
+#define  LISTEN2_COEFIDLE_VALUE            0xF5 // Default
+
+// RegListen3
+#define  LISTEN3_COEFRX_VALUE            0x20 // Default
+*/
+
+// RegPaLevel
+#define  MASK_PALEVEL_PA0            0x80
+#define  MASK_PALEVEL_PA1            0x40
+#define  MASK_PALEVEL_PA2            0x20
+#define  MASK_PALEVEL_OUTPUT_POWER        0x1F
+
+
+
+// RegPaRamp
+#define  PARAMP_3400                0x00
+#define  PARAMP_2000                0x01
+#define  PARAMP_1000                0x02
+#define  PARAMP_500                0x03
+#define  PARAMP_250                0x04
+#define  PARAMP_125                0x05
+#define  PARAMP_100                0x06
+#define  PARAMP_62                0x07
+#define  PARAMP_50                0x08
+#define  PARAMP_40                0x09 /* default */
+#define  PARAMP_31                0x0A
+#define  PARAMP_25                0x0B
+#define  PARAMP_20                0x0C
+#define  PARAMP_15                0x0D
+#define  PARAMP_12                0x0E
+#define  PARAMP_10                0x0F
+
+#define  MASK_PARAMP                0x0F
+
+/*
+// RegOcp
+#define  OCP_OFF                0x0F
+#define  OCP_ON                    0x1A  // Default
+
+#define  OCP_TRIM_45                0x00
+#define  OCP_TRIM_50                0x01
+#define  OCP_TRIM_55                0x02
+#define  OCP_TRIM_60                0x03
+#define  OCP_TRIM_65                0x04
+#define  OCP_TRIM_70                0x05
+#define  OCP_TRIM_75                0x06
+#define  OCP_TRIM_80                0x07
+#define  OCP_TRIM_85                0x08
+#define  OCP_TRIM_90                0x09
+#define  OCP_TRIM_95                0x0A
+#define  OCP_TRIM_100                0x0B  // Default
+#define  OCP_TRIM_105                0x0C
+#define  OCP_TRIM_110                0x0D
+#define  OCP_TRIM_115                0x0E
+#define  OCP_TRIM_120                0x0F
+*/
+
+/* RegLna (0x18) */
+#define  MASK_LNA_ZIN                0x80
+#define  MASK_LNA_CURRENT_GAIN            0x38
+#define  MASK_LNA_GAIN                0x07
+
+#define  LNA_GAIN_AUTO                0x00 /* default */
+#define  LNA_GAIN_MAX                0x01
+#define  LNA_GAIN_MAX_MINUS_6            0x02
+#define  LNA_GAIN_MAX_MINUS_12            0x03
+#define  LNA_GAIN_MAX_MINUS_24            0x04
+#define  LNA_GAIN_MAX_MINUS_36            0x05
+#define  LNA_GAIN_MAX_MINUS_48            0x06
+
+
+/* RegRxBw (0x19) and RegAfcBw (0x1A) */
+#define  MASK_BW_DCC_FREQ            0xE0
+#define  MASK_BW_MANTISSE            0x18
+#define  MASK_BW_EXPONENT            0x07
+
+#define  BW_DCC_16_PERCENT            0x00
+#define  BW_DCC_8_PERCENT            0x20
+#define  BW_DCC_4_PERCENT            0x40 /* default */
+#define  BW_DCC_2_PERCENT            0x60
+#define  BW_DCC_1_PERCENT            0x80
+#define  BW_DCC_0_5_PERCENT            0xA0
+#define  BW_DCC_0_25_PERCENT            0xC0
+#define  BW_DCC_0_125_PERCENT            0xE0
+
+#define  BW_MANT_16                0x00
+#define  BW_MANT_20                0x08
+#define  BW_MANT_24                0x10 /* default */
+
+
+/* RegOokPeak (0x1B) */
+#define  MASK_OOKPEAK_THRESTYPE            0xc0
+#define  MASK_OOKPEAK_THRESSTEP            0x38
+#define  MASK_OOKPEAK_THRESDEC            0x07
+
+#define  OOKPEAK_THRESHTYPE_FIXED        0x00
+#define  OOKPEAK_THRESHTYPE_PEAK        0x40 /* default */
+#define  OOKPEAK_THRESHTYPE_AVERAGE        0x80
+
+#define  OOKPEAK_THRESHSTEP_0_5_DB        0x00 /* default */
+#define  OOKPEAK_THRESHSTEP_1_0_DB        0x08
+#define  OOKPEAK_THRESHSTEP_1_5_DB        0x10
+#define  OOKPEAK_THRESHSTEP_2_0_DB        0x18
+#define  OOKPEAK_THRESHSTEP_3_0_DB        0x20
+#define  OOKPEAK_THRESHSTEP_4_0_DB        0x28
+#define  OOKPEAK_THRESHSTEP_5_0_DB        0x30
+#define  OOKPEAK_THRESHSTEP_6_0_DB        0x38
+
+#define  OOKPEAK_THRESHDEC_ONCE            0x00 /* default */
+#define  OOKPEAK_THRESHDEC_EVERY_2ND        0x01
+#define  OOKPEAK_THRESHDEC_EVERY_4TH        0x02
+#define  OOKPEAK_THRESHDEC_EVERY_8TH        0x03
+#define  OOKPEAK_THRESHDEC_TWICE        0x04
+#define  OOKPEAK_THRESHDEC_4_TIMES        0x05
+#define  OOKPEAK_THRESHDEC_8_TIMES        0x06
+#define  OOKPEAK_THRESHDEC_16_TIMES        0x07
+
+/*
+// RegOokAvg
+#define  OOKAVG_AVERAGETHRESHFILT_00        0x00
+#define  OOKAVG_AVERAGETHRESHFILT_01        0x40
+#define  OOKAVG_AVERAGETHRESHFILT_10        0x80  // Default
+#define  OOKAVG_AVERAGETHRESHFILT_11        0xC0
+
+
+// RegAfcFei
+#define  AFCFEI_FEI_DONE            0x40
+#define  AFCFEI_FEI_START            0x20
+#define  AFCFEI_AFC_DONE            0x10
+#define  AFCFEI_AFCAUTOCLEAR_ON            0x08
+#define  AFCFEI_AFCAUTOCLEAR_OFF        0x00  // Default
+
+#define  AFCFEI_AFCAUTO_ON            0x04
+#define  AFCFEI_AFCAUTO_OFF            0x00  // Default
+
+#define  AFCFEI_AFC_CLEAR            0x02
+#define  AFCFEI_AFC_START            0x01
+
+// RegRssiConfig
+#define  RSSI_FASTRX_ON                0x08
+#define  RSSI_FASTRX_OFF            0x00  // Default
+#define  RSSI_DONE                0x02
+#define  RSSI_START                0x01
+*/
+
+/* RegDioMapping1 */
+#define  MASK_DIO0                0xC0
+#define  MASK_DIO1                0x30
+#define  MASK_DIO2                0x0C
+#define  MASK_DIO3                0x03
+#define  SHIFT_DIO0                6
+#define  SHIFT_DIO1                4
+#define  SHIFT_DIO2                2
+#define  SHIFT_DIO3                0
+
+/* RegDioMapping2 */
+#define  MASK_DIO4                0xC0
+#define  MASK_DIO5                0x30
+#define  SHIFT_DIO4                6
+#define  SHIFT_DIO5                4
+
+/* DIO numbers */
+#define  DIO0                    0
+#define  DIO1                    1
+#define  DIO2                    2
+#define  DIO3                    3
+#define  DIO4                    4
+#define  DIO5                    5
+
+/* DIO Mapping values (packet mode) */
+#define  DIO_ModeReady_DIO4            0x00
+#define  DIO_ModeReady_DIO5            0x03
+#define  DIO_ClkOut                0x00
+#define  DIO_Data                0x01
+#define  DIO_TimeOut_DIO1            0x03
+#define  DIO_TimeOut_DIO4            0x00
+#define  DIO_Rssi_DIO0                0x03
+#define  DIO_Rssi_DIO3_4            0x01
+#define  DIO_RxReady                0x02
+#define  DIO_PLLLock                0x03
+#define  DIO_TxReady                0x01
+#define  DIO_FifoFull_DIO1            0x01
+#define  DIO_FifoFull_DIO3            0x00
+#define  DIO_SyncAddress            0x02
+#define  DIO_FifoNotEmpty_DIO1            0x02
+#define  DIO_FifoNotEmpty_FIO2            0x00
+#define  DIO_Automode                0x04
+#define  DIO_FifoLevel                0x00
+#define  DIO_CrcOk                0x00
+#define  DIO_PayloadReady            0x01
+#define  DIO_PacketSent                0x00
+#define  DIO_Dclk                0x00
+
+/* RegDioMapping2 CLK_OUT part */
+#define  MASK_DIOMAPPING2_CLK_OUT        0x07
+
+#define  DIOMAPPING2_CLK_OUT_NO_DIV        0x00
+#define  DIOMAPPING2_CLK_OUT_DIV_2        0x01
+#define  DIOMAPPING2_CLK_OUT_DIV_4        0x02
+#define  DIOMAPPING2_CLK_OUT_DIV_8        0x03
+#define  DIOMAPPING2_CLK_OUT_DIV_16        0x04
+#define  DIOMAPPING2_CLK_OUT_DIV_32        0x05
+#define  DIOMAPPING2_CLK_OUT_RC            0x06
+#define  DIOMAPPING2_CLK_OUT_OFF        0x07 /* default */
+
+/* RegIrqFlags1 */
+#define  MASK_IRQFLAGS1_MODE_READY        0x80
+#define  MASK_IRQFLAGS1_RX_READY        0x40
+#define  MASK_IRQFLAGS1_TX_READY        0x20
+#define  MASK_IRQFLAGS1_PLL_LOCK        0x10
+#define  MASK_IRQFLAGS1_RSSI            0x08
+#define  MASK_IRQFLAGS1_TIMEOUT            0x04
+#define  MASK_IRQFLAGS1_AUTOMODE        0x02
+#define  MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH    0x01
+
+/* RegIrqFlags2 */
+#define  MASK_IRQFLAGS2_FIFO_FULL        0x80
+#define  MASK_IRQFLAGS2_FIFO_NOT_EMPTY        0x40
+#define  MASK_IRQFLAGS2_FIFO_LEVEL        0x20
+#define  MASK_IRQFLAGS2_FIFO_OVERRUN        0x10
+#define  MASK_IRQFLAGS2_PACKET_SENT        0x08
+#define  MASK_IRQFLAGS2_PAYLOAD_READY        0x04
+#define  MASK_IRQFLAGS2_CRC_OK            0x02
+#define  MASK_IRQFLAGS2_LOW_BAT            0x01
+
+/* RegSyncConfig */
+#define  MASK_SYNC_CONFIG_SYNC_ON        0x80 /* default */
+#define  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION    0x40
+#define  MASK_SYNC_CONFIG_SYNC_SIZE        0x38
+#define  MASK_SYNC_CONFIG_SYNC_TOLERANCE    0x07
+
+/* RegPacketConfig1 */
+#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE    0x80
+#define  MASK_PACKETCONFIG1_DCFREE            0x60
+#define  MASK_PACKETCONFIG1_CRC_ON            0x10 /* default */
+#define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF        0x08
+#define  MASK_PACKETCONFIG1_ADDRESSFILTERING        0x06
+
+#define  PACKETCONFIG1_DCFREE_OFF            0x00 /* default */
+#define  PACKETCONFIG1_DCFREE_MANCHESTER        0x20
+#define  PACKETCONFIG1_DCFREE_WHITENING            0x40
+#define  PACKETCONFIG1_ADDRESSFILTERING_OFF        0x00 /* default */
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODE        0x02
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST    0x04
+
+/*
+// RegAutoModes
+#define  AUTOMODES_ENTER_OFF            0x00  // Default
+#define  AUTOMODES_ENTER_FIFONOTEMPTY        0x20
+#define  AUTOMODES_ENTER_FIFOLEVEL        0x40
+#define  AUTOMODES_ENTER_CRCOK            0x60
+#define  AUTOMODES_ENTER_PAYLOADREADY        0x80
+#define  AUTOMODES_ENTER_SYNCADRSMATCH        0xA0
+#define  AUTOMODES_ENTER_PACKETSENT        0xC0
+#define  AUTOMODES_ENTER_FIFOEMPTY        0xE0
+
+#define  AUTOMODES_EXIT_OFF            0x00  // Default
+#define  AUTOMODES_EXIT_FIFOEMPTY        0x04
+#define  AUTOMODES_EXIT_FIFOLEVEL        0x08
+#define  AUTOMODES_EXIT_CRCOK            0x0C
+#define  AUTOMODES_EXIT_PAYLOADREADY        0x10
+#define  AUTOMODES_EXIT_SYNCADRSMATCH        0x14
+#define  AUTOMODES_EXIT_PACKETSENT        0x18
+#define  AUTOMODES_EXIT_RXTIMEOUT        0x1C
+
+#define  AUTOMODES_INTERMEDIATE_SLEEP        0x00  // Default
+#define  AUTOMODES_INTERMEDIATE_STANDBY        0x01
+#define  AUTOMODES_INTERMEDIATE_RECEIVER    0x02
+#define  AUTOMODES_INTERMEDIATE_TRANSMITTER    0x03
+
+*/
+/* RegFifoThresh (0x3c) */
+#define  MASK_FIFO_THRESH_TXSTART        0x80
+#define  MASK_FIFO_THRESH_VALUE            0x7F
+
+/*
+
+// RegPacketConfig2
+#define  PACKET2_RXRESTARTDELAY_1BIT        0x00  // Default
+#define  PACKET2_RXRESTARTDELAY_2BITS        0x10
+#define  PACKET2_RXRESTARTDELAY_4BITS        0x20
+#define  PACKET2_RXRESTARTDELAY_8BITS        0x30
+#define  PACKET2_RXRESTARTDELAY_16BITS        0x40
+#define  PACKET2_RXRESTARTDELAY_32BITS        0x50
+#define  PACKET2_RXRESTARTDELAY_64BITS        0x60
+#define  PACKET2_RXRESTARTDELAY_128BITS        0x70
+#define  PACKET2_RXRESTARTDELAY_256BITS        0x80
+#define  PACKET2_RXRESTARTDELAY_512BITS        0x90
+#define  PACKET2_RXRESTARTDELAY_1024BITS    0xA0
+#define  PACKET2_RXRESTARTDELAY_2048BITS    0xB0
+#define  PACKET2_RXRESTARTDELAY_NONE        0xC0
+#define  PACKET2_RXRESTART            0x04
+
+#define  PACKET2_AUTORXRESTART_ON        0x02  // Default
+#define  PACKET2_AUTORXRESTART_OFF        0x00
+
+#define  PACKET2_AES_ON                0x01
+#define  PACKET2_AES_OFF            0x00  // Default
+
+
+// RegTemp1
+#define  TEMP1_MEAS_START            0x08
+#define  TEMP1_MEAS_RUNNING            0x04
+#define  TEMP1_ADCLOWPOWER_ON            0x01  // Default
+#define  TEMP1_ADCLOWPOWER_OFF            0x00
+*/
+
+// RegTestDagc (0x6F)
+#define  DAGC_NORMAL                0x00 /* Reset value */
+#define  DAGC_IMPROVED_LOWBETA1            0x20
+#define  DAGC_IMPROVED_LOWBETA0            0x30 /* Recommended val */
 
 
 
 

> Greg KH <gregkh@linuxfoundation.org> hat am 12. Juli 2017 um 09:43
> geschrieben:
>
>
> On Tue, Jul 11, 2017 at 06:02:09PM +0200, Marcus Wolf wrote:
> > Hi folks,
> >
> > I developed a radio shield for the 433MHz ISM band [0] for the Raspberry Pi.
> > This shield is called Pi433 [1]. It can be used to communicate between two
> > Raspberries or to control third party equipment e. g. cheap radio sockets
> > [2].
> > The base of this radio shield is a radio module from HopeRf - a
> > rfm69cw-433s2.
> >
> > In the beginning, I conrolled the rf69 chip by direct access via SPI, but I
> > figured out, that several tasks were hard to handle. Especially the
> > following
> > points were annoying:
> > * Just one process could open the SPI interface so just one process was
> > able to access the module
> > * A simultaneous send and receive was very hard to implement
> >
> > Therefore I started to implement a driver.
> > The drivers features:
> > * simple access/nice abstraction of spi registers via open, close,
> > read, write and ioctl
> > * multiple applications can open
> > * tx requests are queued, so every app can send a tx request at any time
> > * first app asking for rx will block other apps, also asking for rx until
> > one
> > rx
> > cycle is complete
> > * rx cycle means listening on the air until something appears
> > * if an app wants to tx during the driver is waiting in rx cycle, rx will be
> > shortly interrupted to do the tx task
> > * for each tx task a seperate configuration of the rf chip (bitrate,
> > modulation, ...)
> > can be chosen
> > * wrtten in modular architecture, allowing to extend for other products with
> > rf69 chip (e.g. rfm69hcw, ...) or even to support other HopeRf chips with
> > similar
> > interface (e. g. rfm12, rfm95, ...)
> >
> > In principle the driver was intended to be used by my project
> > (Smarthome-Pi),
> > only.
> > But while having all this nice features, I was asked, whether I could offer
> > the
> > driver to the community. I never did that before, so I started reading about
> > submitting drivers and figured out, that there is a lot of work to do, to
> > meet
> > all
> > concepts and ideas of complying to kernel code. I spend some days and
> > modified
> > a lot, but still, a lot of things aren't perfect.
> > Already known tasks are:
> >
> > * coding style does not fully comply with the kernel style guide.
> > * still TODOs, annotated in the code
> > * currently the code introduces new IOCTLs. I'm afraid this is a bad idea.
> > Replace this with another interface, hints are welcome!
> >
> > I tested the patch on Raspbian with Kernel v4.12 and applied the patch on
> > mainline Linux v4.12
> >
> > Is it posibble to integrate into the staging area to ease further
> > development?
>
> Sure, I'm always glad to take new drivers, but can you submit it as just
> a single patch, and keep it self-contained (i.e. nothing outside of
> drivers/staging/YOUR_DRIVER/)?
>
> thanks,
>
> greg k-h
>

[-- Attachment #2: Type: text/html, Size: 220761 bytes --]

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 11:24       ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-15 11:24 UTC (permalink / raw)
  To: Marcus Wolf; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

On Sat, Jul 15, 2017 at 01:15:43PM +0200, Marcus Wolf wrote:
> Hi Greg,
>  
> thanks for your reply :-)
>  
> Today I moved the documentation and header files to drivers/staging/pi433 and
> fromated it as a single patch.
>  
> Cheers,
>  
> Marcus

I still need it in a format I can apply it in (i.e. proper subject,
changelog text, signed-off-by, etc.)  Can you do that?

Also, for staging drivers, I need a TODO file, much like the existing
drivers/staging/*/TODO files saying what needs to be done with the code
in order to get it out of staging.

And finally, your patch seemed to have the whitespace corrupted and was
line-wrapped, making it impossible to apply even if I could have :(

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 11:24       ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-15 11:24 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Sat, Jul 15, 2017 at 01:15:43PM +0200, Marcus Wolf wrote:
> Hi Greg,
>  
> thanks for your reply :-)
>  
> Today I moved the documentation and header files to drivers/staging/pi433 and
> fromated it as a single patch.
>  
> Cheers,
>  
> Marcus

I still need it in a format I can apply it in (i.e. proper subject,
changelog text, signed-off-by, etc.)  Can you do that?

Also, for staging drivers, I need a TODO file, much like the existing
drivers/staging/*/TODO files saying what needs to be done with the code
in order to get it out of staging.

And finally, your patch seemed to have the whitespace corrupted and was
line-wrapped, making it impossible to apply even if I could have :(

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
  2017-07-15 11:24       ` Greg KH
  (?)
@ 2017-07-15 12:26       ` Marcus Wolf
  -1 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-15 12:26 UTC (permalink / raw)
  To: Greg KH; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

[-- Attachment #1: Type: text/plain, Size: 1360 bytes --]

Hi Greg,

> I still need it in a format I can apply it in (i.e. proper subject,
> changelog text, signed-off-by, etc.) Can you do that?
 
Yes, I will. But I need to know how. The patch on the first mail, I generated by
git format-patch master --stdout -p > pi433_patch
But that lead to several patches - one for each commit I did on my local git
repo.
Today, I searched on the net, how to squasch it together in one patch and found
git diff master > pi433_patch
 
 
Sorry for annoying you with newbie-problems,
 
Marcus

> Greg KH <gregkh@linuxfoundation.org> hat am 15. Juli 2017 um 13:24
> geschrieben:
>
>
> On Sat, Jul 15, 2017 at 01:15:43PM +0200, Marcus Wolf wrote:
> > Hi Greg,
> >
> > thanks for your reply :-)
> >
> > Today I moved the documentation and header files to drivers/staging/pi433
> > and
> > fromated it as a single patch.
> >
> > Cheers,
> >
> > Marcus
>
> I still need it in a format I can apply it in (i.e. proper subject,
> changelog text, signed-off-by, etc.) Can you do that?
>
> Also, for staging drivers, I need a TODO file, much like the existing
> drivers/staging/*/TODO files saying what needs to be done with the code
> in order to get it out of staging.
>
> And finally, your patch seemed to have the whitespace corrupted and was
> line-wrapped, making it impossible to apply even if I could have :(
>
> thanks,
>
> greg k-h
>

[-- Attachment #2: Type: text/html, Size: 1926 bytes --]

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 12:59         ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-15 12:59 UTC (permalink / raw)
  To: Greg KH; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

Hi!
 
It's me again. Seems like I also need help on sending the email :-/
 
I checked the whitespace/line wrap problem, but couldn't find any suspicious
lines.
 
What I did:
* Looked into my outbox - the copy of my mail to you seems to be okay...
* I sent the patch once again (just to me) - result: Seems to be fine, too.
 
Maybe you can bounce back my mail? Maybe I'll get an idea what went wrong, if I
see the smashed code...
 
Cheers,
 
Marcus
 

> Greg KH <gregkh@linuxfoundation.org> hat am 15. Juli 2017 um 13:24
> geschrieben:
>
>
> On Sat, Jul 15, 2017 at 01:15:43PM +0200, Marcus Wolf wrote:
> > Hi Greg,
> >
> > thanks for your reply :-)
> >
> > Today I moved the documentation and header files to drivers/staging/pi433
> > and
> > fromated it as a single patch.
> >
> > Cheers,
> >
> > Marcus
>
> I still need it in a format I can apply it in (i.e. proper subject,
> changelog text, signed-off-by, etc.) Can you do that?
>
> Also, for staging drivers, I need a TODO file, much like the existing
> drivers/staging/*/TODO files saying what needs to be done with the code
> in order to get it out of staging.
>
> And finally, your patch seemed to have the whitespace corrupted and was
> line-wrapped, making it impossible to apply even if I could have :(
>
> thanks,
>
> greg k-h
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 12:59         ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-15 12:59 UTC (permalink / raw)
  To: Greg KH
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi!
 
It's me again. Seems like I also need help on sending the email :-/
 
I checked the whitespace/line wrap problem, but couldn't find any suspicious
lines.
 
What I did:
* Looked into my outbox - the copy of my mail to you seems to be okay...
* I sent the patch once again (just to me) - result: Seems to be fine, too.
 
Maybe you can bounce back my mail? Maybe I'll get an idea what went wrong, if I
see the smashed code...
 
Cheers,
 
Marcus
 

> Greg KH <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org> hat am 15. Juli 2017 um 13:24
> geschrieben:
>
>
> On Sat, Jul 15, 2017 at 01:15:43PM +0200, Marcus Wolf wrote:
> > Hi Greg,
> >
> > thanks for your reply :-)
> >
> > Today I moved the documentation and header files to drivers/staging/pi433
> > and
> > fromated it as a single patch.
> >
> > Cheers,
> >
> > Marcus
>
> I still need it in a format I can apply it in (i.e. proper subject,
> changelog text, signed-off-by, etc.) Can you do that?
>
> Also, for staging drivers, I need a TODO file, much like the existing
> drivers/staging/*/TODO files saying what needs to be done with the code
> in order to get it out of staging.
>
> And finally, your patch seemed to have the whitespace corrupted and was
> line-wrapped, making it impossible to apply even if I could have :(
>
> thanks,
>
> greg k-h
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 13:02           ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-15 13:02 UTC (permalink / raw)
  To: Marcus Wolf; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

On Sat, Jul 15, 2017 at 02:59:25PM +0200, Marcus Wolf wrote:
> Hi!
>  
> It's me again. Seems like I also need help on sending the email :-/
>  
> I checked the whitespace/line wrap problem, but couldn't find any suspicious
> lines.
>  
> What I did:
> * Looked into my outbox - the copy of my mail to you seems to be okay...
> * I sent the patch once again (just to me) - result: Seems to be fine, too.
>  
> Maybe you can bounce back my mail? Maybe I'll get an idea what went wrong, if I
> see the smashed code...

You sent the patch in html format, which caused all of the whitespace
corruption.  html will not work for kernel patches for obvious reasons
:)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 13:02           ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-15 13:02 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Sat, Jul 15, 2017 at 02:59:25PM +0200, Marcus Wolf wrote:
> Hi!
>  
> It's me again. Seems like I also need help on sending the email :-/
>  
> I checked the whitespace/line wrap problem, but couldn't find any suspicious
> lines.
>  
> What I did:
> * Looked into my outbox - the copy of my mail to you seems to be okay...
> * I sent the patch once again (just to me) - result: Seems to be fine, too.
>  
> Maybe you can bounce back my mail? Maybe I'll get an idea what went wrong, if I
> see the smashed code...

You sent the patch in html format, which caused all of the whitespace
corruption.  html will not work for kernel patches for obvious reasons
:)

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 13:10             ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-15 13:10 UTC (permalink / raw)
  To: Greg KH; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

Hi!
 
Ok. Thanks for the info. Didn't observe that.
 I'll give the old patch another try.
 
I will send a new patch as soon, as I know. how to produce the 
poper format (with subjects, signing and so on).

Cheers,

Marcus

 
 
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 268d4e6..fdf060c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"
 
 source "drivers/staging/typec/Kconfig"
 
+source "drivers/staging/pi433/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b93e6f5..998f644 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)        += ks7010/
 obj-$(CONFIG_GREYBUS)        += greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)    += vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)    += ccree/
+obj-$(CONFIG_PI433)        += pi433/
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
new file mode 100644
index 0000000..004b502
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
@@ -0,0 +1,53 @@
+// Definitions for Pi433
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+    fragment@1 {
+        target = <&gpio>;
+        __overlay__ {
+            pi433_pins: pi433_pins {
+                brcm,pins = <7 25 24>;
+                brcm,function = <0 0 0>; // in in in
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&spi0>;
+        __overlay__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            status = "okay";
+
+            pi433: pi433@0 {
+                compatible = "Smarthome-Wolf,pi433";
+                reg = <0>;
+                spi-max-frequency = <10000000>;
+                status = "okay";
+
+                pinctrl-0 = <&pi433_pins>;
+                DIO0-gpio = <&gpio 24 0>;
+                DIO1-gpio = <&gpio 25 0>;
+                DIO2-gpio = <&gpio  7 0>;
+            };
+        };
+    };
+};
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt
b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
new file mode 100644
index 0000000..14197c6
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
@@ -0,0 +1,62 @@
+* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see
www.pi433.de)
+
+Required properties:
+- compatible: must be "Smarthome-Wolf,pi433"
+- reg: chip select of SPI Interface
+- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69
module
+
+
+Example:
+
+With the following lines in gpio-section, the gpio pins, connected with pi433
are
+reserved/declared.
+
+&gpio{
+    [...]
+
+    pi433_pins: pi433_pins {
+        brcm,pins = <7 25 24>;
+        brcm,function = <0 0 0>; // in in in
+    };
+
+    [...]
+}
+
+With the following lines in spi section, the device pi433 is declared.
+It consists of the three gpio pins and an spi interface (here chip select 0)
+
+&spi0{
+    [...]
+
+    pi433: pi433@0 {
+        compatible = "Smarthome-Wolf,pi433";
+        reg = <0>; /* CE 0 */
+        #address-cells = <1>;
+        #size-cells = <0>;
+        spi-max-frequency = <10000000>;
+
+        pinctrl-0 = <&pi433_pins>;
+        DIO0-gpio = <&gpio 24 0>;
+        DIO1-gpio = <&gpio 25 0>;
+        DIO2-gpio = <&gpio  7 0>;
+    };
+}
+
+
+
+For Raspbian users only
+=======================
+Since Raspbian supports device tree overlays, you may use and overlay, instead
+of editing your boards device tree.
+For using the overlay, you need to compile the file pi433-overlay.dts you can
+find aside to this documentation.
+The file needs to be compiled - either manually or by integration in your
kernel
+source tree. For a manual compile, you may use a command line like the
following:
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+arch/arm/boot/dts/overlays and you need to add the file to the list of files
+in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
+kernel make files compile the device tree overlay for you.
+
+
diff --git a/drivers/staging/pi433/Documentation/pi433.txt
b/drivers/staging/pi433/Documentation/pi433.txt
new file mode 100644
index 0000000..860dd0f
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -0,0 +1,274 @@
+=====
+Pi433
+=====
+
+
+Introduction
+============
+This driver is for controlling pi433, a radio module for the Raspberry Pi
+(www.pi433.de). It supports transmission and reception. It can be opened
+by multiple applications for transmission and reception. While transmit
+jobs were queued and process automatically in the background, the first  
+application asking for reception will block out all other applications  
+until something gets received terminates the read request.  
+The driver supports on the fly reloading of the hardware fifo of the rf
+chip, thus enabling for much longer telegrams then hardware fifo size.
+
+Discription of driver operation
+===============================
+
+a) transmission
+
+Each transmission can take place with a different configuration of the rf
+module. Therfore each application can set its own set of parameters. The driver
+takes care, that each transmission takes place with the parameterset of the
+application, that requests the transmission. To allow the transmission to take
+place in the background, a tx thread is introduced.
+The transfer of data from the main thread to the tx thread is realised by a
+kfifo. With each write request of an application, the passed in data and the
+corresponding parameter set gets written to the kfifo.  
+On the other "side" of the kfifo, the tx thread continuously checks, whether
the
+kfifo is empty. If not, it gets one set of config and data from the kfifo. If  
+there is no receive request or the receiver is still waiting for something in
+the air, the rf module is set to standby, the parameters for transmission gets
+set, the hardware fifo of the rf chip gets preloaded and the transmission gets
+started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling
+much longer telegrams then hardware fifo size. If the telegram is send and
there
+is more data available in the kfifo, the procedure is repeated. If not the
+transmission cycle ends.
+
+b) reception
+
+Since there is only one application allowed to receive data at a time, for
+reception there is only one configuration set.
+As soon as an application sets an request for receiving a telegram, the
reception
+configuration set is written to the rf module and it gets set into receiving
mode.  
+Now the driver is waiting, that a predefined RSSI level (signal strength at the
+receiver) is reached. Until this hasn't happened, the reception can be
+interrupted by the transmission thread at any time to insert a transmission
cycle.
+As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar
+as described for the transmission cycle the read out of the hardware fifo is
done
+dynamically. Upon each hardware fifo threshold interrupt, a portion of data
gets
+read. So also for reception it is possible to receive more data then the
hardware
+fifo can hold.
+
+
+Driver API
+==========
+
+The driver is currently implemented as a character device. Therefore it
supports
+the calls open, ioctl, read, write and close.
+
+
+params for ioctl
+----------------
+
+There are four options:  
+PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver
+PI433_IOC_WR_TX_CFG - set the transmission parameters
+PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver
+PI433_IOC_WR_RX_CFG - set the receiving parameters  
+
+The tx configuration is transfered via struct pi433_tx_cfg, the parameterset
for transmission.  
+It is devided into two sections: rf parameters and packet format.
+
+rf params:
+    frequency
+        frequency used for transmission.  
+        Allowed values: 433050000...434790000
+    bit_rate
+        bit rate used for transmission.  
+        Allowed values: #####
+    dev_frequency
+        frequency deviation in case of FSK.  
+        Allowed values: 600...500000
+    modulation
+        FSK - frequency shift key
+        OOK - On-Off-key
+    modShaping
+        shapingOff    - no shaping
+        shaping1_0    - gauss filter with BT 1 (FSK only)
+        shaping0_5    - gauss filter with BT 0.5 (FSK only)
+        shaping0_3    - gauss filter with BT 0.3 (FSK only)
+        shapingBR    - filter cut off at BR (OOK only)
+        shaping2BR    - filter cut off at 2*BR (OOK only)
+    paRamp (FSK only)
+        ramp3400    - amp ramps up in 3.4ms
+        ramp2000    - amp ramps up in 2.0ms
+        ramp1000    - amp ramps up in 1ms
+        ramp500        - amp ramps up in 500us
+        ramp250        - amp ramps up in 250us
+        ramp125        - amp ramps up in 125us
+        ramp100        - amp ramps up in 100us
+        ramp62        - amp ramps up in 62us
+        ramp50        - amp ramps up in 50us
+        ramp40        - amp ramps up in 40us
+        ramp31        - amp ramps up in 31us
+        ramp25        - amp ramps up in 25us
+        ramp20        - amp ramps up in 20us
+        ramp15        - amp ramps up in 15us
+        ramp12        - amp ramps up in 12us
+        ramp10        - amp ramps up in 10us
+    tx_start_condition
+        fifoLevel    - transmission starts, if fifo is filled to
+                  threshold level
+        fifoNotEmpty    - transmission starts, as soon as there is one
+                  byte in internal fifo
+    repetitions
+        This gives the option, to send a telegram multiple times. Default: 1
+
+packet format:
+    enable_preamble
+        optionOn    - a preamble will be automatically generated
+        optionOff    - no preamble will be generated
+    enable_sync
+        optionOn    - a sync word will be automatically added to
+                  the telegram after preamble
+        optionOff    - no sync word will be added
+        Attention: While possible to generate sync without preamble, the
+        receiver won't be able to detect the sync without preamble.
+    enable_length_byte
+        optionOn    - the length of the telegram will be automatically
+                  added to the telegram. It's part of the payload
+        optionOff    - no length information will be automatically added
+                  to the telegram.
+        Attention: For telegram length over 255 bytes, this option can't be
used
+        Attention: should be used in combination with sync, only
+    enable_address_byte
+        optionOn    - the address byte will be automatically added to the
+                  telgram. It's part of the payload
+        optionOff    - the address byte will not be added to the telegram.
+        The address byte can be used for address filtering, so the receiver
+        will only receive telegrams with a given address byte.
+        Attention: should be used in combination with sync, only
+    enable_crc
+        optionOn    - an crc will be automatically calculated over the
+                  payload of the telegram and added to the telegram
+                  after payload.
+        optionOff    - no crc will be calculated        
+    preamble_length
+        length of the preamble. Allowed values: 0...65536
+    sync_length
+        length of the sync word. Allowed values: 0...8
+    fixed_message_length
+        length of the payload of the telegram. Will override the length
+        given by the buffer, passed in with the write command. Will be
+        ignored if set to zero.
+    sync_pattern[8]
+        contains up to eight values, that are used as the sync pattern
+        on sync option
+    address_byte
+        one byte, used as address byte on address byte option.
+
+
+The rx configuration is transfered via struct pi433_rx_cfg, the parameterset
for receiving. It is devided into two sections: rf parameters and packet format.
+
+rf params:
+    frequency
+        frequency used for transmission.  
+        Allowed values: 433050000...434790000
+    bit_rate
+        bit rate used for transmission.
+        Allowed values: #####
+    dev_frequency
+        frequency deviation in case of FSK.
+        Allowed values: 600...500000
+    modulation
+        FSK - frequency shift key
+        OOK - on off key
+    rssi_threshold
+        threshold value for the signal strength on the receiver input.
+        If this value is exeeded, a reception cycle starts
+        Allowed values: 0...255
+    thresholdDecrement
+        in order to adapt to different levels of singnal strength, over
+        time the receiver gets more and more sensitive. This value  
+        determs, how fast the sensitivity increases.
+        step_0_5db    - increase in 0,5dB steps
+        step_1_0db    - increase in 1 db steps
+        step_1_5db    - increase in 1,5dB steps
+        step_2_0db    - increase in 2 db steps
+        step_3_0db    - increase in 3 db steps
+        step_4_0db    - increase in 4 db steps
+        step_5_0db    - increase in 5 db steps
+        step_6_0db    - increase in 6 db steps
+    antennaImpedance
+        sets the electrical adoption of the antenna
+        fiftyOhm    - for antennas with an impedance of 50Ohm
+        twohundretOhm    - for antennas with an impedance of 200Ohm
+    lnaGain
+        sets the gain of the low noise amp
+        automatic    - lna gain is determed by an agc
+        max        - lna gain is set to maximum
+        maxMinus6    - lna gain is set to  6db below max
+        maxMinus12    - lna gain is set to 12db below max
+        maxMinus24    - lna gain is set to 24db below max
+        maxMinus36    - lna gain is set to 36db below max
+        maxMinus48    - lna gain is set to 48db below max
+    bw_mantisse
+        sets the bandwidth of the channel filter - part one: mantisse.  
+        mantisse16    - mantisse is set to 16
+        mantisse20    - mantisse is set to 20
+        mantisse24    - mantisse is set to 24
+    bw_exponent
+        sets the bandwidth of the channel filter - part two: exponent.  
+        Allowd values: 0...7
+    dagc;
+        operation mode of the digital automatic gain control
+        normalMode
+        improve
+        improve4LowModulationIndex
+
+ packet format:
+    enable_sync
+        optionOn  - sync detection is enabled. If configured sync pattern
+                isn't found, telegram will be internally discarded  
+        optionOff - sync detection is disabled.
+    enable_length_byte
+        optionOn   - First byte of payload will be used as length byte,  
+                 regardless of the amount of bytes that were requested  
+                 by the read request.
+        optionOff  - Number of bytes to be read will be set according to
+                 amount of bytes that were requested by the read request.
+        Attention: should be used in combination with sync, only
+    enable_address_filtering;
+        filteringOff        - no adress filtering will take place
+        nodeAddress        - all telegrams, not matching the node  
+                      address will be internally discarded
+        nodeOrBroadcastAddress    - all telegrams, neither matching the
+                      node, nor the broadcast address will
+                      be internally discarded
+        Attention: Sync option must be enabled in order to use this feature
+    enable_crc
+        optionOn    - a crc will be calculated over the payload of
+                  the telegram, that was received. If the
+                  calculated crc doesn't match to two bytes,
+                  that follow the payload, the telegram will be
+                  internally discarded.
+        Attention: This option is only operational, if sync on and fixed length
+        or length byte is used
+    sync_length
+        Gives the length of the payload.  
+        Attention: This setting must meet the setting of the transmitter,
+        if sync option is used.
+    fixed_message_length
+        Overrides the telegram length either given by the first byte of
+        payload or by the read request.
+    bytes_to_drop
+        gives the number of bytes, that will be dropped before transfering
+        data to the read buffer
+        This option is only usefull, if all packet helper are switched
+        off and the rf chip is used in raw receiving mode. This may be
+        needed, if a telegram of a third party device should be received,
+        using a protocol not compatible with the packet engine of the rf69
chip.
+    sync_pattern[8]
+        contains up to eight values, that are used as the sync pattern
+        on sync option.
+        This setting must meet the configuration of the transmitting device,
+        if sync option is enabled.
+    node_address
+        one byte, used as node address byte on address byte option.
+    broadcast_address
+        one byte, used as broadcast address byte on address byte option.
+        
+
diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
new file mode 100644
index 0000000..61b4b4e
--- /dev/null
+++ b/drivers/staging/pi433/Kconfig
@@ -0,0 +1,16 @@
+config PI433
+        tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
+        default n
+        ---help---
+          This option allows you to enable support for the radio module Pi433.
+
+          Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi
+          or compatible. It extends the Raspberry Pi with the option, to
+          send and receive data in the 433MHz ISM band - for example to
+          communicate between two systems without using ethernet or bluetooth
+          or for control or read sockets, actors, sensors, widely available
+          for low price.
+
+          For details or the option to buy, please visit
https://pi433.de/en.html
+
+          If in doubt, say N here, but saying yes most probably won't hurt
diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile
new file mode 100644
index 0000000..417f3e4
--- /dev/null
+++ b/drivers/staging/pi433/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PI433) += pi433.o
+
+pi433-objs := pi433_if.o rf69.o
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
new file mode 100644
index 0000000..57edf91
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.c
@@ -0,0 +1,1315 @@
+/*
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+#endif
+
+#include "pi433_if.h"
+#include "rf69.h"
+
+
+#define N_PI433_MINORS            (1U << MINORBITS) /*32*/    /* ... up to 256
*/
+#define MAX_MSG_SIZE            900    /* min: FIFO_SIZE! */
+#define MSG_FIFO_SIZE            65536   /* 65536 = 2^16  */
+#define NUM_DIO                2
+
+static dev_t pi433_dev;
+static DEFINE_IDR(pi433_idr);
+static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+
+static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
+
+/* tx config is instance specific
+    so with each open a new tx config struct is needed */
+/* rx config is device specific
+    so we have just one rx config, ebedded in device struct */
+struct pi433_device {
+    /* device handling related values */
+    dev_t            devt;
+    int            minor;
+    struct device        *dev;
+    struct cdev        *cdev;
+    struct spi_device    *spi;
+    unsigned        users;
+
+    /* irq related values */
+    struct gpio_desc    *gpiod[NUM_DIO];
+    int            irq_num[NUM_DIO];
+    u8            irq_state[NUM_DIO];
+
+    /* tx related values */
+    STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
+    struct mutex        tx_fifo_lock; // TODO: check, whether necessary or
obsolete
+    struct task_struct    *tx_task_struct;
+    wait_queue_head_t    tx_wait_queue;
+    u8            free_in_fifo;
+
+    /* rx related values */
+    struct pi433_rx_cfg    rx_cfg;
+    u8            *rx_buffer;
+    unsigned int        rx_buffer_size;
+    u32            rx_bytes_to_drop;
+    u32            rx_bytes_dropped;
+    unsigned int        rx_position;
+    struct mutex        rx_lock;
+    wait_queue_head_t    rx_wait_queue;
+
+    /* fifo wait queue */
+    struct task_struct    *fifo_task_struct;
+    wait_queue_head_t    fifo_wait_queue;
+
+    /* flags */
+    bool            rx_active;
+    bool            tx_active;
+    bool            interrupt_rx_allowed;
+};
+
+struct pi433_instance {
+    struct pi433_device    *device;
+    struct pi433_tx_cfg    tx_cfg;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* macro for checked access of registers of radio module */
+#define SET_CHECKED(retval) \
+    if (retval < 0) \
+        return retval;
+
+/*-------------------------------------------------------------------------*/
+
+/* GPIO interrupt handlers */
+static irq_handler_t
+DIO0_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct pi433_device *device = dev_id;
+
+    if      (device->irq_state[DIO0] == DIO_PacketSent)
+    {
+        device->free_in_fifo = FIFO_SIZE;
+        printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include
KERN_ facility level
+        wake_up_interruptible(&device->fifo_wait_queue);
+    }
+    else if (device->irq_state[DIO0] == DIO_Rssi_DIO0)
+    {
+        printk("DIO0 irq: RSSI level over threshold\n");
+        wake_up_interruptible(&device->rx_wait_queue);
+    }
+    else if (device->irq_state[DIO0] == DIO_PayloadReady)
+    {
+        printk("DIO0 irq: PayloadReady\n");
+        device->free_in_fifo = 0;
+        wake_up_interruptible(&device->fifo_wait_queue);
+    }
+
+    return (irq_handler_t) IRQ_HANDLED;
+}
+
+static irq_handler_t
+DIO1_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct pi433_device *device = dev_id;
+
+    if      (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1)
+    {
+        device->free_in_fifo = FIFO_SIZE;
+    }
+    else if (device->irq_state[DIO1] == DIO_FifoLevel)
+    {
+        if (device->rx_active)    device->free_in_fifo = FIFO_THRESHOLD - 1;
+        else            device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1;
+    }
+    printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO:
printk() should include KERN_ facility level
+    wake_up_interruptible(&device->fifo_wait_queue);
+
+    return (irq_handler_t) IRQ_HANDLED;
+}
+
+static void *DIO_irq_handler[NUM_DIO] = {
+    DIO0_irq_handler,
+    DIO1_irq_handler
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
+{
+    int payload_length;
+
+    /* receiver config */
+    SET_CHECKED(rf69_set_frequency    (dev->spi, rx_cfg->frequency));
+    SET_CHECKED(rf69_set_bit_rate    (dev->spi, rx_cfg->bit_rate));
+    SET_CHECKED(rf69_set_modulation    (dev->spi, rx_cfg->modulation));
+    SET_CHECKED(rf69_set_antenna_impedance     (dev->spi,
rx_cfg->antenna_impedance));
+    SET_CHECKED(rf69_set_rssi_threshold     (dev->spi,
rx_cfg->rssi_threshold));
+    SET_CHECKED(rf69_set_ook_threshold_dec     (dev->spi,
rx_cfg->thresholdDecrement));
+    SET_CHECKED(rf69_set_bandwidth          (dev->spi, rx_cfg->bw_mantisse,
rx_cfg->bw_exponent));
+    SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse,
rx_cfg->bw_exponent));
+    SET_CHECKED(rf69_set_dagc          (dev->spi, rx_cfg->dagc));
+
+    dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop;
+
+    /* packet config */
+    /* enable */
+    SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync));
+    if (rx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi,
afterSyncInterrupt));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always));
+    }
+    SET_CHECKED(rf69_set_packet_format  (dev->spi,
rx_cfg->enable_length_byte));
+    SET_CHECKED(rf69_set_adressFiltering(dev->spi,
rx_cfg->enable_address_filtering));
+    SET_CHECKED(rf69_set_crc_enable        (dev->spi, rx_cfg->enable_crc));
+
+    /* lengths */
+    SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
+    if (rx_cfg->enable_length_byte == optionOn)
+    {
+        SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff));
+    }
+    else if (rx_cfg->fixed_message_length != 0)
+    {
+        payload_length = rx_cfg->fixed_message_length;
+        if (rx_cfg->enable_length_byte  == optionOn) payload_length++;
+        if (rx_cfg->enable_address_filtering != filteringOff) payload_length++;
+        SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
+    }
+
+    /* values */
+    if (rx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern));
+    }
+    if (rx_cfg->enable_address_filtering != filteringOff)
+    {
+        SET_CHECKED(rf69_set_node_address     (dev->spi,
rx_cfg->node_address));
+        SET_CHECKED(rf69_set_broadcast_address(dev->spi,
rx_cfg->broadcast_address));
+    }
+
+    return 0;
+}
+
+static int
+rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
+{
+    SET_CHECKED(rf69_set_frequency    (dev->spi, tx_cfg->frequency));
+    SET_CHECKED(rf69_set_bit_rate    (dev->spi, tx_cfg->bit_rate));
+    SET_CHECKED(rf69_set_modulation    (dev->spi, tx_cfg->modulation));
+    SET_CHECKED(rf69_set_deviation    (dev->spi, tx_cfg->dev_frequency));
+    SET_CHECKED(rf69_set_pa_ramp    (dev->spi, tx_cfg->pa_ramp));
+    SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping));
+    SET_CHECKED(rf69_set_tx_start_condition(dev->spi,
tx_cfg->tx_start_condition));
+
+    /* packet format enable */
+    if (tx_cfg->enable_preamble == optionOn)
+    {
+        SET_CHECKED(rf69_set_preamble_length(dev->spi,
tx_cfg->preamble_length));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
+    }
+    SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
+    SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
+    SET_CHECKED(rf69_set_crc_enable      (dev->spi, tx_cfg->enable_crc));
+
+    /* configure sync, if enabled */
+    if (tx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length));
+        SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern));
+    }
+
+    return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pi433_start_rx(struct pi433_device *dev)
+{
+    int retval;
+
+    /* return without action, if no pending read request */
+    if (!dev->rx_active)
+        return 0;
+
+    /* setup for receiving */
+    retval = rf69_set_rx_cfg(dev, &dev->rx_cfg);
+    if (retval) return retval;
+
+    /* setup rssi irq */
+    SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0));
+    dev->irq_state[DIO0] = DIO_Rssi_DIO0;
+    irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+    /* setup fifo level interrupt */
+    SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD));
+    SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel));
+    dev->irq_state[DIO1] = DIO_FifoLevel;
+    irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING);
+
+    /* set module to receiving mode */
+    SET_CHECKED(rf69_set_mode(dev->spi, receive));
+
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int
+pi433_receive(void *data)
+{
+    struct pi433_device *dev = data;
+    struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */
+    int bytes_to_read, bytes_total;
+    int retval;
+
+    dev->interrupt_rx_allowed = false;
+
+    /* wait for any tx to finish */
+    dev_dbg(dev->dev,"rx: going to wait for any tx to finish");
+    retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
+    if(retval) /* wait was interrupted */
+    {
+        dev->interrupt_rx_allowed = true;
+        wake_up_interruptible(&dev->tx_wait_queue);
+        return retval;
+    }
+
+    /* prepare status vars */
+    dev->free_in_fifo = FIFO_SIZE;
+    dev->rx_position = 0;
+    dev->rx_bytes_dropped = 0;
+
+    /* setup radio module to listen for something "in the air" */
+    retval = pi433_start_rx(dev);
+    if (retval)
+        return retval;
+
+    /* now check RSSI, if low wait for getting high (RSSI interrupt) */
+    while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) )
+    {
+        /* allow tx to interrupt us while waiting for high RSSI */
+        dev->interrupt_rx_allowed = true;
+        wake_up_interruptible(&dev->tx_wait_queue);
+
+        /* wait for RSSI level to become high */
+        dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
+        retval = wait_event_interruptible(dev->rx_wait_queue,
+                                      rf69_get_flag(dev->spi,
+
                                                       rssiExceededThreshold));
+        if (retval) goto abort; /* wait was interrupted */
+        dev->interrupt_rx_allowed = false;
+
+        /* cross check for ongoing tx */
+        if (!dev->tx_active) break;
+    }
+
+    /* configure payload ready irq */
+    SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady));
+    dev->irq_state[DIO0] = DIO_PayloadReady;
+    irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+    /* fixed or unlimited length? */
+    if (dev->rx_cfg.fixed_message_length != 0)
+    {
+        if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size)
+        {
+            retval = -1;
+            goto abort;
+        }
+        bytes_total = dev->rx_cfg.fixed_message_length;
+        dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total);
+    }
+    else
+    {
+        bytes_total = dev->rx_buffer_size;
+        dev_dbg(dev->dev, "rx: msg len set to %d as requested by read",
bytes_total);
+    }
+
+    /* length byte enabled? */
+    if (dev->rx_cfg.enable_length_byte == optionOn)
+    {
+        retval = wait_event_interruptible(dev->fifo_wait_queue,
+                          dev->free_in_fifo < FIFO_SIZE);
+        if (retval) goto abort; /* wait was interrupted */
+
+        rf69_read_fifo(spi, (u8 *)&bytes_total, 1);
+        if (bytes_total > dev->rx_buffer_size)
+        {
+            retval = -1;
+            goto abort;
+        }
+        dev->free_in_fifo++;
+        dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte",
bytes_total);
+    }
+
+    /* address byte enabled? */
+    if (dev->rx_cfg.enable_address_filtering != filteringOff)
+    {
+        u8 dummy;
+
+        bytes_total--;
+
+        retval = wait_event_interruptible(dev->fifo_wait_queue,
+                          dev->free_in_fifo < FIFO_SIZE);
+        if (retval) goto abort; /* wait was interrupted */
+
+        rf69_read_fifo(spi, &dummy, 1);
+        dev->free_in_fifo++;
+        dev_dbg(dev->dev, "rx: address byte stripped off");
+    }
+
+    /* get payload */
+    while (dev->rx_position < bytes_total)
+    {
+        if ( !rf69_get_flag(dev->spi, payloadReady) )
+        {
+            retval = wait_event_interruptible(dev->fifo_wait_queue,
+                              dev->free_in_fifo < FIFO_SIZE);
+            if (retval) goto abort; /* wait was interrupted */
+        }
+
+        /* need to drop bytes or acquire? */
+        if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+            bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+        else
+            bytes_to_read = bytes_total - dev->rx_position;
+
+
+        /* access the fifo */
+        if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo)
+            bytes_to_read = FIFO_SIZE - dev->free_in_fifo;
+        retval = rf69_read_fifo(spi,
+                    &dev->rx_buffer[dev->rx_position],
+                    bytes_to_read);
+        if (retval) goto abort; /* read failed */
+        dev->free_in_fifo += bytes_to_read;
+
+        /* adjust status vars */
+        if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+            dev->rx_bytes_dropped += bytes_to_read;
+        else
+            dev->rx_position += bytes_to_read;
+    }
+
+
+    /* rx done, wait was interrupted or error occured */
+abort:
+    dev->interrupt_rx_allowed = true;
+    SET_CHECKED(rf69_set_mode(dev->spi, standby));
+    wake_up_interruptible(&dev->tx_wait_queue);
+
+    if (retval)
+        return retval;
+    else
+        return bytes_total;
+}
+
+int
+pi433_tx_thread(void *data)
+{
+    struct pi433_device *device = data;
+    struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
+    struct pi433_tx_cfg tx_cfg;
+    u8     buffer[MAX_MSG_SIZE];
+    size_t size;
+    bool   rx_interrupted = false;
+    int    position, repetitions;
+    int    retval;
+
+    while (1)
+    {
+        /* wait for fifo to be populated or for request to terminate*/
+        dev_dbg(device->dev, "thread: going to wait for new messages");
+        wait_event_interruptible(device->tx_wait_queue,
+                     ( !kfifo_is_empty(&device->tx_fifo) ||
+                        kthread_should_stop() ));
+        if ( kthread_should_stop() )
+            return 0;
+
+        /* get data from fifo in the following order:
+           - tx_cfg
+           - size of message
+           - message */
+        mutex_lock(&device->tx_fifo_lock);
+
+        retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
+        if (retval != sizeof(tx_cfg))
+        {
+            dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d
byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) );
+            mutex_unlock(&device->tx_fifo_lock);
+            continue;
+        }
+
+        retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
+        if (retval != sizeof(size_t))
+        {
+            dev_dbg(device->dev, "reading msg size from fifo failed: got %d,
expected %d", retval, (unsigned int)sizeof(size_t) );
+            mutex_unlock(&device->tx_fifo_lock);
+            continue;
+        }
+
+        /* use fixed message length, if requested */
+        if (tx_cfg.fixed_message_length != 0)
+            size = tx_cfg.fixed_message_length;
+
+        /* increase size, if len byte is requested */
+        if (tx_cfg.enable_length_byte == optionOn)
+            size++;
+
+        /* increase size, if adr byte is requested */
+        if (tx_cfg.enable_address_byte == optionOn)
+            size++;
+
+        /* prime buffer */
+        memset(buffer, 0, size);
+        position = 0;
+
+        /* add length byte, if requested */
+        if (tx_cfg.enable_length_byte  == optionOn)
+            buffer[position++] = size-1; /* according to spec length byte
itself must be excluded from the length calculation */
+
+        /* add adr byte, if requested */
+        if (tx_cfg.enable_address_byte == optionOn)
+            buffer[position++] = tx_cfg.address_byte;
+
+        /* finally get message data from fifo */
+        retval = kfifo_out(&device->tx_fifo, &buffer[position],
sizeof(buffer)-position );
+        dev_dbg(device->dev, "read %d message byte(s) from fifo queue.",
retval);
+        mutex_unlock(&device->tx_fifo_lock);
+
+        /* if rx is active, we need to interrupt the waiting for
+           incoming telegrams, to be able to send something.
+           We are only allowed, if currently no reception takes
+           place otherwise we need to  wait for the incoming telegram
+           to finish */
+        wait_event_interruptible(device->tx_wait_queue,
+                     !device->rx_active ||
+                      device->interrupt_rx_allowed == true);
+
+        /* prevent race conditions
+           irq will be reenabled after tx config is set */
+        disable_irq(device->irq_num[DIO0]);
+        device->tx_active = true;
+
+        if (device->rx_active && rx_interrupted == false)
+        {
+            /* rx is currently waiting for a telegram;
+               we need to set the radio module to standby */
+            SET_CHECKED(rf69_set_mode(device->spi, standby));
+            rx_interrupted = true;
+        }
+
+        /* clear fifo, set fifo threshold, set payload length */
+        SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */
+        SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD));
+        if (tx_cfg.enable_length_byte == optionOn)
+        {
+            SET_CHECKED(rf69_set_payload_length(spi, size *
tx_cfg.repetitions));
+        }
+        else
+        {
+            SET_CHECKED(rf69_set_payload_length(spi, 0));
+        }
+
+        /* configure the rf chip */
+        rf69_set_tx_cfg(device, &tx_cfg);
+
+        /* enable fifo level interrupt */
+        SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel));
+        device->irq_state[DIO1] = DIO_FifoLevel;
+        irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING);
+
+        /* enable packet sent interrupt */
+        SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent));
+        device->irq_state[DIO0] = DIO_PacketSent;
+        irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+        enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check
*/
+
+        /* enable transmission */
+        SET_CHECKED(rf69_set_mode(spi, transmit));
+
+        /* transfer this msg (and repetitions) to chip fifo */
+        device->free_in_fifo = FIFO_SIZE;
+        position = 0;
+        repetitions = tx_cfg.repetitions;
+        while( (repetitions > 0) && (size > position) )
+        {
+            if ( (size - position) > device->free_in_fifo)
+            {    /* msg to big for fifo - take a part */
+                int temp = device->free_in_fifo;
+                device->free_in_fifo = 0;
+                rf69_write_fifo(spi,
+                                &buffer[position],
+                                temp);
+                position +=temp;
+            }
+            else
+            {    /* msg fits into fifo - take all */
+                device->free_in_fifo -= size;
+                repetitions--;
+                rf69_write_fifo(spi,
+                        &buffer[position],
+                        (size - position) );
+                position = 0; /* reset for next repetition */
+            }
+
+            retval = wait_event_interruptible(device->fifo_wait_queue,
+                              device->free_in_fifo > 0);
+            if (retval) { printk("ABORT\n"); goto abort; }
+        }
+
+        /* we are done. Wait for packet to get sent */
+        dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be
empty");
+        wait_event_interruptible(device->fifo_wait_queue,
+                     device->free_in_fifo == FIFO_SIZE ||
+                     kthread_should_stop() );
+        if ( kthread_should_stop() )    printk("ABORT\n");
+
+
+        /* STOP_TRANSMISSION */
+        dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.");
+        SET_CHECKED(rf69_set_mode(spi, standby));
+
+        /* everything sent? */
+        if ( kfifo_is_empty(&device->tx_fifo) )
+        {
+abort:
+            if (rx_interrupted)
+            {
+                rx_interrupted = false;
+                pi433_start_rx(device);
+            }
+            device->tx_active = false;
+            wake_up_interruptible(&device->rx_wait_queue);
+        }
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t
+pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    unsigned int        bytes_received;
+    ssize_t            retval;
+
+    /* check, whether internal buffer is big enough for requested size */
+    if (size > MAX_MSG_SIZE)
+        return -EMSGSIZE;
+
+    instance = filp->private_data;
+    device = instance->device;
+
+    /* just one read request at a time */
+    mutex_lock(&device->rx_lock);
+    if (device->rx_active)
+    {
+        mutex_unlock(&device->rx_lock);
+        return -EAGAIN;
+    }
+    else
+    {
+        device->rx_active = true;
+        mutex_unlock(&device->rx_lock);
+    }
+
+    /* start receiving */
+    /* will block until something was received*/
+    device->rx_buffer_size = size;
+    bytes_received = pi433_receive(device);
+
+    /* release rx */
+    mutex_lock(&device->rx_lock);
+    device->rx_active = false;
+    mutex_unlock(&device->rx_lock);
+
+    /* if read was successful copy to user space*/
+    if (bytes_received >= 0)
+    {
+        retval = copy_to_user(buf, device->rx_buffer, bytes_received);
+        if (retval)
+            return retval;
+    }
+
+    return bytes_received;
+}
+
+
+static ssize_t
+pi433_write(struct file *filp, const char __user *buf,
+        size_t count, loff_t *f_pos)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    int                     copied, retval;
+
+    instance = filp->private_data;
+    device = instance->device;
+
+    /* check, whether internal buffer (tx thread) is big enough for requested
size */
+    if (count > MAX_MSG_SIZE)
+        return -EMSGSIZE;
+
+    /* write the following sequence into fifo:
+       - tx_cfg
+       - size of message
+       - message */
+    mutex_lock(&device->tx_fifo_lock);
+    retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg,
sizeof(instance->tx_cfg));
+    if ( retval != sizeof(instance->tx_cfg) )
+        goto abort;
+
+    retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t));
+    if ( retval != sizeof(size_t) )
+        goto abort;
+
+    retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied);
+    if (retval || copied != count)
+        goto abort;
+
+    mutex_unlock(&device->tx_fifo_lock);
+
+    /* start transfer */
+    wake_up_interruptible(&device->tx_wait_queue);
+    dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied);
+
+    return 0;
+
+abort:
+    dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
+    kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to
discard already stored, valid entries
+    mutex_unlock(&device->tx_fifo_lock);
+    return -EAGAIN;
+}
+
+
+static long
+pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    int            err = 0;
+    int            retval = 0;
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    u32            tmp;
+
+    /* Check type and command number */
+    if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
+        return -ENOTTY;
+
+    /* Check access direction once here; don't repeat below.
+     * IOC_DIR is from the user perspective, while access_ok is
+     * from the kernel perspective; so they look reversed.
+     */
+    if (_IOC_DIR(cmd) & _IOC_READ)
+        err = !access_ok(VERIFY_WRITE,
+                 (void __user *)arg,
+                 _IOC_SIZE(cmd));
+
+    if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+        err = !access_ok(VERIFY_READ,
+                 (void __user *)arg,
+                 _IOC_SIZE(cmd));
+    if (err)
+        return -EFAULT;
+
+    /* TODO? guard against device removal before, or while,
+     * we issue this ioctl. --> device_get()
+     */
+    instance = filp->private_data;
+    device = instance->device;
+
+    if (device == NULL)
+        return -ESHUTDOWN;
+
+    switch (cmd) {
+    case PI433_IOC_RD_TX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_to_user((void __user *)arg,
+                    &instance->tx_cfg,
+                    tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+    case PI433_IOC_WR_TX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_from_user(&instance->tx_cfg,
+                     (void __user *)arg,
+                     tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+
+    case PI433_IOC_RD_RX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_to_user((void __user *)arg,
+                   &device->rx_cfg,
+                   tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+    case PI433_IOC_WR_RX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        mutex_lock(&device->rx_lock);
+
+        /* during pendig read request, change of config not allowed */
+        if (device->rx_active) {
+            retval = -EAGAIN;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+            retval = -EINVAL;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        if (__copy_from_user(&device->rx_cfg,
+                     (void __user *)arg,
+                     tmp))
+        {
+            retval = -EFAULT;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        mutex_unlock(&device->rx_lock);
+        break;
+    default:
+        retval = -EINVAL;
+    }
+
+    return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define pi433_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_open(struct inode *inode, struct file *filp)
+{
+    struct pi433_device    *device;
+    struct pi433_instance    *instance;
+
+    mutex_lock(&minor_lock);
+    device = idr_find(&pi433_idr, iminor(inode));
+
+    mutex_unlock(&minor_lock);
+    if (!device) {
+        dev_dbg(device->dev, "device: minor %d unknown.\n", iminor(inode));
+        return -ENODEV;
+    }
+
+    if (!device->rx_buffer) {
+        device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL);
+        if (!device->rx_buffer)
+        {
+            dev_dbg(device->dev, "open/ENOMEM\n");
+            return -ENOMEM;
+        }
+    }
+
+    device->users++;
+    instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+    if (!instance)
+    {
+        kfree(device->rx_buffer);
+        device->rx_buffer = NULL;
+        return -ENOMEM;
+    }
+
+    /* setup instance data*/
+    instance->device = device;
+    instance->tx_cfg.bit_rate = 4711;
+    // TODO: fill instance->tx_cfg;
+
+    /* instance data as context */
+    filp->private_data = instance;
+    nonseekable_open(inode, filp);
+
+    return 0;
+}
+
+static int pi433_release(struct inode *inode, struct file *filp)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+
+    instance = filp->private_data;
+    device = instance->device;
+    kfree(instance);
+    filp->private_data = NULL;
+
+    /* last close? */
+    device->users--;
+
+    if (!device->users) {
+        kfree(device->rx_buffer);
+        device->rx_buffer = NULL;
+        if (device->spi == NULL)
+            kfree(device);
+    }
+
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int setup_GPIOs(struct pi433_device *device)
+{
+    char     name[5];
+    int    retval;
+    int    i;
+
+    for (i=0; i<NUM_DIO; i++)
+    {
+        /* "construct" name and get the gpio descriptor */
+        snprintf(name, sizeof(name), "DIO%d", i);
+        device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+
+        if (device->gpiod[i] == ERR_PTR(-ENOENT))
+        {
+            dev_dbg(&device->spi->dev, "Could not find entry for %s.
Ignoring.", name);
+            continue;
+        }
+
+        if (device->gpiod[i] == ERR_PTR(-EBUSY))
+            dev_dbg(&device->spi->dev, "%s is busy.", name);
+
+        if ( IS_ERR(device->gpiod[i]) )
+        {
+            retval = PTR_ERR(device->gpiod[i]);
+            /* release already allocated gpios */
+            for (i--; i>=0; i--)
+            {
+                free_irq(device->irq_num[i], device);
+                gpiod_put(device->gpiod[i]);
+            }
+            return retval;
+        }
+
+
+        /* configure the pin */
+        gpiod_unexport(device->gpiod[i]);
+        retval = gpiod_direction_input(device->gpiod[i]);
+        if (retval) return retval;
+
+
+        /* configure irq */
+        device->irq_num[i] = gpiod_to_irq(device->gpiod[i]);
+        if (device->irq_num[i] < 0)
+        {
+            device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc
*)device->irq_num[i];
+            return device->irq_num[i];
+        }
+        retval = request_irq(device->irq_num[i],
+                     DIO_irq_handler[i],
+                     0, /* flags */
+                     name,
+                     device);
+
+        if (retval)
+            return retval;
+
+        dev_dbg(&device->spi->dev, "%s succesfully configured", name);
+    }
+
+    return 0;
+}
+
+static void free_GPIOs(struct pi433_device *device)
+{
+    int i;
+
+    for (i=0; i<NUM_DIO; i++)
+    {
+        /* check if gpiod is valid */
+        if ( IS_ERR(device->gpiod[i]) )
+            continue;
+
+        free_irq(device->irq_num[i], device);
+        gpiod_put(device->gpiod[i]);
+    }
+    return;
+}
+
+static int pi433_get_minor(struct pi433_device *device)
+{
+    int retval = -ENOMEM;
+
+    mutex_lock(&minor_lock);
+    retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL);
+    if (retval >= 0) {
+        device->minor = retval;
+        retval = 0;
+    } else if (retval == -ENOSPC) {
+        dev_err(device->dev, "too many pi433 devices\n");
+        retval = -EINVAL;
+    }
+    mutex_unlock(&minor_lock);
+    return retval;
+}
+
+static void pi433_free_minor(struct pi433_device *dev)
+{
+    mutex_lock(&minor_lock);
+    idr_remove(&pi433_idr, dev->minor);
+    mutex_unlock(&minor_lock);
+}
+/*-------------------------------------------------------------------------*/
+
+static const struct file_operations pi433_fops = {
+    .owner =    THIS_MODULE,
+    /* REVISIT switch to aio primitives, so that userspace
+     * gets more complete API coverage.  It'll simplify things
+     * too, except for the locking.
+     */
+    .write =    pi433_write,
+    .read =        pi433_read,
+    .unlocked_ioctl = pi433_ioctl,
+    .compat_ioctl = pi433_compat_ioctl,
+    .open =        pi433_open,
+    .release =    pi433_release,
+    .llseek =    no_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_probe(struct spi_device *spi)
+{
+    struct pi433_device    *device;
+    int            retval;
+
+    /* setup spi parameters */
+    spi->mode = 0x00;
+    spi->bits_per_word = 8;
+    /* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay
*/
+
+    retval = spi_setup(spi);
+    if (retval)
+    {
+        dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
+        return retval;
+    }
+    else
+    {
+        dev_dbg(&spi->dev,
+            "spi interface setup: mode 0x%2x, %d bits per word, %dhz max
speed",
+            spi->mode, spi->bits_per_word, spi->max_speed_hz);
+    }
+
+    /* Ping the chip by reading the version register */
+    retval = spi_w8r8(spi, 0x10);
+    if (retval < 0)
+        return retval;
+
+    switch(retval)
+    {
+        case 0x24:
+            dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
+            break;
+        default:
+            dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
+            return -ENODEV;
+    }
+
+    /* Allocate driver data */
+    device = kzalloc(sizeof(*device), GFP_KERNEL);
+    if (!device)
+        return -ENOMEM;
+
+    /* Initialize the driver data */
+    device->spi = spi;
+    device->rx_active = false;
+    device->tx_active = false;
+    device->interrupt_rx_allowed = false;
+
+    /* init wait queues */
+    init_waitqueue_head(&device->tx_wait_queue);
+    init_waitqueue_head(&device->rx_wait_queue);
+    init_waitqueue_head(&device->fifo_wait_queue);
+
+    /* init fifo */
+    INIT_KFIFO(device->tx_fifo);
+
+    /* init mutexes and locks */
+    mutex_init(&device->tx_fifo_lock);
+    mutex_init(&device->rx_lock);
+
+    /* setup GPIO (including irq_handler) for the different DIOs */
+    retval = setup_GPIOs(device);
+    if (retval)
+    {
+        dev_dbg(&spi->dev, "setup of GPIOs failed");
+        goto GPIO_failed;
+    }
+
+    /* setup the radio module */
+    SET_CHECKED(rf69_set_mode        (spi, standby));
+    SET_CHECKED(rf69_set_data_mode        (spi, packet));
+    SET_CHECKED(rf69_set_amplifier_0    (spi, optionOn));
+    SET_CHECKED(rf69_set_amplifier_1    (spi, optionOff));
+    SET_CHECKED(rf69_set_amplifier_2    (spi, optionOff));
+    SET_CHECKED(rf69_set_output_power_level    (spi, 13));
+    SET_CHECKED(rf69_set_antenna_impedance    (spi, fiftyOhm));
+
+    /* start tx thread */
+    device->tx_task_struct = kthread_run(pi433_tx_thread,
+                         device,
+                         "pi433_tx_task");
+    if (device->tx_task_struct < 0)
+    {
+        dev_dbg(device->dev, "start of send thread failed");
+        goto send_thread_failed;
+    }
+
+    /* determ minor number */
+    retval = pi433_get_minor(device);
+    if (retval)
+    {
+        dev_dbg(device->dev, "get of minor number failed");
+        goto minor_failed;
+    }
+
+    /* create device */
+    device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
+    device->dev = device_create(pi433_class,
+                    &spi->dev,
+                    device->devt,
+                    device,
+                    "pi433");
+    if (IS_ERR(device->dev)) {
+        pr_err("pi433: device register failed\n");
+        retval = PTR_ERR(device->dev);
+        goto device_create_failed;
+    }
+    else {
+        dev_dbg(device->dev,
+            "created device for major %d, minor %d\n",
+            MAJOR(pi433_dev),
+            device->minor);
+    }
+
+    /* create cdev */
+    device->cdev = cdev_alloc();
+    device->cdev->owner = THIS_MODULE;
+    cdev_init(device->cdev, &pi433_fops);
+    retval = cdev_add(device->cdev, device->devt, 1);
+    if (retval)
+    {
+        dev_dbg(device->dev, "register of cdev failed");
+        goto cdev_failed;
+    }
+
+    /* spi setup */
+    spi_set_drvdata(spi, device);
+
+    return 0;
+
+cdev_failed:
+    device_destroy(pi433_class, device->devt);
+device_create_failed:
+    pi433_free_minor(device);
+minor_failed:
+    kthread_stop(device->tx_task_struct);
+send_thread_failed:
+    free_GPIOs(device);
+GPIO_failed:
+    kfree(device);
+
+    return retval;
+}
+
+static int pi433_remove(struct spi_device *spi)
+{
+    struct pi433_device    *device = spi_get_drvdata(spi);
+
+    /* free GPIOs */
+    free_GPIOs(device);
+
+    /* make sure ops on existing fds can abort cleanly */
+    device->spi = NULL;
+
+    kthread_stop(device->tx_task_struct);
+
+    device_destroy(pi433_class, device->devt);
+
+    cdev_del(device->cdev);
+
+    pi433_free_minor(device);
+
+    if (device->users == 0)
+        kfree(device);
+
+    return 0;
+}
+
+static const struct of_device_id pi433_dt_ids[] = {
+    { .compatible = "Smarthome-Wolf,pi433" },
+    {},
+};
+
+MODULE_DEVICE_TABLE(of, pi433_dt_ids);
+
+static struct spi_driver pi433_spi_driver = {
+    .driver = {
+        .name =        "pi433",
+        .owner =    THIS_MODULE,
+        .of_match_table = of_match_ptr(pi433_dt_ids),
+    },
+    .probe =    pi433_probe,
+    .remove =    pi433_remove,
+
+    /* NOTE:  suspend/resume methods are not necessary here.
+     * We don't do anything except pass the requests to/from
+     * the underlying controller.  The refrigerator handles
+     * most issues; the controller driver handles the rest.
+     */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init pi433_init(void)
+{
+    int status;
+
+    /* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't
+           work stable - risk of buffer overflow */
+    if (MAX_MSG_SIZE < FIFO_SIZE)
+        return -EINVAL;
+
+    /* Claim device numbers.  Then register a class
+     * that will key udev/mdev to add/remove /dev nodes.  Last, register
+     * Last, register the driver which manages those device numbers.
+     */
+    status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS
/*count*/, "pi433" /*name*/);
+    if (status < 0)
+        return status;
+
+    pi433_class = class_create(THIS_MODULE, "pi433");
+    if (IS_ERR(pi433_class))
+    {
+        unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+        return PTR_ERR(pi433_class);
+    }
+
+    status = spi_register_driver(&pi433_spi_driver);
+    if (status < 0)
+    {
+        class_destroy(pi433_class);
+        unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+    }
+
+    return status;
+}
+
+module_init(pi433_init);
+
+static void __exit pi433_exit(void)
+{
+    spi_unregister_driver(&pi433_spi_driver);
+    class_destroy(pi433_class);
+    unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+}
+module_exit(pi433_exit);
+
+MODULE_AUTHOR("Marcus Wolf, <linux@wolf-entwicklungen.de>");
+MODULE_DESCRIPTION("Driver for Pi433");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:pi433");
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
new file mode 100644
index 0000000..e6ed3cd
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.h
@@ -0,0 +1,152 @@
+/*
+ * include/linux/TODO
+ *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR     0
+struct pi433_tx_cfg
+{
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+    enum modulation        modulation;
+    enum modShaping        modShaping;
+
+    enum paRamp        pa_ramp;
+
+    enum txStartCondition    tx_start_condition;
+
+    __u16            repetitions;
+
+
+    /* packet format */
+    enum optionOnOff    enable_preamble;
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;
+    enum optionOnOff    enable_address_byte;
+    enum optionOnOff    enable_crc;
+
+    __u16            preamble_length;
+    __u8            sync_length;
+    __u8            fixed_message_length;
+
+    __u8            sync_pattern[8];
+    __u8            address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR     1
+struct pi433_rx_cfg {
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+
+    enum modulation        modulation;
+
+    __u8            rssi_threshold;
+    enum thresholdDecrement    thresholdDecrement;
+    enum antennaImpedance    antenna_impedance;
+    enum lnaGain        lna_gain;
+    enum mantisse        bw_mantisse;    /* normal: 0x50 */
+    __u8            bw_exponent;    /* during AFC: 0x8b */
+    enum dagc        dagc;
+
+
+
+    /* packet format */
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;      /* should be used in
combination with sync, only */
+    enum addressFiltering    enable_address_filtering; /* operational with
sync, only */
+    enum optionOnOff    enable_crc;          /* only operational, if sync on
and fixed length or length byte is used */
+
+    __u8            sync_length;
+    __u8            fixed_message_length;
+    __u32            bytes_to_drop;
+
+    __u8            sync_pattern[8];
+    __u8            node_address;
+    __u8            broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC            'r'
+
+#define PI433_IOC_RD_TX_CFG    _IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG    _IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG    _IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG    _IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
new file mode 100644
index 0000000..b6bc45b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.c
@@ -0,0 +1,982 @@
+/*
+ * abstraction of the spi interface of HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* enable prosa debug info */
+#undef DEBUG
+/* enable print of values on reg access */
+#undef DEBUG_VALUES
+/* enable print of values on fifo access */
+#undef DEBUG_FIFO_ACCESS
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include "rf69.h"
+#include "rf69_registers.h"
+
+#define F_OSC      32000000 /* in Hz */
+#define FIFO_SIZE 66        /* in byte */
+
+/*-------------------------------------------------------------------------*/
+
+#define READ_REG(x)    rf69_read_reg (spi, x)
+#define WRITE_REG(x,y)    rf69_write_reg(spi, x, y)
+#define INVALID_PARAM \
+    { \
+        dev_dbg(&spi->dev, "set: illegal input param"); \
+        return -EINVAL; \
+    }
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: mode");
+    #endif
+
+    switch (mode){
+    case transmit:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT);
+    case receive:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE);
+    case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER);
+    case standby:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY);
+    case mode_sleep:  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP);
+    default:      INVALID_PARAM;
+    }
+
+    // we are using packet mode, so this check is not really needed
+    // but waiting for mode ready is necessary when going from sleep because
the FIFO may not be immediately available from previous mode
+    //while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) &
RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
+
+}
+
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: data mode");
+    #endif
+
+    switch (dataMode) {
+    case packet:        return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET);
+    case continuous:    return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS);
+    case continuousNoSync:  return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) |
DATAMODUL_MODE_CONTINUOUS_NOSYNC);
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: modulation");
+    #endif
+
+    switch (modulation) {
+    case OOK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) &
~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK);
+    case FSK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) &
~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK);
+    default:    INVALID_PARAM;
+    }
+}
+
+enum modulation rf69_get_modulation(struct spi_device *spi)
+{
+    u8 currentValue;    
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: mode");
+    #endif
+
+    currentValue = READ_REG(REG_DATAMODUL);
+
+    switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3)  // TODO
improvement: change 3 to define
+    {
+    case DATAMODUL_MODULATION_TYPE_OOK: return OOK;
+    case DATAMODUL_MODULATION_TYPE_FSK: return FSK;
+    default:                return undefined;
+    }
+}
+
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping
modShaping)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: mod shaping");
+    #endif
+
+    if (rf69_get_modulation(spi) == FSK)
+    {
+        switch (modShaping) {
+        case shapingOff: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_NONE);
+        case shaping1_0: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_1_0);
+        case shaping0_5: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_0_3);
+        case shaping0_3: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_0_5);
+        default:     INVALID_PARAM;
+        }
+    }
+    else
+    {
+        switch (modShaping) {
+        case shapingOff: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_NONE);
+        case shapingBR:     return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_BR);
+        case shaping2BR: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_2BR);
+        default:     INVALID_PARAM;
+        }
+    }
+}
+
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+{
+    int retval;
+    u32 bitRate_min;
+    u32 bitRate_reg;
+    u8 msb;
+    u8 lsb;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: bit rate");
+    #endif
+
+    // check input value
+    bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
+    if (bitRate < bitRate_min)
+    {
+        dev_dbg(&spi->dev, "setBitRate: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculate reg settings
+    bitRate_reg = (F_OSC / bitRate);
+
+    msb = (bitRate_reg&0xff00)   >>  8;
+    lsb = (bitRate_reg&0xff);
+
+    // transmit to RF 69
+    retval = WRITE_REG(REG_BITRATE_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_BITRATE_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_deviation(struct spi_device *spi, u32 deviation)
+{
+    int retval;
+//    u32 f_max; TODO: Abhängigkeit von Bitrate beachten!!
+    u64 f_reg;
+    u64 f_step;
+    u8 msb;
+    u8 lsb;
+    u64 factor = 1000000; // to improve precision of calculation
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: deviation");
+    #endif
+
+    if (deviation < 600 || deviation > 500000) //TODO: Abhängigkeit von Bitrate
beachten!!
+    {
+        dev_dbg(&spi->dev, "set_deviation: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculat f step
+    f_step = F_OSC * factor;
+    do_div(f_step, 524288); //  524288 = 2^19
+
+    // calculate register settings
+    f_reg = deviation * factor;
+    do_div(f_reg  , f_step);
+
+    msb = (f_reg&0xff00)   >>  8;
+    lsb = (f_reg&0xff);
+
+    // check msb
+    if (msb & !FDEVMASB_MASK)
+    {
+        dev_dbg(&spi->dev, "set_deviation: err in calc of msb");
+        INVALID_PARAM;
+    }
+
+    // write to chip
+    retval = WRITE_REG(REG_FDEV_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FDEV_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_frequency(struct spi_device *spi, u32 frequency)
+{
+    int retval;
+    u32 f_max;
+    u64 f_reg;
+    u64 f_step;
+    u8 msb;
+    u8 mid;
+    u8 lsb;
+    u64 factor = 1000000; // to improve precision of calculation
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: frequency");
+    #endif
+
+    // calculat f step
+    f_step = F_OSC * factor;
+    do_div(f_step, 524288); //  524288 = 2^19
+
+    // check input value
+    f_max = f_step * 8388608 / factor;
+    if (frequency > f_max)
+    {
+        dev_dbg(&spi->dev, "setFrequency: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculate reg settings
+    f_reg = frequency * factor;
+    do_div(f_reg  , f_step);
+
+    msb = (f_reg&0xff0000) >> 16;
+    mid = (f_reg&0xff00)   >>  8;
+    lsb = (f_reg&0xff);
+
+    // write to chip
+    retval = WRITE_REG(REG_FRF_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FRF_MID, mid);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FRF_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #0");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA0) );
+    case optionOff:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA0) );
+    default:    INVALID_PARAM;
+    }
+}    
+
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #1");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA1) );
+    case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA1) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #2");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA2) );
+    case optionOff:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA2) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: power level");
+    #endif
+
+    powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting
+
+    // check input value
+    if (powerLevel > 0x1f)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_OUTPUT_POWER) | powerLevel);
+}
+
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: pa ramp");
+    #endif
+
+    switch(paRamp) {
+    case ramp3400:    return WRITE_REG(REG_PARAMP, PARAMP_3400);
+    case ramp2000:    return WRITE_REG(REG_PARAMP, PARAMP_2000);
+    case ramp1000:    return WRITE_REG(REG_PARAMP, PARAMP_1000);
+    case ramp500:    return WRITE_REG(REG_PARAMP, PARAMP_500);
+    case ramp250:    return WRITE_REG(REG_PARAMP, PARAMP_250);
+    case ramp125:    return WRITE_REG(REG_PARAMP, PARAMP_125);
+    case ramp100:    return WRITE_REG(REG_PARAMP, PARAMP_100);
+    case ramp62:    return WRITE_REG(REG_PARAMP, PARAMP_62);
+    case ramp50:    return WRITE_REG(REG_PARAMP, PARAMP_50);
+    case ramp40:    return WRITE_REG(REG_PARAMP, PARAMP_40);
+    case ramp31:    return WRITE_REG(REG_PARAMP, PARAMP_31);
+    case ramp25:    return WRITE_REG(REG_PARAMP, PARAMP_25);
+    case ramp20:    return WRITE_REG(REG_PARAMP, PARAMP_20);
+    case ramp15:    return WRITE_REG(REG_PARAMP, PARAMP_15);
+    case ramp12:    return WRITE_REG(REG_PARAMP, PARAMP_12);
+    case ramp10:    return WRITE_REG(REG_PARAMP, PARAMP_10);
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance
antennaImpedance)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: antenna impedance");
+    #endif
+
+    switch(antennaImpedance) {
+    case fiftyOhm:        return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) &
~MASK_LNA_ZIN) );
+    case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) |
 MASK_LNA_ZIN) );
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: lna gain");
+    #endif
+
+    switch(lnaGain) {
+    case automatic:     return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_AUTO) );
+    case max:     return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX) );
+    case maxMinus6:  return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) );
+    case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) );
+    case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) );
+    case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) );
+    case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) );
+    default:     INVALID_PARAM;
+    }
+}
+
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi)
+{
+    u8 currentValue;    
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: lna gain");
+    #endif
+
+    currentValue = READ_REG(REG_LNA);
+
+    switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3)  // improvement: change
3 to define
+    {
+    case LNA_GAIN_AUTO:        return automatic;
+    case LNA_GAIN_MAX:        return max;
+    case LNA_GAIN_MAX_MINUS_6:  return maxMinus6;
+    case LNA_GAIN_MAX_MINUS_12: return maxMinus12;
+    case LNA_GAIN_MAX_MINUS_24: return maxMinus24;
+    case LNA_GAIN_MAX_MINUS_36: return maxMinus36;
+    case LNA_GAIN_MAX_MINUS_48: return maxMinus48;
+    default:            return undefined;
+    }
+}
+
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum
dccPercent dccPercent)
+{
+    switch (dccPercent) {
+    case dcc16Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) );
+    case dcc8Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) );
+    case dcc4Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) );
+    case dcc2Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) );
+    case dcc1Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) );
+    case dcc0_5Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) );
+    case dcc0_25Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) );
+    case dcc0_125Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) );
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent
dccPercent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: cut off freq");
+    #endif
+
+    return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent);
+}
+
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum
dccPercent dccPercent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: cut off freq during afc");
+    #endif
+
+    return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent);
+}
+
+int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse
mantisse, u8 exponent)
+{
+    u8 newValue;
+
+    // check value for mantisse and exponent
+    if (exponent > 7)   INVALID_PARAM;
+    if ( (mantisse!=mantisse16) &&
+         (mantisse!=mantisse20) &&
+             (mantisse!=mantisse24) ) INVALID_PARAM;
+
+    // read old value
+    newValue = READ_REG(reg);
+
+    // "delete" mantisse and exponent = just keep the DCC setting
+    newValue = newValue & MASK_BW_DCC_FREQ;
+
+    // add new mantisse
+    switch(mantisse) {
+    case mantisse16: newValue = newValue | BW_MANT_16;    break;
+    case mantisse20: newValue = newValue | BW_MANT_20;    break;
+    case mantisse24: newValue = newValue | BW_MANT_24;    break;
+    }
+
+    // add new exponent
+    newValue = newValue | exponent;
+
+    // write back
+    return WRITE_REG(reg, newValue);
+}
+
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8
exponent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: band width");
+    #endif
+
+    return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent);
+}
+
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse
mantisse, u8 exponent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: band width during afc");
+    #endif
+
+    return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
+}
+
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType
thresholdType)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold type");
+    #endif
+
+    switch (thresholdType)
+    {
+    case fixed:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) );
+    case peak:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) );
+    case average:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep
thresholdStep)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold step");
+    #endif
+
+    switch (thresholdStep) {
+    case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) );
+    case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) );
+    case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) );
+    case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) );
+    case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) );
+    case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) );
+    case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) );
+    case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) );
+    default:     INVALID_PARAM;
+    }
+}
+
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement
thresholdDecrement)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold decrement");
+    #endif
+
+    switch (thresholdDecrement) {
+    case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) );
+    case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) );
+    case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) );
+    case dec_once:       return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK)
& ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) );
+    case dec_twice:       return WRITE_REG(REG_OOKPEAK, (
(READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) );
+    case dec_4times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) );
+    case dec_8times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) );
+    case dec_16times:  return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) );
+    default:       INVALID_PARAM;
+    }
+}
+
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+{
+    u8 mask;
+    u8 shift;
+    u8 regaddr;
+    u8 regValue;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: DIO mapping");
+    #endif
+
+    // check DIO number
+    if (DIONumber > 5) INVALID_PARAM;
+
+    switch (DIONumber) {
+    case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break;
+    case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break;
+    case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break;
+    case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break;
+    case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break;
+    case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break;
+    }
+
+    // read reg
+    regValue=READ_REG(regaddr);
+    // delete old value
+    regValue = regValue & ~mask;
+    // add new value
+    regValue = regValue | value << shift;
+    // write back
+    return WRITE_REG(regaddr,regValue);
+}
+
+bool rf69_get_flag(struct spi_device *spi, enum flag flag)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: flag");
+    #endif
+
+    switch(flag) {
+    case modeSwitchCompleted:     return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_MODE_READY);
+    case readyToReceive:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_RX_READY);
+    case readyToSend:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_TX_READY);
+    case pllLocked:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_PLL_LOCK);
+    case rssiExceededThreshold:   return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_RSSI);
+    case timeout:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_TIMEOUT);
+    case automode:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_AUTOMODE);
+    case syncAddressMatch:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+    case fifoFull:              return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_FULL);
+/*    case fifoNotEmpty:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */
+    case fifoEmpty:              return !(READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_NOT_EMPTY);
+    case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_LEVEL);
+    case fifoOverrun:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_OVERRUN);
+    case packetSent:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_PACKET_SENT);
+    case payloadReady:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_PAYLOAD_READY);
+    case crcOk:              return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_CRC_OK);
+    case batteryLow:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_LOW_BAT);
+    default:              return false;
+    }
+}
+
+int rf69_reset_flag(struct spi_device *spi, enum flag flag)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "reset: flag");
+    #endif
+
+    switch(flag) {
+    case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1,
MASK_IRQFLAGS1_RSSI);
+    case syncAddressMatch:        return WRITE_REG(REG_IRQFLAGS1,
MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+    case fifoOverrun:        return WRITE_REG(REG_IRQFLAGS2,
MASK_IRQFLAGS2_FIFO_OVERRUN);
+    default:            INVALID_PARAM;
+    }
+}
+
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: rssi threshold");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RSSITHRESH, threshold);
+}
+
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: start timeout");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RXTIMEOUT1, timeout);
+}
+
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: rssi timeout");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RXTIMEOUT2, timeout);
+}
+
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+{
+    int retval;
+    u8 msb, lsb;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: preample length");
+    #endif
+
+    /* no value check needed - u16 exactly matches register size */
+
+    /* calculate reg settings */
+    msb = (preambleLength&0xff00)   >>  8;
+    lsb = (preambleLength&0xff);
+
+    /* transmit to chip */
+    retval = WRITE_REG(REG_PREAMBLE_MSB, msb);
+    if (retval) return retval;
+    retval = WRITE_REG(REG_PREAMBLE_LSB, lsb);
+
+    return retval;
+}
+
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync enable");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_SYNC_ON) );
+    case optionOff:    return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition
fifoFillCondition)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: fifo fill condition");
+    #endif
+
+    switch(fifoFillCondition) {
+    case always:         return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+    case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+    default:         INVALID_PARAM;
+    }
+}
+
+int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync size");
+    #endif
+
+    // check input value
+    if (syncSize > 0x07)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) &
~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) );
+}
+
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync tolerance");
+    #endif
+
+    // check input value
+    if (syncTolerance > 0x07)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) &
~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance);
+}
+
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+{
+    int retval = 0;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync values");
+    #endif
+
+    retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]);
+    retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]);
+    retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]);
+    retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]);
+    retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]);
+    retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]);
+    retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]);
+    retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]);
+
+    return retval;
+}
+
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat
packetFormat)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: packet format");
+    #endif
+
+    switch(packetFormat) {
+    case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+    case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+    default:          INVALID_PARAM;
+    }
+}
+
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: crc enable");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_CRC_ON) );
+    case optionOff:    return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering
addressFiltering)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: address filtering");
+    #endif
+
+    switch (addressFiltering) {
+    case filteringOff:         return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_OFF) );
+    case nodeAddress:         return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_NODE) );
+    case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) );
+    default:             INVALID_PARAM;
+    }
+}
+
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: payload length");
+    #endif
+
+    return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength);
+}
+
+u8  rf69_get_payload_length(struct spi_device *spi)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: payload length");
+    #endif
+
+    return (u8) READ_REG(REG_PAYLOAD_LENGTH);
+}
+
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: node address");
+    #endif
+
+    return WRITE_REG(REG_NODEADRS, nodeAddress);
+}
+
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: broadcast address");
+    #endif
+
+    return WRITE_REG(REG_BROADCASTADRS, broadcastAddress);
+}
+
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition
txStartCondition)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: start condition");
+    #endif
+
+    switch(txStartCondition) {
+    case fifoLevel:       return WRITE_REG(REG_FIFO_THRESH,
(READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) );
+    case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH,
(READ_REG(REG_FIFO_THRESH) |  MASK_FIFO_THRESH_TXSTART) );
+    default:       INVALID_PARAM;
+    }
+}
+
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
+{
+    int retval;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: fifo threshold");
+    #endif
+
+    // check input value
+    if (threshold & 0x80)
+        INVALID_PARAM;
+
+    // write value
+    retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) &
~MASK_FIFO_THRESH_VALUE) | threshold);
+    if (retval)
+        return retval;
+
+    // access the fifo to activate new threshold
+    return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer
+}
+
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: dagc");
+    #endif
+
+    switch(dagc) {
+    case normalMode:         return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL);
+    case improve:             return WRITE_REG(REG_TESTDAGC,
DAGC_IMPROVED_LOWBETA0);
+    case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC,
DAGC_IMPROVED_LOWBETA1);
+    default:             INVALID_PARAM;
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+    #ifdef DEBUG_FIFO_ACCESS    
+        int i;
+    #endif
+    struct spi_transfer transfer;
+    u8 local_buffer[FIFO_SIZE + 1];
+    int retval;
+
+    if (size > FIFO_SIZE)
+    {
+        #ifdef DEBUG
+            dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then
internal buffer \n");
+        #endif
+        return -EMSGSIZE;
+    }
+
+    /* prepare a bidirectional transfer */
+    local_buffer[0] = REG_FIFO;
+    memset(&transfer, 0, sizeof(transfer));
+      transfer.tx_buf = local_buffer;
+      transfer.rx_buf = local_buffer;
+    transfer.len    = size+1;
+
+    retval = spi_sync_transfer(spi, &transfer, 1);
+
+    #ifdef DEBUG_FIFO_ACCESS
+        for (i=0; i<size; i++)
+            dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]);
+    #endif
+
+    memcpy(buffer, &local_buffer[1], size);  // TODO: ohne memcopy wäre schöner
+
+    return retval;
+}
+
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+    #ifdef DEBUG_FIFO_ACCESS    
+        int i;
+    #endif
+    char spi_address = REG_FIFO | WRITE_BIT;
+    u8 local_buffer[FIFO_SIZE + 1];
+
+    if (size > FIFO_SIZE)
+    {
+        #ifdef DEBUG
+            dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then
internal buffer \n");
+        #endif
+        return -EMSGSIZE;
+    }
+
+    local_buffer[0] = spi_address;
+    memcpy(&local_buffer[1], buffer, size);  // TODO: ohne memcopy wäre schöner
+
+    #ifdef DEBUG_FIFO_ACCESS
+        for (i=0; i<size; i++)
+            dev_dbg(&spi->dev, "0x%x\n",buffer[i]);
+    #endif
+
+    return spi_write (spi, local_buffer, size + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+u8 rf69_read_reg(struct spi_device *spi, u8 addr)
+{
+    int retval;
+
+    retval = spi_w8r8(spi, addr);
+
+    #ifdef DEBUG_VALUES
+        if (retval < 0)
+            /* should never happen, since we already checked,
+               that module is connected. Therefore no error
+               handling, just an optional error message... */
+            dev_dbg(&spi->dev, "read 0x%x FAILED\n",
+                addr);
+        else
+            dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n",
+                retval,
+                addr);
+    #endif
+
+    return retval;
+}
+
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value)
+{
+    int retval;
+    char buffer[2];
+    
+    buffer[0] = addr | WRITE_BIT;
+    buffer[1] = value;
+
+    retval = spi_write(spi, &buffer, 2);
+
+    #ifdef DEBUG_VALUES
+        if (retval < 0)
+            /* should never happen, since we already checked,
+               that module is connected. Therefore no error
+               handling, just an optional error message... */
+            dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n",
+                value,
+                addr);
+        else
+            dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n",
+                value,
+                addr);
+    #endif
+
+    return retval;
+}
+
+
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
new file mode 100644
index 0000000..6a6841b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.h
@@ -0,0 +1,82 @@
+/*
+ * hardware abstraction/register access for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef RF69_H
+#define RF69_H
+
+#include "rf69_enum.h"
+#include "rf69_registers.h"
+
+#define F_OSC         32000000  /* in Hz */
+#define FREQUENCY    433920000 /* in Hz, modifying this value impacts CE
certification */
+#define FIFO_SIZE     66        /* in byte */
+#define FIFO_THRESHOLD    15       /* in byte */
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode);
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode);
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
+enum modulation rf69_get_modulation(struct spi_device *spi);
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping
modShaping);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_deviation(struct spi_device *spi, u32 deviation);
+int rf69_set_frequency(struct spi_device *spi, u32 frequency);
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance
antennaImpedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi);
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum
dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent
dccPercent);
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum
dccPercent dccPercent);
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8
exponent);
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse
mantisse, u8 exponent);
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType
thresholdType);
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep
thresholdStep);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement
thresholdDecrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+bool rf69_get_flag(struct spi_device *spi, enum flag flag);
+int rf69_reset_flag(struct spi_device *spi, enum flag flag);
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition
fifoFillCondition);
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance);
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat
packetFormat);
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering
addressFiltering);
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength);
+u8  rf69_get_payload_length(struct spi_device *spi);
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition
txStartCondition);
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size);
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size);
+
+u8  rf69_read_reg (struct spi_device *spi, u8 addr);
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value);
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_enum.h
b/drivers/staging/pi433/rf69_enum.h
new file mode 100644
index 0000000..fbfb59b
--- /dev/null
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -0,0 +1,201 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_registers.h
b/drivers/staging/pi433/rf69_registers.h
new file mode 100644
index 0000000..d0c4992
--- /dev/null
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -0,0 +1,489 @@
+/*
+ * register description for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*******************************************/
+/* RF69 register addresses           */
+/*******************************************/
+#define  REG_FIFO            0x00
+#define  REG_OPMODE            0x01
+#define  REG_DATAMODUL            0x02
+#define  REG_BITRATE_MSB        0x03
+#define  REG_BITRATE_LSB        0x04
+#define  REG_FDEV_MSB            0x05
+#define  REG_FDEV_LSB            0x06
+#define  REG_FRF_MSB            0x07
+#define  REG_FRF_MID            0x08
+#define  REG_FRF_LSB            0x09
+#define  REG_OSC1            0x0A
+#define  REG_AFCCTRL            0x0B
+#define  REG_LOWBAT            0x0C
+#define  REG_LISTEN1            0x0D
+#define  REG_LISTEN2            0x0E
+#define  REG_LISTEN3            0x0F
+#define  REG_VERSION            0x10
+#define  REG_PALEVEL            0x11
+#define  REG_PARAMP            0x12
+#define  REG_OCP            0x13
+#define  REG_AGCREF            0x14 /* not available on RF69 */
+#define  REG_AGCTHRESH1            0x15 /* not available on RF69 */
+#define  REG_AGCTHRESH2            0x16 /* not available on RF69 */
+#define  REG_AGCTHRESH3            0x17 /* not available on RF69 */
+#define  REG_LNA            0x18
+#define  REG_RXBW            0x19
+#define  REG_AFCBW            0x1A
+#define  REG_OOKPEAK            0x1B
+#define  REG_OOKAVG            0x1C
+#define  REG_OOKFIX            0x1D
+#define  REG_AFCFEI            0x1E
+#define  REG_AFCMSB            0x1F
+#define  REG_AFCLSB            0x20
+#define  REG_FEIMSB            0x21
+#define  REG_FEILSB            0x22
+#define  REG_RSSICONFIG            0x23
+#define  REG_RSSIVALUE            0x24
+#define  REG_DIOMAPPING1        0x25
+#define  REG_DIOMAPPING2        0x26
+#define  REG_IRQFLAGS1            0x27
+#define  REG_IRQFLAGS2            0x28
+#define  REG_RSSITHRESH            0x29
+#define  REG_RXTIMEOUT1            0x2A
+#define  REG_RXTIMEOUT2            0x2B
+#define  REG_PREAMBLE_MSB        0x2C
+#define  REG_PREAMBLE_LSB        0x2D
+#define  REG_SYNC_CONFIG        0x2E
+#define  REG_SYNCVALUE1            0x2F
+#define  REG_SYNCVALUE2            0x30
+#define  REG_SYNCVALUE3            0x31
+#define  REG_SYNCVALUE4            0x32
+#define  REG_SYNCVALUE5            0x33
+#define  REG_SYNCVALUE6            0x34
+#define  REG_SYNCVALUE7            0x35
+#define  REG_SYNCVALUE8            0x36
+#define  REG_PACKETCONFIG1        0x37
+#define  REG_PAYLOAD_LENGTH        0x38
+#define  REG_NODEADRS            0x39
+#define  REG_BROADCASTADRS        0x3A
+#define  REG_AUTOMODES            0x3B
+#define  REG_FIFO_THRESH        0x3C
+#define  REG_PACKETCONFIG2        0x3D
+#define  REG_AESKEY1            0x3E
+#define  REG_AESKEY2            0x3F
+#define  REG_AESKEY3            0x40
+#define  REG_AESKEY4            0x41
+#define  REG_AESKEY5            0x42
+#define  REG_AESKEY6            0x43
+#define  REG_AESKEY7            0x44
+#define  REG_AESKEY8            0x45
+#define  REG_AESKEY9            0x46
+#define  REG_AESKEY10            0x47
+#define  REG_AESKEY11            0x48
+#define  REG_AESKEY12            0x49
+#define  REG_AESKEY13            0x4A
+#define  REG_AESKEY14            0x4B
+#define  REG_AESKEY15            0x4C
+#define  REG_AESKEY16            0x4D
+#define  REG_TEMP1            0x4E
+#define  REG_TEMP2            0x4F
+#define  REG_TESTPA1            0x5A /* only present on RFM69HW */
+#define  REG_TESTPA2            0x5C /* only present on RFM69HW */
+#define  REG_TESTDAGC            0x6F
+
+/******************************************************/
+/* RF69/SX1231 bit definition                */
+/******************************************************/
+/* write bit */
+#define WRITE_BIT                0x80
+
+/* RegOpMode */
+#define  MASK_OPMODE_SEQUENCER_OFF        0x80
+#define  MASK_OPMODE_LISTEN_ON            0x40
+#define  MASK_OPMODE_LISTEN_ABORT        0x20
+#define  MASK_OPMODE_MODE            0x1C
+
+#define  OPMODE_MODE_SLEEP            0x00
+#define  OPMODE_MODE_STANDBY            0x04 /* default */
+#define  OPMODE_MODE_SYNTHESIZER        0x08
+#define  OPMODE_MODE_TRANSMIT            0x0C
+#define  OPMODE_MODE_RECEIVE            0x10
+
+/* RegDataModul */
+#define  MASK_DATAMODUL_MODE            0x06
+#define  MASK_DATAMODUL_MODULATION_TYPE        0x18
+#define  MASK_DATAMODUL_MODULATION_SHAPE    0x03
+
+#define  DATAMODUL_MODE_PACKET            0x00 /* default */
+#define  DATAMODUL_MODE_CONTINUOUS        0x40
+#define  DATAMODUL_MODE_CONTINUOUS_NOSYNC    0x60
+
+#define  DATAMODUL_MODULATION_TYPE_FSK        0x00 /* default */
+#define  DATAMODUL_MODULATION_TYPE_OOK        0x08
+
+#define  DATAMODUL_MODULATION_SHAPE_NONE    0x00 /* default */
+#define  DATAMODUL_MODULATION_SHAPE_1_0        0x01
+#define  DATAMODUL_MODULATION_SHAPE_0_5        0x02
+#define  DATAMODUL_MODULATION_SHAPE_0_3        0x03
+#define  DATAMODUL_MODULATION_SHAPE_BR        0x01
+#define  DATAMODUL_MODULATION_SHAPE_2BR        0x02
+
+/* RegFDevMsb (0x05)*/
+#define FDEVMASB_MASK                0x3f
+
+/*
+// RegOsc1
+#define  OSC1_RCCAL_START            0x80
+#define  OSC1_RCCAL_DONE            0x40
+
+// RegLowBat
+#define  LOWBAT_MONITOR                0x10
+#define  LOWBAT_ON                0x08
+#define  LOWBAT_OFF                0x00  // Default
+
+#define  LOWBAT_TRIM_1695            0x00
+#define  LOWBAT_TRIM_1764            0x01
+#define  LOWBAT_TRIM_1835            0x02  // Default
+#define  LOWBAT_TRIM_1905            0x03
+#define  LOWBAT_TRIM_1976            0x04
+#define  LOWBAT_TRIM_2045            0x05
+#define  LOWBAT_TRIM_2116            0x06
+#define  LOWBAT_TRIM_2185            0x07
+
+
+// RegListen1
+#define  LISTEN1_RESOL_64            0x50
+#define  LISTEN1_RESOL_4100            0xA0  // Default
+#define  LISTEN1_RESOL_262000            0xF0
+
+#define  LISTEN1_CRITERIA_RSSI            0x00  // Default
+#define  LISTEN1_CRITERIA_RSSIANDSYNC        0x08
+
+#define  LISTEN1_END_00                0x00
+#define  LISTEN1_END_01                0x02  // Default
+#define  LISTEN1_END_10                0x04
+
+
+// RegListen2
+#define  LISTEN2_COEFIDLE_VALUE            0xF5 // Default
+
+// RegListen3
+#define  LISTEN3_COEFRX_VALUE            0x20 // Default
+*/
+
+// RegPaLevel
+#define  MASK_PALEVEL_PA0            0x80
+#define  MASK_PALEVEL_PA1            0x40
+#define  MASK_PALEVEL_PA2            0x20
+#define  MASK_PALEVEL_OUTPUT_POWER        0x1F
+
+
+
+// RegPaRamp
+#define  PARAMP_3400                0x00
+#define  PARAMP_2000                0x01
+#define  PARAMP_1000                0x02
+#define  PARAMP_500                0x03
+#define  PARAMP_250                0x04
+#define  PARAMP_125                0x05
+#define  PARAMP_100                0x06
+#define  PARAMP_62                0x07
+#define  PARAMP_50                0x08
+#define  PARAMP_40                0x09 /* default */
+#define  PARAMP_31                0x0A
+#define  PARAMP_25                0x0B
+#define  PARAMP_20                0x0C
+#define  PARAMP_15                0x0D
+#define  PARAMP_12                0x0E
+#define  PARAMP_10                0x0F
+
+#define  MASK_PARAMP                0x0F
+
+/*
+// RegOcp
+#define  OCP_OFF                0x0F
+#define  OCP_ON                    0x1A  // Default
+
+#define  OCP_TRIM_45                0x00
+#define  OCP_TRIM_50                0x01
+#define  OCP_TRIM_55                0x02
+#define  OCP_TRIM_60                0x03
+#define  OCP_TRIM_65                0x04
+#define  OCP_TRIM_70                0x05
+#define  OCP_TRIM_75                0x06
+#define  OCP_TRIM_80                0x07
+#define  OCP_TRIM_85                0x08
+#define  OCP_TRIM_90                0x09
+#define  OCP_TRIM_95                0x0A
+#define  OCP_TRIM_100                0x0B  // Default
+#define  OCP_TRIM_105                0x0C
+#define  OCP_TRIM_110                0x0D
+#define  OCP_TRIM_115                0x0E
+#define  OCP_TRIM_120                0x0F
+*/
+
+/* RegLna (0x18) */
+#define  MASK_LNA_ZIN                0x80
+#define  MASK_LNA_CURRENT_GAIN            0x38
+#define  MASK_LNA_GAIN                0x07
+
+#define  LNA_GAIN_AUTO                0x00 /* default */
+#define  LNA_GAIN_MAX                0x01
+#define  LNA_GAIN_MAX_MINUS_6            0x02
+#define  LNA_GAIN_MAX_MINUS_12            0x03
+#define  LNA_GAIN_MAX_MINUS_24            0x04
+#define  LNA_GAIN_MAX_MINUS_36            0x05
+#define  LNA_GAIN_MAX_MINUS_48            0x06
+
+
+/* RegRxBw (0x19) and RegAfcBw (0x1A) */
+#define  MASK_BW_DCC_FREQ            0xE0
+#define  MASK_BW_MANTISSE            0x18
+#define  MASK_BW_EXPONENT            0x07
+
+#define  BW_DCC_16_PERCENT            0x00
+#define  BW_DCC_8_PERCENT            0x20
+#define  BW_DCC_4_PERCENT            0x40 /* default */
+#define  BW_DCC_2_PERCENT            0x60
+#define  BW_DCC_1_PERCENT            0x80
+#define  BW_DCC_0_5_PERCENT            0xA0
+#define  BW_DCC_0_25_PERCENT            0xC0
+#define  BW_DCC_0_125_PERCENT            0xE0
+
+#define  BW_MANT_16                0x00
+#define  BW_MANT_20                0x08
+#define  BW_MANT_24                0x10 /* default */
+
+
+/* RegOokPeak (0x1B) */
+#define  MASK_OOKPEAK_THRESTYPE            0xc0
+#define  MASK_OOKPEAK_THRESSTEP            0x38
+#define  MASK_OOKPEAK_THRESDEC            0x07
+
+#define  OOKPEAK_THRESHTYPE_FIXED        0x00
+#define  OOKPEAK_THRESHTYPE_PEAK        0x40 /* default */
+#define  OOKPEAK_THRESHTYPE_AVERAGE        0x80
+
+#define  OOKPEAK_THRESHSTEP_0_5_DB        0x00 /* default */
+#define  OOKPEAK_THRESHSTEP_1_0_DB        0x08
+#define  OOKPEAK_THRESHSTEP_1_5_DB        0x10
+#define  OOKPEAK_THRESHSTEP_2_0_DB        0x18
+#define  OOKPEAK_THRESHSTEP_3_0_DB        0x20
+#define  OOKPEAK_THRESHSTEP_4_0_DB        0x28
+#define  OOKPEAK_THRESHSTEP_5_0_DB        0x30
+#define  OOKPEAK_THRESHSTEP_6_0_DB        0x38
+
+#define  OOKPEAK_THRESHDEC_ONCE            0x00 /* default */
+#define  OOKPEAK_THRESHDEC_EVERY_2ND        0x01
+#define  OOKPEAK_THRESHDEC_EVERY_4TH        0x02
+#define  OOKPEAK_THRESHDEC_EVERY_8TH        0x03
+#define  OOKPEAK_THRESHDEC_TWICE        0x04
+#define  OOKPEAK_THRESHDEC_4_TIMES        0x05
+#define  OOKPEAK_THRESHDEC_8_TIMES        0x06
+#define  OOKPEAK_THRESHDEC_16_TIMES        0x07
+
+/*
+// RegOokAvg
+#define  OOKAVG_AVERAGETHRESHFILT_00        0x00
+#define  OOKAVG_AVERAGETHRESHFILT_01        0x40
+#define  OOKAVG_AVERAGETHRESHFILT_10        0x80  // Default
+#define  OOKAVG_AVERAGETHRESHFILT_11        0xC0
+
+
+// RegAfcFei
+#define  AFCFEI_FEI_DONE            0x40
+#define  AFCFEI_FEI_START            0x20
+#define  AFCFEI_AFC_DONE            0x10
+#define  AFCFEI_AFCAUTOCLEAR_ON            0x08
+#define  AFCFEI_AFCAUTOCLEAR_OFF        0x00  // Default
+
+#define  AFCFEI_AFCAUTO_ON            0x04
+#define  AFCFEI_AFCAUTO_OFF            0x00  // Default
+
+#define  AFCFEI_AFC_CLEAR            0x02
+#define  AFCFEI_AFC_START            0x01
+
+// RegRssiConfig
+#define  RSSI_FASTRX_ON                0x08
+#define  RSSI_FASTRX_OFF            0x00  // Default
+#define  RSSI_DONE                0x02
+#define  RSSI_START                0x01
+*/
+
+/* RegDioMapping1 */
+#define  MASK_DIO0                0xC0
+#define  MASK_DIO1                0x30
+#define  MASK_DIO2                0x0C
+#define  MASK_DIO3                0x03
+#define  SHIFT_DIO0                6
+#define  SHIFT_DIO1                4
+#define  SHIFT_DIO2                2
+#define  SHIFT_DIO3                0
+
+/* RegDioMapping2 */
+#define  MASK_DIO4                0xC0
+#define  MASK_DIO5                0x30
+#define  SHIFT_DIO4                6
+#define  SHIFT_DIO5                4
+
+/* DIO numbers */
+#define  DIO0                    0
+#define  DIO1                    1
+#define  DIO2                    2
+#define  DIO3                    3
+#define  DIO4                    4
+#define  DIO5                    5
+
+/* DIO Mapping values (packet mode) */
+#define  DIO_ModeReady_DIO4            0x00
+#define  DIO_ModeReady_DIO5            0x03
+#define  DIO_ClkOut                0x00
+#define  DIO_Data                0x01
+#define  DIO_TimeOut_DIO1            0x03
+#define  DIO_TimeOut_DIO4            0x00
+#define  DIO_Rssi_DIO0                0x03
+#define  DIO_Rssi_DIO3_4            0x01
+#define  DIO_RxReady                0x02
+#define  DIO_PLLLock                0x03
+#define  DIO_TxReady                0x01
+#define  DIO_FifoFull_DIO1            0x01
+#define  DIO_FifoFull_DIO3            0x00
+#define  DIO_SyncAddress            0x02
+#define  DIO_FifoNotEmpty_DIO1            0x02
+#define  DIO_FifoNotEmpty_FIO2            0x00
+#define  DIO_Automode                0x04
+#define  DIO_FifoLevel                0x00
+#define  DIO_CrcOk                0x00
+#define  DIO_PayloadReady            0x01
+#define  DIO_PacketSent                0x00
+#define  DIO_Dclk                0x00
+
+/* RegDioMapping2 CLK_OUT part */
+#define  MASK_DIOMAPPING2_CLK_OUT        0x07
+
+#define  DIOMAPPING2_CLK_OUT_NO_DIV        0x00
+#define  DIOMAPPING2_CLK_OUT_DIV_2        0x01
+#define  DIOMAPPING2_CLK_OUT_DIV_4        0x02
+#define  DIOMAPPING2_CLK_OUT_DIV_8        0x03
+#define  DIOMAPPING2_CLK_OUT_DIV_16        0x04
+#define  DIOMAPPING2_CLK_OUT_DIV_32        0x05
+#define  DIOMAPPING2_CLK_OUT_RC            0x06
+#define  DIOMAPPING2_CLK_OUT_OFF        0x07 /* default */
+
+/* RegIrqFlags1 */
+#define  MASK_IRQFLAGS1_MODE_READY        0x80
+#define  MASK_IRQFLAGS1_RX_READY        0x40
+#define  MASK_IRQFLAGS1_TX_READY        0x20
+#define  MASK_IRQFLAGS1_PLL_LOCK        0x10
+#define  MASK_IRQFLAGS1_RSSI            0x08
+#define  MASK_IRQFLAGS1_TIMEOUT            0x04
+#define  MASK_IRQFLAGS1_AUTOMODE        0x02
+#define  MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH    0x01
+
+/* RegIrqFlags2 */
+#define  MASK_IRQFLAGS2_FIFO_FULL        0x80
+#define  MASK_IRQFLAGS2_FIFO_NOT_EMPTY        0x40
+#define  MASK_IRQFLAGS2_FIFO_LEVEL        0x20
+#define  MASK_IRQFLAGS2_FIFO_OVERRUN        0x10
+#define  MASK_IRQFLAGS2_PACKET_SENT        0x08
+#define  MASK_IRQFLAGS2_PAYLOAD_READY        0x04
+#define  MASK_IRQFLAGS2_CRC_OK            0x02
+#define  MASK_IRQFLAGS2_LOW_BAT            0x01
+
+/* RegSyncConfig */
+#define  MASK_SYNC_CONFIG_SYNC_ON        0x80 /* default */
+#define  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION    0x40
+#define  MASK_SYNC_CONFIG_SYNC_SIZE        0x38
+#define  MASK_SYNC_CONFIG_SYNC_TOLERANCE    0x07
+
+/* RegPacketConfig1 */
+#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE    0x80
+#define  MASK_PACKETCONFIG1_DCFREE            0x60
+#define  MASK_PACKETCONFIG1_CRC_ON            0x10 /* default */
+#define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF        0x08
+#define  MASK_PACKETCONFIG1_ADDRESSFILTERING        0x06
+
+#define  PACKETCONFIG1_DCFREE_OFF            0x00 /* default */
+#define  PACKETCONFIG1_DCFREE_MANCHESTER        0x20
+#define  PACKETCONFIG1_DCFREE_WHITENING            0x40
+#define  PACKETCONFIG1_ADDRESSFILTERING_OFF        0x00 /* default */
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODE        0x02
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST    0x04
+
+/*
+// RegAutoModes
+#define  AUTOMODES_ENTER_OFF            0x00  // Default
+#define  AUTOMODES_ENTER_FIFONOTEMPTY        0x20
+#define  AUTOMODES_ENTER_FIFOLEVEL        0x40
+#define  AUTOMODES_ENTER_CRCOK            0x60
+#define  AUTOMODES_ENTER_PAYLOADREADY        0x80
+#define  AUTOMODES_ENTER_SYNCADRSMATCH        0xA0
+#define  AUTOMODES_ENTER_PACKETSENT        0xC0
+#define  AUTOMODES_ENTER_FIFOEMPTY        0xE0
+
+#define  AUTOMODES_EXIT_OFF            0x00  // Default
+#define  AUTOMODES_EXIT_FIFOEMPTY        0x04
+#define  AUTOMODES_EXIT_FIFOLEVEL        0x08
+#define  AUTOMODES_EXIT_CRCOK            0x0C
+#define  AUTOMODES_EXIT_PAYLOADREADY        0x10
+#define  AUTOMODES_EXIT_SYNCADRSMATCH        0x14
+#define  AUTOMODES_EXIT_PACKETSENT        0x18
+#define  AUTOMODES_EXIT_RXTIMEOUT        0x1C
+
+#define  AUTOMODES_INTERMEDIATE_SLEEP        0x00  // Default
+#define  AUTOMODES_INTERMEDIATE_STANDBY        0x01
+#define  AUTOMODES_INTERMEDIATE_RECEIVER    0x02
+#define  AUTOMODES_INTERMEDIATE_TRANSMITTER    0x03
+
+*/
+/* RegFifoThresh (0x3c) */
+#define  MASK_FIFO_THRESH_TXSTART        0x80
+#define  MASK_FIFO_THRESH_VALUE            0x7F
+
+/*
+
+// RegPacketConfig2
+#define  PACKET2_RXRESTARTDELAY_1BIT        0x00  // Default
+#define  PACKET2_RXRESTARTDELAY_2BITS        0x10
+#define  PACKET2_RXRESTARTDELAY_4BITS        0x20
+#define  PACKET2_RXRESTARTDELAY_8BITS        0x30
+#define  PACKET2_RXRESTARTDELAY_16BITS        0x40
+#define  PACKET2_RXRESTARTDELAY_32BITS        0x50
+#define  PACKET2_RXRESTARTDELAY_64BITS        0x60
+#define  PACKET2_RXRESTARTDELAY_128BITS        0x70
+#define  PACKET2_RXRESTARTDELAY_256BITS        0x80
+#define  PACKET2_RXRESTARTDELAY_512BITS        0x90
+#define  PACKET2_RXRESTARTDELAY_1024BITS    0xA0
+#define  PACKET2_RXRESTARTDELAY_2048BITS    0xB0
+#define  PACKET2_RXRESTARTDELAY_NONE        0xC0
+#define  PACKET2_RXRESTART            0x04
+
+#define  PACKET2_AUTORXRESTART_ON        0x02  // Default
+#define  PACKET2_AUTORXRESTART_OFF        0x00
+
+#define  PACKET2_AES_ON                0x01
+#define  PACKET2_AES_OFF            0x00  // Default
+
+
+// RegTemp1
+#define  TEMP1_MEAS_START            0x08
+#define  TEMP1_MEAS_RUNNING            0x04
+#define  TEMP1_ADCLOWPOWER_ON            0x01  // Default
+#define  TEMP1_ADCLOWPOWER_OFF            0x00
+*/
+
+// RegTestDagc (0x6F)
+#define  DAGC_NORMAL                0x00 /* Reset value */
+#define  DAGC_IMPROVED_LOWBETA1            0x20
+#define  DAGC_IMPROVED_LOWBETA0            0x30 /* Recommended val */
 
 

> Greg KH <gregkh@linuxfoundation.org> hat am 15. Juli 2017 um 15:02
> geschrieben:
>
>
> On Sat, Jul 15, 2017 at 02:59:25PM +0200, Marcus Wolf wrote:
> > Hi!
> >
> > It's me again. Seems like I also need help on sending the email :-/
> >
> > I checked the whitespace/line wrap problem, but couldn't find any suspicious
> > lines.
> >
> > What I did:
> > * Looked into my outbox - the copy of my mail to you seems to be okay...
> > * I sent the patch once again (just to me) - result: Seems to be fine, too.
> >
> > Maybe you can bounce back my mail? Maybe I'll get an idea what went wrong,
> > if I
> > see the smashed code...
>
> You sent the patch in html format, which caused all of the whitespace
> corruption. html will not work for kernel patches for obvious reasons
> :)
>
> thanks,
>
> greg k-h
>

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 13:10             ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-15 13:10 UTC (permalink / raw)
  To: Greg KH
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi!
 
Ok. Thanks for the info. Didn't observe that.
 I'll give the old patch another try.
 
I will send a new patch as soon, as I know. how to produce the 
poper format (with subjects, signing and so on).

Cheers,

Marcus

 
 
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 268d4e6..fdf060c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"
 
 source "drivers/staging/typec/Kconfig"
 
+source "drivers/staging/pi433/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b93e6f5..998f644 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)        += ks7010/
 obj-$(CONFIG_GREYBUS)        += greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)    += vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)    += ccree/
+obj-$(CONFIG_PI433)        += pi433/
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
new file mode 100644
index 0000000..004b502
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
@@ -0,0 +1,53 @@
+// Definitions for Pi433
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+    fragment@1 {
+        target = <&gpio>;
+        __overlay__ {
+            pi433_pins: pi433_pins {
+                brcm,pins = <7 25 24>;
+                brcm,function = <0 0 0>; // in in in
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&spi0>;
+        __overlay__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            status = "okay";
+
+            pi433: pi433@0 {
+                compatible = "Smarthome-Wolf,pi433";
+                reg = <0>;
+                spi-max-frequency = <10000000>;
+                status = "okay";
+
+                pinctrl-0 = <&pi433_pins>;
+                DIO0-gpio = <&gpio 24 0>;
+                DIO1-gpio = <&gpio 25 0>;
+                DIO2-gpio = <&gpio  7 0>;
+            };
+        };
+    };
+};
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt
b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
new file mode 100644
index 0000000..14197c6
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
@@ -0,0 +1,62 @@
+* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see
www.pi433.de)
+
+Required properties:
+- compatible: must be "Smarthome-Wolf,pi433"
+- reg: chip select of SPI Interface
+- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69
module
+
+
+Example:
+
+With the following lines in gpio-section, the gpio pins, connected with pi433
are
+reserved/declared.
+
+&gpio{
+    [...]
+
+    pi433_pins: pi433_pins {
+        brcm,pins = <7 25 24>;
+        brcm,function = <0 0 0>; // in in in
+    };
+
+    [...]
+}
+
+With the following lines in spi section, the device pi433 is declared.
+It consists of the three gpio pins and an spi interface (here chip select 0)
+
+&spi0{
+    [...]
+
+    pi433: pi433@0 {
+        compatible = "Smarthome-Wolf,pi433";
+        reg = <0>; /* CE 0 */
+        #address-cells = <1>;
+        #size-cells = <0>;
+        spi-max-frequency = <10000000>;
+
+        pinctrl-0 = <&pi433_pins>;
+        DIO0-gpio = <&gpio 24 0>;
+        DIO1-gpio = <&gpio 25 0>;
+        DIO2-gpio = <&gpio  7 0>;
+    };
+}
+
+
+
+For Raspbian users only
+=======================
+Since Raspbian supports device tree overlays, you may use and overlay, instead
+of editing your boards device tree.
+For using the overlay, you need to compile the file pi433-overlay.dts you can
+find aside to this documentation.
+The file needs to be compiled - either manually or by integration in your
kernel
+source tree. For a manual compile, you may use a command line like the
following:
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+arch/arm/boot/dts/overlays and you need to add the file to the list of files
+in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
+kernel make files compile the device tree overlay for you.
+
+
diff --git a/drivers/staging/pi433/Documentation/pi433.txt
b/drivers/staging/pi433/Documentation/pi433.txt
new file mode 100644
index 0000000..860dd0f
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -0,0 +1,274 @@
+=====
+Pi433
+=====
+
+
+Introduction
+============
+This driver is for controlling pi433, a radio module for the Raspberry Pi
+(www.pi433.de). It supports transmission and reception. It can be opened
+by multiple applications for transmission and reception. While transmit
+jobs were queued and process automatically in the background, the first  
+application asking for reception will block out all other applications  
+until something gets received terminates the read request.  
+The driver supports on the fly reloading of the hardware fifo of the rf
+chip, thus enabling for much longer telegrams then hardware fifo size.
+
+Discription of driver operation
+===============================
+
+a) transmission
+
+Each transmission can take place with a different configuration of the rf
+module. Therfore each application can set its own set of parameters. The driver
+takes care, that each transmission takes place with the parameterset of the
+application, that requests the transmission. To allow the transmission to take
+place in the background, a tx thread is introduced.
+The transfer of data from the main thread to the tx thread is realised by a
+kfifo. With each write request of an application, the passed in data and the
+corresponding parameter set gets written to the kfifo.  
+On the other "side" of the kfifo, the tx thread continuously checks, whether
the
+kfifo is empty. If not, it gets one set of config and data from the kfifo. If  
+there is no receive request or the receiver is still waiting for something in
+the air, the rf module is set to standby, the parameters for transmission gets
+set, the hardware fifo of the rf chip gets preloaded and the transmission gets
+started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling
+much longer telegrams then hardware fifo size. If the telegram is send and
there
+is more data available in the kfifo, the procedure is repeated. If not the
+transmission cycle ends.
+
+b) reception
+
+Since there is only one application allowed to receive data at a time, for
+reception there is only one configuration set.
+As soon as an application sets an request for receiving a telegram, the
reception
+configuration set is written to the rf module and it gets set into receiving
mode.  
+Now the driver is waiting, that a predefined RSSI level (signal strength at the
+receiver) is reached. Until this hasn't happened, the reception can be
+interrupted by the transmission thread at any time to insert a transmission
cycle.
+As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar
+as described for the transmission cycle the read out of the hardware fifo is
done
+dynamically. Upon each hardware fifo threshold interrupt, a portion of data
gets
+read. So also for reception it is possible to receive more data then the
hardware
+fifo can hold.
+
+
+Driver API
+==========
+
+The driver is currently implemented as a character device. Therefore it
supports
+the calls open, ioctl, read, write and close.
+
+
+params for ioctl
+----------------
+
+There are four options:  
+PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver
+PI433_IOC_WR_TX_CFG - set the transmission parameters
+PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver
+PI433_IOC_WR_RX_CFG - set the receiving parameters  
+
+The tx configuration is transfered via struct pi433_tx_cfg, the parameterset
for transmission.  
+It is devided into two sections: rf parameters and packet format.
+
+rf params:
+    frequency
+        frequency used for transmission.  
+        Allowed values: 433050000...434790000
+    bit_rate
+        bit rate used for transmission.  
+        Allowed values: #####
+    dev_frequency
+        frequency deviation in case of FSK.  
+        Allowed values: 600...500000
+    modulation
+        FSK - frequency shift key
+        OOK - On-Off-key
+    modShaping
+        shapingOff    - no shaping
+        shaping1_0    - gauss filter with BT 1 (FSK only)
+        shaping0_5    - gauss filter with BT 0.5 (FSK only)
+        shaping0_3    - gauss filter with BT 0.3 (FSK only)
+        shapingBR    - filter cut off at BR (OOK only)
+        shaping2BR    - filter cut off at 2*BR (OOK only)
+    paRamp (FSK only)
+        ramp3400    - amp ramps up in 3.4ms
+        ramp2000    - amp ramps up in 2.0ms
+        ramp1000    - amp ramps up in 1ms
+        ramp500        - amp ramps up in 500us
+        ramp250        - amp ramps up in 250us
+        ramp125        - amp ramps up in 125us
+        ramp100        - amp ramps up in 100us
+        ramp62        - amp ramps up in 62us
+        ramp50        - amp ramps up in 50us
+        ramp40        - amp ramps up in 40us
+        ramp31        - amp ramps up in 31us
+        ramp25        - amp ramps up in 25us
+        ramp20        - amp ramps up in 20us
+        ramp15        - amp ramps up in 15us
+        ramp12        - amp ramps up in 12us
+        ramp10        - amp ramps up in 10us
+    tx_start_condition
+        fifoLevel    - transmission starts, if fifo is filled to
+                  threshold level
+        fifoNotEmpty    - transmission starts, as soon as there is one
+                  byte in internal fifo
+    repetitions
+        This gives the option, to send a telegram multiple times. Default: 1
+
+packet format:
+    enable_preamble
+        optionOn    - a preamble will be automatically generated
+        optionOff    - no preamble will be generated
+    enable_sync
+        optionOn    - a sync word will be automatically added to
+                  the telegram after preamble
+        optionOff    - no sync word will be added
+        Attention: While possible to generate sync without preamble, the
+        receiver won't be able to detect the sync without preamble.
+    enable_length_byte
+        optionOn    - the length of the telegram will be automatically
+                  added to the telegram. It's part of the payload
+        optionOff    - no length information will be automatically added
+                  to the telegram.
+        Attention: For telegram length over 255 bytes, this option can't be
used
+        Attention: should be used in combination with sync, only
+    enable_address_byte
+        optionOn    - the address byte will be automatically added to the
+                  telgram. It's part of the payload
+        optionOff    - the address byte will not be added to the telegram.
+        The address byte can be used for address filtering, so the receiver
+        will only receive telegrams with a given address byte.
+        Attention: should be used in combination with sync, only
+    enable_crc
+        optionOn    - an crc will be automatically calculated over the
+                  payload of the telegram and added to the telegram
+                  after payload.
+        optionOff    - no crc will be calculated        
+    preamble_length
+        length of the preamble. Allowed values: 0...65536
+    sync_length
+        length of the sync word. Allowed values: 0...8
+    fixed_message_length
+        length of the payload of the telegram. Will override the length
+        given by the buffer, passed in with the write command. Will be
+        ignored if set to zero.
+    sync_pattern[8]
+        contains up to eight values, that are used as the sync pattern
+        on sync option
+    address_byte
+        one byte, used as address byte on address byte option.
+
+
+The rx configuration is transfered via struct pi433_rx_cfg, the parameterset
for receiving. It is devided into two sections: rf parameters and packet format.
+
+rf params:
+    frequency
+        frequency used for transmission.  
+        Allowed values: 433050000...434790000
+    bit_rate
+        bit rate used for transmission.
+        Allowed values: #####
+    dev_frequency
+        frequency deviation in case of FSK.
+        Allowed values: 600...500000
+    modulation
+        FSK - frequency shift key
+        OOK - on off key
+    rssi_threshold
+        threshold value for the signal strength on the receiver input.
+        If this value is exeeded, a reception cycle starts
+        Allowed values: 0...255
+    thresholdDecrement
+        in order to adapt to different levels of singnal strength, over
+        time the receiver gets more and more sensitive. This value  
+        determs, how fast the sensitivity increases.
+        step_0_5db    - increase in 0,5dB steps
+        step_1_0db    - increase in 1 db steps
+        step_1_5db    - increase in 1,5dB steps
+        step_2_0db    - increase in 2 db steps
+        step_3_0db    - increase in 3 db steps
+        step_4_0db    - increase in 4 db steps
+        step_5_0db    - increase in 5 db steps
+        step_6_0db    - increase in 6 db steps
+    antennaImpedance
+        sets the electrical adoption of the antenna
+        fiftyOhm    - for antennas with an impedance of 50Ohm
+        twohundretOhm    - for antennas with an impedance of 200Ohm
+    lnaGain
+        sets the gain of the low noise amp
+        automatic    - lna gain is determed by an agc
+        max        - lna gain is set to maximum
+        maxMinus6    - lna gain is set to  6db below max
+        maxMinus12    - lna gain is set to 12db below max
+        maxMinus24    - lna gain is set to 24db below max
+        maxMinus36    - lna gain is set to 36db below max
+        maxMinus48    - lna gain is set to 48db below max
+    bw_mantisse
+        sets the bandwidth of the channel filter - part one: mantisse.  
+        mantisse16    - mantisse is set to 16
+        mantisse20    - mantisse is set to 20
+        mantisse24    - mantisse is set to 24
+    bw_exponent
+        sets the bandwidth of the channel filter - part two: exponent.  
+        Allowd values: 0...7
+    dagc;
+        operation mode of the digital automatic gain control
+        normalMode
+        improve
+        improve4LowModulationIndex
+
+ packet format:
+    enable_sync
+        optionOn  - sync detection is enabled. If configured sync pattern
+                isn't found, telegram will be internally discarded  
+        optionOff - sync detection is disabled.
+    enable_length_byte
+        optionOn   - First byte of payload will be used as length byte,  
+                 regardless of the amount of bytes that were requested  
+                 by the read request.
+        optionOff  - Number of bytes to be read will be set according to
+                 amount of bytes that were requested by the read request.
+        Attention: should be used in combination with sync, only
+    enable_address_filtering;
+        filteringOff        - no adress filtering will take place
+        nodeAddress        - all telegrams, not matching the node  
+                      address will be internally discarded
+        nodeOrBroadcastAddress    - all telegrams, neither matching the
+                      node, nor the broadcast address will
+                      be internally discarded
+        Attention: Sync option must be enabled in order to use this feature
+    enable_crc
+        optionOn    - a crc will be calculated over the payload of
+                  the telegram, that was received. If the
+                  calculated crc doesn't match to two bytes,
+                  that follow the payload, the telegram will be
+                  internally discarded.
+        Attention: This option is only operational, if sync on and fixed length
+        or length byte is used
+    sync_length
+        Gives the length of the payload.  
+        Attention: This setting must meet the setting of the transmitter,
+        if sync option is used.
+    fixed_message_length
+        Overrides the telegram length either given by the first byte of
+        payload or by the read request.
+    bytes_to_drop
+        gives the number of bytes, that will be dropped before transfering
+        data to the read buffer
+        This option is only usefull, if all packet helper are switched
+        off and the rf chip is used in raw receiving mode. This may be
+        needed, if a telegram of a third party device should be received,
+        using a protocol not compatible with the packet engine of the rf69
chip.
+    sync_pattern[8]
+        contains up to eight values, that are used as the sync pattern
+        on sync option.
+        This setting must meet the configuration of the transmitting device,
+        if sync option is enabled.
+    node_address
+        one byte, used as node address byte on address byte option.
+    broadcast_address
+        one byte, used as broadcast address byte on address byte option.
+        
+
diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
new file mode 100644
index 0000000..61b4b4e
--- /dev/null
+++ b/drivers/staging/pi433/Kconfig
@@ -0,0 +1,16 @@
+config PI433
+        tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
+        default n
+        ---help---
+          This option allows you to enable support for the radio module Pi433.
+
+          Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi
+          or compatible. It extends the Raspberry Pi with the option, to
+          send and receive data in the 433MHz ISM band - for example to
+          communicate between two systems without using ethernet or bluetooth
+          or for control or read sockets, actors, sensors, widely available
+          for low price.
+
+          For details or the option to buy, please visit
https://pi433.de/en.html
+
+          If in doubt, say N here, but saying yes most probably won't hurt
diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile
new file mode 100644
index 0000000..417f3e4
--- /dev/null
+++ b/drivers/staging/pi433/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PI433) += pi433.o
+
+pi433-objs := pi433_if.o rf69.o
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
new file mode 100644
index 0000000..57edf91
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.c
@@ -0,0 +1,1315 @@
+/*
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+#endif
+
+#include "pi433_if.h"
+#include "rf69.h"
+
+
+#define N_PI433_MINORS            (1U << MINORBITS) /*32*/    /* ... up to 256
*/
+#define MAX_MSG_SIZE            900    /* min: FIFO_SIZE! */
+#define MSG_FIFO_SIZE            65536   /* 65536 = 2^16  */
+#define NUM_DIO                2
+
+static dev_t pi433_dev;
+static DEFINE_IDR(pi433_idr);
+static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+
+static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
+
+/* tx config is instance specific
+    so with each open a new tx config struct is needed */
+/* rx config is device specific
+    so we have just one rx config, ebedded in device struct */
+struct pi433_device {
+    /* device handling related values */
+    dev_t            devt;
+    int            minor;
+    struct device        *dev;
+    struct cdev        *cdev;
+    struct spi_device    *spi;
+    unsigned        users;
+
+    /* irq related values */
+    struct gpio_desc    *gpiod[NUM_DIO];
+    int            irq_num[NUM_DIO];
+    u8            irq_state[NUM_DIO];
+
+    /* tx related values */
+    STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
+    struct mutex        tx_fifo_lock; // TODO: check, whether necessary or
obsolete
+    struct task_struct    *tx_task_struct;
+    wait_queue_head_t    tx_wait_queue;
+    u8            free_in_fifo;
+
+    /* rx related values */
+    struct pi433_rx_cfg    rx_cfg;
+    u8            *rx_buffer;
+    unsigned int        rx_buffer_size;
+    u32            rx_bytes_to_drop;
+    u32            rx_bytes_dropped;
+    unsigned int        rx_position;
+    struct mutex        rx_lock;
+    wait_queue_head_t    rx_wait_queue;
+
+    /* fifo wait queue */
+    struct task_struct    *fifo_task_struct;
+    wait_queue_head_t    fifo_wait_queue;
+
+    /* flags */
+    bool            rx_active;
+    bool            tx_active;
+    bool            interrupt_rx_allowed;
+};
+
+struct pi433_instance {
+    struct pi433_device    *device;
+    struct pi433_tx_cfg    tx_cfg;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* macro for checked access of registers of radio module */
+#define SET_CHECKED(retval) \
+    if (retval < 0) \
+        return retval;
+
+/*-------------------------------------------------------------------------*/
+
+/* GPIO interrupt handlers */
+static irq_handler_t
+DIO0_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct pi433_device *device = dev_id;
+
+    if      (device->irq_state[DIO0] == DIO_PacketSent)
+    {
+        device->free_in_fifo = FIFO_SIZE;
+        printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include
KERN_ facility level
+        wake_up_interruptible(&device->fifo_wait_queue);
+    }
+    else if (device->irq_state[DIO0] == DIO_Rssi_DIO0)
+    {
+        printk("DIO0 irq: RSSI level over threshold\n");
+        wake_up_interruptible(&device->rx_wait_queue);
+    }
+    else if (device->irq_state[DIO0] == DIO_PayloadReady)
+    {
+        printk("DIO0 irq: PayloadReady\n");
+        device->free_in_fifo = 0;
+        wake_up_interruptible(&device->fifo_wait_queue);
+    }
+
+    return (irq_handler_t) IRQ_HANDLED;
+}
+
+static irq_handler_t
+DIO1_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct pi433_device *device = dev_id;
+
+    if      (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1)
+    {
+        device->free_in_fifo = FIFO_SIZE;
+    }
+    else if (device->irq_state[DIO1] == DIO_FifoLevel)
+    {
+        if (device->rx_active)    device->free_in_fifo = FIFO_THRESHOLD - 1;
+        else            device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1;
+    }
+    printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO:
printk() should include KERN_ facility level
+    wake_up_interruptible(&device->fifo_wait_queue);
+
+    return (irq_handler_t) IRQ_HANDLED;
+}
+
+static void *DIO_irq_handler[NUM_DIO] = {
+    DIO0_irq_handler,
+    DIO1_irq_handler
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
+{
+    int payload_length;
+
+    /* receiver config */
+    SET_CHECKED(rf69_set_frequency    (dev->spi, rx_cfg->frequency));
+    SET_CHECKED(rf69_set_bit_rate    (dev->spi, rx_cfg->bit_rate));
+    SET_CHECKED(rf69_set_modulation    (dev->spi, rx_cfg->modulation));
+    SET_CHECKED(rf69_set_antenna_impedance     (dev->spi,
rx_cfg->antenna_impedance));
+    SET_CHECKED(rf69_set_rssi_threshold     (dev->spi,
rx_cfg->rssi_threshold));
+    SET_CHECKED(rf69_set_ook_threshold_dec     (dev->spi,
rx_cfg->thresholdDecrement));
+    SET_CHECKED(rf69_set_bandwidth          (dev->spi, rx_cfg->bw_mantisse,
rx_cfg->bw_exponent));
+    SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse,
rx_cfg->bw_exponent));
+    SET_CHECKED(rf69_set_dagc          (dev->spi, rx_cfg->dagc));
+
+    dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop;
+
+    /* packet config */
+    /* enable */
+    SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync));
+    if (rx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi,
afterSyncInterrupt));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always));
+    }
+    SET_CHECKED(rf69_set_packet_format  (dev->spi,
rx_cfg->enable_length_byte));
+    SET_CHECKED(rf69_set_adressFiltering(dev->spi,
rx_cfg->enable_address_filtering));
+    SET_CHECKED(rf69_set_crc_enable        (dev->spi, rx_cfg->enable_crc));
+
+    /* lengths */
+    SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
+    if (rx_cfg->enable_length_byte == optionOn)
+    {
+        SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff));
+    }
+    else if (rx_cfg->fixed_message_length != 0)
+    {
+        payload_length = rx_cfg->fixed_message_length;
+        if (rx_cfg->enable_length_byte  == optionOn) payload_length++;
+        if (rx_cfg->enable_address_filtering != filteringOff) payload_length++;
+        SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
+    }
+
+    /* values */
+    if (rx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern));
+    }
+    if (rx_cfg->enable_address_filtering != filteringOff)
+    {
+        SET_CHECKED(rf69_set_node_address     (dev->spi,
rx_cfg->node_address));
+        SET_CHECKED(rf69_set_broadcast_address(dev->spi,
rx_cfg->broadcast_address));
+    }
+
+    return 0;
+}
+
+static int
+rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
+{
+    SET_CHECKED(rf69_set_frequency    (dev->spi, tx_cfg->frequency));
+    SET_CHECKED(rf69_set_bit_rate    (dev->spi, tx_cfg->bit_rate));
+    SET_CHECKED(rf69_set_modulation    (dev->spi, tx_cfg->modulation));
+    SET_CHECKED(rf69_set_deviation    (dev->spi, tx_cfg->dev_frequency));
+    SET_CHECKED(rf69_set_pa_ramp    (dev->spi, tx_cfg->pa_ramp));
+    SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping));
+    SET_CHECKED(rf69_set_tx_start_condition(dev->spi,
tx_cfg->tx_start_condition));
+
+    /* packet format enable */
+    if (tx_cfg->enable_preamble == optionOn)
+    {
+        SET_CHECKED(rf69_set_preamble_length(dev->spi,
tx_cfg->preamble_length));
+    }
+    else
+    {
+        SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
+    }
+    SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
+    SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
+    SET_CHECKED(rf69_set_crc_enable      (dev->spi, tx_cfg->enable_crc));
+
+    /* configure sync, if enabled */
+    if (tx_cfg->enable_sync == optionOn)
+    {
+        SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length));
+        SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern));
+    }
+
+    return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pi433_start_rx(struct pi433_device *dev)
+{
+    int retval;
+
+    /* return without action, if no pending read request */
+    if (!dev->rx_active)
+        return 0;
+
+    /* setup for receiving */
+    retval = rf69_set_rx_cfg(dev, &dev->rx_cfg);
+    if (retval) return retval;
+
+    /* setup rssi irq */
+    SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0));
+    dev->irq_state[DIO0] = DIO_Rssi_DIO0;
+    irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+    /* setup fifo level interrupt */
+    SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD));
+    SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel));
+    dev->irq_state[DIO1] = DIO_FifoLevel;
+    irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING);
+
+    /* set module to receiving mode */
+    SET_CHECKED(rf69_set_mode(dev->spi, receive));
+
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int
+pi433_receive(void *data)
+{
+    struct pi433_device *dev = data;
+    struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */
+    int bytes_to_read, bytes_total;
+    int retval;
+
+    dev->interrupt_rx_allowed = false;
+
+    /* wait for any tx to finish */
+    dev_dbg(dev->dev,"rx: going to wait for any tx to finish");
+    retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
+    if(retval) /* wait was interrupted */
+    {
+        dev->interrupt_rx_allowed = true;
+        wake_up_interruptible(&dev->tx_wait_queue);
+        return retval;
+    }
+
+    /* prepare status vars */
+    dev->free_in_fifo = FIFO_SIZE;
+    dev->rx_position = 0;
+    dev->rx_bytes_dropped = 0;
+
+    /* setup radio module to listen for something "in the air" */
+    retval = pi433_start_rx(dev);
+    if (retval)
+        return retval;
+
+    /* now check RSSI, if low wait for getting high (RSSI interrupt) */
+    while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) )
+    {
+        /* allow tx to interrupt us while waiting for high RSSI */
+        dev->interrupt_rx_allowed = true;
+        wake_up_interruptible(&dev->tx_wait_queue);
+
+        /* wait for RSSI level to become high */
+        dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
+        retval = wait_event_interruptible(dev->rx_wait_queue,
+                                      rf69_get_flag(dev->spi,
+
                                                       rssiExceededThreshold));
+        if (retval) goto abort; /* wait was interrupted */
+        dev->interrupt_rx_allowed = false;
+
+        /* cross check for ongoing tx */
+        if (!dev->tx_active) break;
+    }
+
+    /* configure payload ready irq */
+    SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady));
+    dev->irq_state[DIO0] = DIO_PayloadReady;
+    irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+    /* fixed or unlimited length? */
+    if (dev->rx_cfg.fixed_message_length != 0)
+    {
+        if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size)
+        {
+            retval = -1;
+            goto abort;
+        }
+        bytes_total = dev->rx_cfg.fixed_message_length;
+        dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total);
+    }
+    else
+    {
+        bytes_total = dev->rx_buffer_size;
+        dev_dbg(dev->dev, "rx: msg len set to %d as requested by read",
bytes_total);
+    }
+
+    /* length byte enabled? */
+    if (dev->rx_cfg.enable_length_byte == optionOn)
+    {
+        retval = wait_event_interruptible(dev->fifo_wait_queue,
+                          dev->free_in_fifo < FIFO_SIZE);
+        if (retval) goto abort; /* wait was interrupted */
+
+        rf69_read_fifo(spi, (u8 *)&bytes_total, 1);
+        if (bytes_total > dev->rx_buffer_size)
+        {
+            retval = -1;
+            goto abort;
+        }
+        dev->free_in_fifo++;
+        dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte",
bytes_total);
+    }
+
+    /* address byte enabled? */
+    if (dev->rx_cfg.enable_address_filtering != filteringOff)
+    {
+        u8 dummy;
+
+        bytes_total--;
+
+        retval = wait_event_interruptible(dev->fifo_wait_queue,
+                          dev->free_in_fifo < FIFO_SIZE);
+        if (retval) goto abort; /* wait was interrupted */
+
+        rf69_read_fifo(spi, &dummy, 1);
+        dev->free_in_fifo++;
+        dev_dbg(dev->dev, "rx: address byte stripped off");
+    }
+
+    /* get payload */
+    while (dev->rx_position < bytes_total)
+    {
+        if ( !rf69_get_flag(dev->spi, payloadReady) )
+        {
+            retval = wait_event_interruptible(dev->fifo_wait_queue,
+                              dev->free_in_fifo < FIFO_SIZE);
+            if (retval) goto abort; /* wait was interrupted */
+        }
+
+        /* need to drop bytes or acquire? */
+        if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+            bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+        else
+            bytes_to_read = bytes_total - dev->rx_position;
+
+
+        /* access the fifo */
+        if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo)
+            bytes_to_read = FIFO_SIZE - dev->free_in_fifo;
+        retval = rf69_read_fifo(spi,
+                    &dev->rx_buffer[dev->rx_position],
+                    bytes_to_read);
+        if (retval) goto abort; /* read failed */
+        dev->free_in_fifo += bytes_to_read;
+
+        /* adjust status vars */
+        if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+            dev->rx_bytes_dropped += bytes_to_read;
+        else
+            dev->rx_position += bytes_to_read;
+    }
+
+
+    /* rx done, wait was interrupted or error occured */
+abort:
+    dev->interrupt_rx_allowed = true;
+    SET_CHECKED(rf69_set_mode(dev->spi, standby));
+    wake_up_interruptible(&dev->tx_wait_queue);
+
+    if (retval)
+        return retval;
+    else
+        return bytes_total;
+}
+
+int
+pi433_tx_thread(void *data)
+{
+    struct pi433_device *device = data;
+    struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
+    struct pi433_tx_cfg tx_cfg;
+    u8     buffer[MAX_MSG_SIZE];
+    size_t size;
+    bool   rx_interrupted = false;
+    int    position, repetitions;
+    int    retval;
+
+    while (1)
+    {
+        /* wait for fifo to be populated or for request to terminate*/
+        dev_dbg(device->dev, "thread: going to wait for new messages");
+        wait_event_interruptible(device->tx_wait_queue,
+                     ( !kfifo_is_empty(&device->tx_fifo) ||
+                        kthread_should_stop() ));
+        if ( kthread_should_stop() )
+            return 0;
+
+        /* get data from fifo in the following order:
+           - tx_cfg
+           - size of message
+           - message */
+        mutex_lock(&device->tx_fifo_lock);
+
+        retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
+        if (retval != sizeof(tx_cfg))
+        {
+            dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d
byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) );
+            mutex_unlock(&device->tx_fifo_lock);
+            continue;
+        }
+
+        retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
+        if (retval != sizeof(size_t))
+        {
+            dev_dbg(device->dev, "reading msg size from fifo failed: got %d,
expected %d", retval, (unsigned int)sizeof(size_t) );
+            mutex_unlock(&device->tx_fifo_lock);
+            continue;
+        }
+
+        /* use fixed message length, if requested */
+        if (tx_cfg.fixed_message_length != 0)
+            size = tx_cfg.fixed_message_length;
+
+        /* increase size, if len byte is requested */
+        if (tx_cfg.enable_length_byte == optionOn)
+            size++;
+
+        /* increase size, if adr byte is requested */
+        if (tx_cfg.enable_address_byte == optionOn)
+            size++;
+
+        /* prime buffer */
+        memset(buffer, 0, size);
+        position = 0;
+
+        /* add length byte, if requested */
+        if (tx_cfg.enable_length_byte  == optionOn)
+            buffer[position++] = size-1; /* according to spec length byte
itself must be excluded from the length calculation */
+
+        /* add adr byte, if requested */
+        if (tx_cfg.enable_address_byte == optionOn)
+            buffer[position++] = tx_cfg.address_byte;
+
+        /* finally get message data from fifo */
+        retval = kfifo_out(&device->tx_fifo, &buffer[position],
sizeof(buffer)-position );
+        dev_dbg(device->dev, "read %d message byte(s) from fifo queue.",
retval);
+        mutex_unlock(&device->tx_fifo_lock);
+
+        /* if rx is active, we need to interrupt the waiting for
+           incoming telegrams, to be able to send something.
+           We are only allowed, if currently no reception takes
+           place otherwise we need to  wait for the incoming telegram
+           to finish */
+        wait_event_interruptible(device->tx_wait_queue,
+                     !device->rx_active ||
+                      device->interrupt_rx_allowed == true);
+
+        /* prevent race conditions
+           irq will be reenabled after tx config is set */
+        disable_irq(device->irq_num[DIO0]);
+        device->tx_active = true;
+
+        if (device->rx_active && rx_interrupted == false)
+        {
+            /* rx is currently waiting for a telegram;
+               we need to set the radio module to standby */
+            SET_CHECKED(rf69_set_mode(device->spi, standby));
+            rx_interrupted = true;
+        }
+
+        /* clear fifo, set fifo threshold, set payload length */
+        SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */
+        SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD));
+        if (tx_cfg.enable_length_byte == optionOn)
+        {
+            SET_CHECKED(rf69_set_payload_length(spi, size *
tx_cfg.repetitions));
+        }
+        else
+        {
+            SET_CHECKED(rf69_set_payload_length(spi, 0));
+        }
+
+        /* configure the rf chip */
+        rf69_set_tx_cfg(device, &tx_cfg);
+
+        /* enable fifo level interrupt */
+        SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel));
+        device->irq_state[DIO1] = DIO_FifoLevel;
+        irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING);
+
+        /* enable packet sent interrupt */
+        SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent));
+        device->irq_state[DIO0] = DIO_PacketSent;
+        irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+        enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check
*/
+
+        /* enable transmission */
+        SET_CHECKED(rf69_set_mode(spi, transmit));
+
+        /* transfer this msg (and repetitions) to chip fifo */
+        device->free_in_fifo = FIFO_SIZE;
+        position = 0;
+        repetitions = tx_cfg.repetitions;
+        while( (repetitions > 0) && (size > position) )
+        {
+            if ( (size - position) > device->free_in_fifo)
+            {    /* msg to big for fifo - take a part */
+                int temp = device->free_in_fifo;
+                device->free_in_fifo = 0;
+                rf69_write_fifo(spi,
+                                &buffer[position],
+                                temp);
+                position +=temp;
+            }
+            else
+            {    /* msg fits into fifo - take all */
+                device->free_in_fifo -= size;
+                repetitions--;
+                rf69_write_fifo(spi,
+                        &buffer[position],
+                        (size - position) );
+                position = 0; /* reset for next repetition */
+            }
+
+            retval = wait_event_interruptible(device->fifo_wait_queue,
+                              device->free_in_fifo > 0);
+            if (retval) { printk("ABORT\n"); goto abort; }
+        }
+
+        /* we are done. Wait for packet to get sent */
+        dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be
empty");
+        wait_event_interruptible(device->fifo_wait_queue,
+                     device->free_in_fifo == FIFO_SIZE ||
+                     kthread_should_stop() );
+        if ( kthread_should_stop() )    printk("ABORT\n");
+
+
+        /* STOP_TRANSMISSION */
+        dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.");
+        SET_CHECKED(rf69_set_mode(spi, standby));
+
+        /* everything sent? */
+        if ( kfifo_is_empty(&device->tx_fifo) )
+        {
+abort:
+            if (rx_interrupted)
+            {
+                rx_interrupted = false;
+                pi433_start_rx(device);
+            }
+            device->tx_active = false;
+            wake_up_interruptible(&device->rx_wait_queue);
+        }
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t
+pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    unsigned int        bytes_received;
+    ssize_t            retval;
+
+    /* check, whether internal buffer is big enough for requested size */
+    if (size > MAX_MSG_SIZE)
+        return -EMSGSIZE;
+
+    instance = filp->private_data;
+    device = instance->device;
+
+    /* just one read request at a time */
+    mutex_lock(&device->rx_lock);
+    if (device->rx_active)
+    {
+        mutex_unlock(&device->rx_lock);
+        return -EAGAIN;
+    }
+    else
+    {
+        device->rx_active = true;
+        mutex_unlock(&device->rx_lock);
+    }
+
+    /* start receiving */
+    /* will block until something was received*/
+    device->rx_buffer_size = size;
+    bytes_received = pi433_receive(device);
+
+    /* release rx */
+    mutex_lock(&device->rx_lock);
+    device->rx_active = false;
+    mutex_unlock(&device->rx_lock);
+
+    /* if read was successful copy to user space*/
+    if (bytes_received >= 0)
+    {
+        retval = copy_to_user(buf, device->rx_buffer, bytes_received);
+        if (retval)
+            return retval;
+    }
+
+    return bytes_received;
+}
+
+
+static ssize_t
+pi433_write(struct file *filp, const char __user *buf,
+        size_t count, loff_t *f_pos)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    int                     copied, retval;
+
+    instance = filp->private_data;
+    device = instance->device;
+
+    /* check, whether internal buffer (tx thread) is big enough for requested
size */
+    if (count > MAX_MSG_SIZE)
+        return -EMSGSIZE;
+
+    /* write the following sequence into fifo:
+       - tx_cfg
+       - size of message
+       - message */
+    mutex_lock(&device->tx_fifo_lock);
+    retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg,
sizeof(instance->tx_cfg));
+    if ( retval != sizeof(instance->tx_cfg) )
+        goto abort;
+
+    retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t));
+    if ( retval != sizeof(size_t) )
+        goto abort;
+
+    retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied);
+    if (retval || copied != count)
+        goto abort;
+
+    mutex_unlock(&device->tx_fifo_lock);
+
+    /* start transfer */
+    wake_up_interruptible(&device->tx_wait_queue);
+    dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied);
+
+    return 0;
+
+abort:
+    dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
+    kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to
discard already stored, valid entries
+    mutex_unlock(&device->tx_fifo_lock);
+    return -EAGAIN;
+}
+
+
+static long
+pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    int            err = 0;
+    int            retval = 0;
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+    u32            tmp;
+
+    /* Check type and command number */
+    if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
+        return -ENOTTY;
+
+    /* Check access direction once here; don't repeat below.
+     * IOC_DIR is from the user perspective, while access_ok is
+     * from the kernel perspective; so they look reversed.
+     */
+    if (_IOC_DIR(cmd) & _IOC_READ)
+        err = !access_ok(VERIFY_WRITE,
+                 (void __user *)arg,
+                 _IOC_SIZE(cmd));
+
+    if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+        err = !access_ok(VERIFY_READ,
+                 (void __user *)arg,
+                 _IOC_SIZE(cmd));
+    if (err)
+        return -EFAULT;
+
+    /* TODO? guard against device removal before, or while,
+     * we issue this ioctl. --> device_get()
+     */
+    instance = filp->private_data;
+    device = instance->device;
+
+    if (device == NULL)
+        return -ESHUTDOWN;
+
+    switch (cmd) {
+    case PI433_IOC_RD_TX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_to_user((void __user *)arg,
+                    &instance->tx_cfg,
+                    tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+    case PI433_IOC_WR_TX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+        {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_from_user(&instance->tx_cfg,
+                     (void __user *)arg,
+                     tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+
+    case PI433_IOC_RD_RX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+            retval = -EINVAL;
+            break;
+        }
+
+        if (__copy_to_user((void __user *)arg,
+                   &device->rx_cfg,
+                   tmp))
+        {
+            retval = -EFAULT;
+            break;
+        }
+
+        break;
+    case PI433_IOC_WR_RX_CFG:
+        tmp = _IOC_SIZE(cmd);
+        mutex_lock(&device->rx_lock);
+
+        /* during pendig read request, change of config not allowed */
+        if (device->rx_active) {
+            retval = -EAGAIN;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+            retval = -EINVAL;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        if (__copy_from_user(&device->rx_cfg,
+                     (void __user *)arg,
+                     tmp))
+        {
+            retval = -EFAULT;
+            mutex_unlock(&device->rx_lock);
+            break;
+        }
+
+        mutex_unlock(&device->rx_lock);
+        break;
+    default:
+        retval = -EINVAL;
+    }
+
+    return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define pi433_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_open(struct inode *inode, struct file *filp)
+{
+    struct pi433_device    *device;
+    struct pi433_instance    *instance;
+
+    mutex_lock(&minor_lock);
+    device = idr_find(&pi433_idr, iminor(inode));
+
+    mutex_unlock(&minor_lock);
+    if (!device) {
+        dev_dbg(device->dev, "device: minor %d unknown.\n", iminor(inode));
+        return -ENODEV;
+    }
+
+    if (!device->rx_buffer) {
+        device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL);
+        if (!device->rx_buffer)
+        {
+            dev_dbg(device->dev, "open/ENOMEM\n");
+            return -ENOMEM;
+        }
+    }
+
+    device->users++;
+    instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+    if (!instance)
+    {
+        kfree(device->rx_buffer);
+        device->rx_buffer = NULL;
+        return -ENOMEM;
+    }
+
+    /* setup instance data*/
+    instance->device = device;
+    instance->tx_cfg.bit_rate = 4711;
+    // TODO: fill instance->tx_cfg;
+
+    /* instance data as context */
+    filp->private_data = instance;
+    nonseekable_open(inode, filp);
+
+    return 0;
+}
+
+static int pi433_release(struct inode *inode, struct file *filp)
+{
+    struct pi433_instance    *instance;
+    struct pi433_device    *device;
+
+    instance = filp->private_data;
+    device = instance->device;
+    kfree(instance);
+    filp->private_data = NULL;
+
+    /* last close? */
+    device->users--;
+
+    if (!device->users) {
+        kfree(device->rx_buffer);
+        device->rx_buffer = NULL;
+        if (device->spi == NULL)
+            kfree(device);
+    }
+
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int setup_GPIOs(struct pi433_device *device)
+{
+    char     name[5];
+    int    retval;
+    int    i;
+
+    for (i=0; i<NUM_DIO; i++)
+    {
+        /* "construct" name and get the gpio descriptor */
+        snprintf(name, sizeof(name), "DIO%d", i);
+        device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+
+        if (device->gpiod[i] == ERR_PTR(-ENOENT))
+        {
+            dev_dbg(&device->spi->dev, "Could not find entry for %s.
Ignoring.", name);
+            continue;
+        }
+
+        if (device->gpiod[i] == ERR_PTR(-EBUSY))
+            dev_dbg(&device->spi->dev, "%s is busy.", name);
+
+        if ( IS_ERR(device->gpiod[i]) )
+        {
+            retval = PTR_ERR(device->gpiod[i]);
+            /* release already allocated gpios */
+            for (i--; i>=0; i--)
+            {
+                free_irq(device->irq_num[i], device);
+                gpiod_put(device->gpiod[i]);
+            }
+            return retval;
+        }
+
+
+        /* configure the pin */
+        gpiod_unexport(device->gpiod[i]);
+        retval = gpiod_direction_input(device->gpiod[i]);
+        if (retval) return retval;
+
+
+        /* configure irq */
+        device->irq_num[i] = gpiod_to_irq(device->gpiod[i]);
+        if (device->irq_num[i] < 0)
+        {
+            device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc
*)device->irq_num[i];
+            return device->irq_num[i];
+        }
+        retval = request_irq(device->irq_num[i],
+                     DIO_irq_handler[i],
+                     0, /* flags */
+                     name,
+                     device);
+
+        if (retval)
+            return retval;
+
+        dev_dbg(&device->spi->dev, "%s succesfully configured", name);
+    }
+
+    return 0;
+}
+
+static void free_GPIOs(struct pi433_device *device)
+{
+    int i;
+
+    for (i=0; i<NUM_DIO; i++)
+    {
+        /* check if gpiod is valid */
+        if ( IS_ERR(device->gpiod[i]) )
+            continue;
+
+        free_irq(device->irq_num[i], device);
+        gpiod_put(device->gpiod[i]);
+    }
+    return;
+}
+
+static int pi433_get_minor(struct pi433_device *device)
+{
+    int retval = -ENOMEM;
+
+    mutex_lock(&minor_lock);
+    retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL);
+    if (retval >= 0) {
+        device->minor = retval;
+        retval = 0;
+    } else if (retval == -ENOSPC) {
+        dev_err(device->dev, "too many pi433 devices\n");
+        retval = -EINVAL;
+    }
+    mutex_unlock(&minor_lock);
+    return retval;
+}
+
+static void pi433_free_minor(struct pi433_device *dev)
+{
+    mutex_lock(&minor_lock);
+    idr_remove(&pi433_idr, dev->minor);
+    mutex_unlock(&minor_lock);
+}
+/*-------------------------------------------------------------------------*/
+
+static const struct file_operations pi433_fops = {
+    .owner =    THIS_MODULE,
+    /* REVISIT switch to aio primitives, so that userspace
+     * gets more complete API coverage.  It'll simplify things
+     * too, except for the locking.
+     */
+    .write =    pi433_write,
+    .read =        pi433_read,
+    .unlocked_ioctl = pi433_ioctl,
+    .compat_ioctl = pi433_compat_ioctl,
+    .open =        pi433_open,
+    .release =    pi433_release,
+    .llseek =    no_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_probe(struct spi_device *spi)
+{
+    struct pi433_device    *device;
+    int            retval;
+
+    /* setup spi parameters */
+    spi->mode = 0x00;
+    spi->bits_per_word = 8;
+    /* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay
*/
+
+    retval = spi_setup(spi);
+    if (retval)
+    {
+        dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
+        return retval;
+    }
+    else
+    {
+        dev_dbg(&spi->dev,
+            "spi interface setup: mode 0x%2x, %d bits per word, %dhz max
speed",
+            spi->mode, spi->bits_per_word, spi->max_speed_hz);
+    }
+
+    /* Ping the chip by reading the version register */
+    retval = spi_w8r8(spi, 0x10);
+    if (retval < 0)
+        return retval;
+
+    switch(retval)
+    {
+        case 0x24:
+            dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
+            break;
+        default:
+            dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
+            return -ENODEV;
+    }
+
+    /* Allocate driver data */
+    device = kzalloc(sizeof(*device), GFP_KERNEL);
+    if (!device)
+        return -ENOMEM;
+
+    /* Initialize the driver data */
+    device->spi = spi;
+    device->rx_active = false;
+    device->tx_active = false;
+    device->interrupt_rx_allowed = false;
+
+    /* init wait queues */
+    init_waitqueue_head(&device->tx_wait_queue);
+    init_waitqueue_head(&device->rx_wait_queue);
+    init_waitqueue_head(&device->fifo_wait_queue);
+
+    /* init fifo */
+    INIT_KFIFO(device->tx_fifo);
+
+    /* init mutexes and locks */
+    mutex_init(&device->tx_fifo_lock);
+    mutex_init(&device->rx_lock);
+
+    /* setup GPIO (including irq_handler) for the different DIOs */
+    retval = setup_GPIOs(device);
+    if (retval)
+    {
+        dev_dbg(&spi->dev, "setup of GPIOs failed");
+        goto GPIO_failed;
+    }
+
+    /* setup the radio module */
+    SET_CHECKED(rf69_set_mode        (spi, standby));
+    SET_CHECKED(rf69_set_data_mode        (spi, packet));
+    SET_CHECKED(rf69_set_amplifier_0    (spi, optionOn));
+    SET_CHECKED(rf69_set_amplifier_1    (spi, optionOff));
+    SET_CHECKED(rf69_set_amplifier_2    (spi, optionOff));
+    SET_CHECKED(rf69_set_output_power_level    (spi, 13));
+    SET_CHECKED(rf69_set_antenna_impedance    (spi, fiftyOhm));
+
+    /* start tx thread */
+    device->tx_task_struct = kthread_run(pi433_tx_thread,
+                         device,
+                         "pi433_tx_task");
+    if (device->tx_task_struct < 0)
+    {
+        dev_dbg(device->dev, "start of send thread failed");
+        goto send_thread_failed;
+    }
+
+    /* determ minor number */
+    retval = pi433_get_minor(device);
+    if (retval)
+    {
+        dev_dbg(device->dev, "get of minor number failed");
+        goto minor_failed;
+    }
+
+    /* create device */
+    device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
+    device->dev = device_create(pi433_class,
+                    &spi->dev,
+                    device->devt,
+                    device,
+                    "pi433");
+    if (IS_ERR(device->dev)) {
+        pr_err("pi433: device register failed\n");
+        retval = PTR_ERR(device->dev);
+        goto device_create_failed;
+    }
+    else {
+        dev_dbg(device->dev,
+            "created device for major %d, minor %d\n",
+            MAJOR(pi433_dev),
+            device->minor);
+    }
+
+    /* create cdev */
+    device->cdev = cdev_alloc();
+    device->cdev->owner = THIS_MODULE;
+    cdev_init(device->cdev, &pi433_fops);
+    retval = cdev_add(device->cdev, device->devt, 1);
+    if (retval)
+    {
+        dev_dbg(device->dev, "register of cdev failed");
+        goto cdev_failed;
+    }
+
+    /* spi setup */
+    spi_set_drvdata(spi, device);
+
+    return 0;
+
+cdev_failed:
+    device_destroy(pi433_class, device->devt);
+device_create_failed:
+    pi433_free_minor(device);
+minor_failed:
+    kthread_stop(device->tx_task_struct);
+send_thread_failed:
+    free_GPIOs(device);
+GPIO_failed:
+    kfree(device);
+
+    return retval;
+}
+
+static int pi433_remove(struct spi_device *spi)
+{
+    struct pi433_device    *device = spi_get_drvdata(spi);
+
+    /* free GPIOs */
+    free_GPIOs(device);
+
+    /* make sure ops on existing fds can abort cleanly */
+    device->spi = NULL;
+
+    kthread_stop(device->tx_task_struct);
+
+    device_destroy(pi433_class, device->devt);
+
+    cdev_del(device->cdev);
+
+    pi433_free_minor(device);
+
+    if (device->users == 0)
+        kfree(device);
+
+    return 0;
+}
+
+static const struct of_device_id pi433_dt_ids[] = {
+    { .compatible = "Smarthome-Wolf,pi433" },
+    {},
+};
+
+MODULE_DEVICE_TABLE(of, pi433_dt_ids);
+
+static struct spi_driver pi433_spi_driver = {
+    .driver = {
+        .name =        "pi433",
+        .owner =    THIS_MODULE,
+        .of_match_table = of_match_ptr(pi433_dt_ids),
+    },
+    .probe =    pi433_probe,
+    .remove =    pi433_remove,
+
+    /* NOTE:  suspend/resume methods are not necessary here.
+     * We don't do anything except pass the requests to/from
+     * the underlying controller.  The refrigerator handles
+     * most issues; the controller driver handles the rest.
+     */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init pi433_init(void)
+{
+    int status;
+
+    /* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't
+           work stable - risk of buffer overflow */
+    if (MAX_MSG_SIZE < FIFO_SIZE)
+        return -EINVAL;
+
+    /* Claim device numbers.  Then register a class
+     * that will key udev/mdev to add/remove /dev nodes.  Last, register
+     * Last, register the driver which manages those device numbers.
+     */
+    status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS
/*count*/, "pi433" /*name*/);
+    if (status < 0)
+        return status;
+
+    pi433_class = class_create(THIS_MODULE, "pi433");
+    if (IS_ERR(pi433_class))
+    {
+        unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+        return PTR_ERR(pi433_class);
+    }
+
+    status = spi_register_driver(&pi433_spi_driver);
+    if (status < 0)
+    {
+        class_destroy(pi433_class);
+        unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+    }
+
+    return status;
+}
+
+module_init(pi433_init);
+
+static void __exit pi433_exit(void)
+{
+    spi_unregister_driver(&pi433_spi_driver);
+    class_destroy(pi433_class);
+    unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+}
+module_exit(pi433_exit);
+
+MODULE_AUTHOR("Marcus Wolf, <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>");
+MODULE_DESCRIPTION("Driver for Pi433");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:pi433");
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
new file mode 100644
index 0000000..e6ed3cd
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.h
@@ -0,0 +1,152 @@
+/*
+ * include/linux/TODO
+ *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR     0
+struct pi433_tx_cfg
+{
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+    enum modulation        modulation;
+    enum modShaping        modShaping;
+
+    enum paRamp        pa_ramp;
+
+    enum txStartCondition    tx_start_condition;
+
+    __u16            repetitions;
+
+
+    /* packet format */
+    enum optionOnOff    enable_preamble;
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;
+    enum optionOnOff    enable_address_byte;
+    enum optionOnOff    enable_crc;
+
+    __u16            preamble_length;
+    __u8            sync_length;
+    __u8            fixed_message_length;
+
+    __u8            sync_pattern[8];
+    __u8            address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for
sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR     1
+struct pi433_rx_cfg {
+    __u32            frequency;
+    __u16            bit_rate;
+    __u32            dev_frequency;
+
+    enum modulation        modulation;
+
+    __u8            rssi_threshold;
+    enum thresholdDecrement    thresholdDecrement;
+    enum antennaImpedance    antenna_impedance;
+    enum lnaGain        lna_gain;
+    enum mantisse        bw_mantisse;    /* normal: 0x50 */
+    __u8            bw_exponent;    /* during AFC: 0x8b */
+    enum dagc        dagc;
+
+
+
+    /* packet format */
+    enum optionOnOff    enable_sync;
+    enum optionOnOff    enable_length_byte;      /* should be used in
combination with sync, only */
+    enum addressFiltering    enable_address_filtering; /* operational with
sync, only */
+    enum optionOnOff    enable_crc;          /* only operational, if sync on
and fixed length or length byte is used */
+
+    __u8            sync_length;
+    __u8            fixed_message_length;
+    __u32            bytes_to_drop;
+
+    __u8            sync_pattern[8];
+    __u8            node_address;
+    __u8            broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC            'r'
+
+#define PI433_IOC_RD_TX_CFG    _IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG    _IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR,
char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG    _IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG    _IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR,
char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
new file mode 100644
index 0000000..b6bc45b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.c
@@ -0,0 +1,982 @@
+/*
+ * abstraction of the spi interface of HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* enable prosa debug info */
+#undef DEBUG
+/* enable print of values on reg access */
+#undef DEBUG_VALUES
+/* enable print of values on fifo access */
+#undef DEBUG_FIFO_ACCESS
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include "rf69.h"
+#include "rf69_registers.h"
+
+#define F_OSC      32000000 /* in Hz */
+#define FIFO_SIZE 66        /* in byte */
+
+/*-------------------------------------------------------------------------*/
+
+#define READ_REG(x)    rf69_read_reg (spi, x)
+#define WRITE_REG(x,y)    rf69_write_reg(spi, x, y)
+#define INVALID_PARAM \
+    { \
+        dev_dbg(&spi->dev, "set: illegal input param"); \
+        return -EINVAL; \
+    }
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: mode");
+    #endif
+
+    switch (mode){
+    case transmit:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT);
+    case receive:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE);
+    case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER);
+    case standby:      return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY);
+    case mode_sleep:  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) &
~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP);
+    default:      INVALID_PARAM;
+    }
+
+    // we are using packet mode, so this check is not really needed
+    // but waiting for mode ready is necessary when going from sleep because
the FIFO may not be immediately available from previous mode
+    //while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) &
RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
+
+}
+
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: data mode");
+    #endif
+
+    switch (dataMode) {
+    case packet:        return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET);
+    case continuous:    return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS);
+    case continuousNoSync:  return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) |
DATAMODUL_MODE_CONTINUOUS_NOSYNC);
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: modulation");
+    #endif
+
+    switch (modulation) {
+    case OOK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) &
~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK);
+    case FSK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) &
~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK);
+    default:    INVALID_PARAM;
+    }
+}
+
+enum modulation rf69_get_modulation(struct spi_device *spi)
+{
+    u8 currentValue;    
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: mode");
+    #endif
+
+    currentValue = READ_REG(REG_DATAMODUL);
+
+    switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3)  // TODO
improvement: change 3 to define
+    {
+    case DATAMODUL_MODULATION_TYPE_OOK: return OOK;
+    case DATAMODUL_MODULATION_TYPE_FSK: return FSK;
+    default:                return undefined;
+    }
+}
+
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping
modShaping)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: mod shaping");
+    #endif
+
+    if (rf69_get_modulation(spi) == FSK)
+    {
+        switch (modShaping) {
+        case shapingOff: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_NONE);
+        case shaping1_0: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_1_0);
+        case shaping0_5: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_0_3);
+        case shaping0_3: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_0_5);
+        default:     INVALID_PARAM;
+        }
+    }
+    else
+    {
+        switch (modShaping) {
+        case shapingOff: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_NONE);
+        case shapingBR:     return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_BR);
+        case shaping2BR: return WRITE_REG(REG_DATAMODUL,
(READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) |
DATAMODUL_MODULATION_SHAPE_2BR);
+        default:     INVALID_PARAM;
+        }
+    }
+}
+
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+{
+    int retval;
+    u32 bitRate_min;
+    u32 bitRate_reg;
+    u8 msb;
+    u8 lsb;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: bit rate");
+    #endif
+
+    // check input value
+    bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
+    if (bitRate < bitRate_min)
+    {
+        dev_dbg(&spi->dev, "setBitRate: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculate reg settings
+    bitRate_reg = (F_OSC / bitRate);
+
+    msb = (bitRate_reg&0xff00)   >>  8;
+    lsb = (bitRate_reg&0xff);
+
+    // transmit to RF 69
+    retval = WRITE_REG(REG_BITRATE_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_BITRATE_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_deviation(struct spi_device *spi, u32 deviation)
+{
+    int retval;
+//    u32 f_max; TODO: Abhängigkeit von Bitrate beachten!!
+    u64 f_reg;
+    u64 f_step;
+    u8 msb;
+    u8 lsb;
+    u64 factor = 1000000; // to improve precision of calculation
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: deviation");
+    #endif
+
+    if (deviation < 600 || deviation > 500000) //TODO: Abhängigkeit von Bitrate
beachten!!
+    {
+        dev_dbg(&spi->dev, "set_deviation: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculat f step
+    f_step = F_OSC * factor;
+    do_div(f_step, 524288); //  524288 = 2^19
+
+    // calculate register settings
+    f_reg = deviation * factor;
+    do_div(f_reg  , f_step);
+
+    msb = (f_reg&0xff00)   >>  8;
+    lsb = (f_reg&0xff);
+
+    // check msb
+    if (msb & !FDEVMASB_MASK)
+    {
+        dev_dbg(&spi->dev, "set_deviation: err in calc of msb");
+        INVALID_PARAM;
+    }
+
+    // write to chip
+    retval = WRITE_REG(REG_FDEV_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FDEV_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_frequency(struct spi_device *spi, u32 frequency)
+{
+    int retval;
+    u32 f_max;
+    u64 f_reg;
+    u64 f_step;
+    u8 msb;
+    u8 mid;
+    u8 lsb;
+    u64 factor = 1000000; // to improve precision of calculation
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: frequency");
+    #endif
+
+    // calculat f step
+    f_step = F_OSC * factor;
+    do_div(f_step, 524288); //  524288 = 2^19
+
+    // check input value
+    f_max = f_step * 8388608 / factor;
+    if (frequency > f_max)
+    {
+        dev_dbg(&spi->dev, "setFrequency: illegal input param");
+        INVALID_PARAM;
+    }
+
+    // calculate reg settings
+    f_reg = frequency * factor;
+    do_div(f_reg  , f_step);
+
+    msb = (f_reg&0xff0000) >> 16;
+    mid = (f_reg&0xff00)   >>  8;
+    lsb = (f_reg&0xff);
+
+    // write to chip
+    retval = WRITE_REG(REG_FRF_MSB, msb);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FRF_MID, mid);
+    if (retval)  return retval;
+    retval = WRITE_REG(REG_FRF_LSB, lsb);
+    if (retval)  return retval;
+
+    return 0;
+}
+
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #0");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA0) );
+    case optionOff:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA0) );
+    default:    INVALID_PARAM;
+    }
+}    
+
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #1");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA1) );
+    case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA1) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: amp #2");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |
 MASK_PALEVEL_PA2) );
+    case optionOff:    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_PA2) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: power level");
+    #endif
+
+    powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting
+
+    // check input value
+    if (powerLevel > 0x1f)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) &
~MASK_PALEVEL_OUTPUT_POWER) | powerLevel);
+}
+
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: pa ramp");
+    #endif
+
+    switch(paRamp) {
+    case ramp3400:    return WRITE_REG(REG_PARAMP, PARAMP_3400);
+    case ramp2000:    return WRITE_REG(REG_PARAMP, PARAMP_2000);
+    case ramp1000:    return WRITE_REG(REG_PARAMP, PARAMP_1000);
+    case ramp500:    return WRITE_REG(REG_PARAMP, PARAMP_500);
+    case ramp250:    return WRITE_REG(REG_PARAMP, PARAMP_250);
+    case ramp125:    return WRITE_REG(REG_PARAMP, PARAMP_125);
+    case ramp100:    return WRITE_REG(REG_PARAMP, PARAMP_100);
+    case ramp62:    return WRITE_REG(REG_PARAMP, PARAMP_62);
+    case ramp50:    return WRITE_REG(REG_PARAMP, PARAMP_50);
+    case ramp40:    return WRITE_REG(REG_PARAMP, PARAMP_40);
+    case ramp31:    return WRITE_REG(REG_PARAMP, PARAMP_31);
+    case ramp25:    return WRITE_REG(REG_PARAMP, PARAMP_25);
+    case ramp20:    return WRITE_REG(REG_PARAMP, PARAMP_20);
+    case ramp15:    return WRITE_REG(REG_PARAMP, PARAMP_15);
+    case ramp12:    return WRITE_REG(REG_PARAMP, PARAMP_12);
+    case ramp10:    return WRITE_REG(REG_PARAMP, PARAMP_10);
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance
antennaImpedance)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: antenna impedance");
+    #endif
+
+    switch(antennaImpedance) {
+    case fiftyOhm:        return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) &
~MASK_LNA_ZIN) );
+    case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) |
 MASK_LNA_ZIN) );
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: lna gain");
+    #endif
+
+    switch(lnaGain) {
+    case automatic:     return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_AUTO) );
+    case max:     return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX) );
+    case maxMinus6:  return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) );
+    case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) );
+    case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) );
+    case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) );
+    case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) &
~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) );
+    default:     INVALID_PARAM;
+    }
+}
+
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi)
+{
+    u8 currentValue;    
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: lna gain");
+    #endif
+
+    currentValue = READ_REG(REG_LNA);
+
+    switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3)  // improvement: change
3 to define
+    {
+    case LNA_GAIN_AUTO:        return automatic;
+    case LNA_GAIN_MAX:        return max;
+    case LNA_GAIN_MAX_MINUS_6:  return maxMinus6;
+    case LNA_GAIN_MAX_MINUS_12: return maxMinus12;
+    case LNA_GAIN_MAX_MINUS_24: return maxMinus24;
+    case LNA_GAIN_MAX_MINUS_36: return maxMinus36;
+    case LNA_GAIN_MAX_MINUS_48: return maxMinus48;
+    default:            return undefined;
+    }
+}
+
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum
dccPercent dccPercent)
+{
+    switch (dccPercent) {
+    case dcc16Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) );
+    case dcc8Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) );
+    case dcc4Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) );
+    case dcc2Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) );
+    case dcc1Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) );
+    case dcc0_5Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) );
+    case dcc0_25Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) );
+    case dcc0_125Percent:    return WRITE_REG(reg, ( (READ_REG(reg) &
~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) );
+    default:        INVALID_PARAM;
+    }
+}
+
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent
dccPercent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: cut off freq");
+    #endif
+
+    return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent);
+}
+
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum
dccPercent dccPercent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: cut off freq during afc");
+    #endif
+
+    return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent);
+}
+
+int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse
mantisse, u8 exponent)
+{
+    u8 newValue;
+
+    // check value for mantisse and exponent
+    if (exponent > 7)   INVALID_PARAM;
+    if ( (mantisse!=mantisse16) &&
+         (mantisse!=mantisse20) &&
+             (mantisse!=mantisse24) ) INVALID_PARAM;
+
+    // read old value
+    newValue = READ_REG(reg);
+
+    // "delete" mantisse and exponent = just keep the DCC setting
+    newValue = newValue & MASK_BW_DCC_FREQ;
+
+    // add new mantisse
+    switch(mantisse) {
+    case mantisse16: newValue = newValue | BW_MANT_16;    break;
+    case mantisse20: newValue = newValue | BW_MANT_20;    break;
+    case mantisse24: newValue = newValue | BW_MANT_24;    break;
+    }
+
+    // add new exponent
+    newValue = newValue | exponent;
+
+    // write back
+    return WRITE_REG(reg, newValue);
+}
+
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8
exponent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: band width");
+    #endif
+
+    return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent);
+}
+
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse
mantisse, u8 exponent)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: band width during afc");
+    #endif
+
+    return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
+}
+
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType
thresholdType)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold type");
+    #endif
+
+    switch (thresholdType)
+    {
+    case fixed:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) );
+    case peak:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) );
+    case average:    return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep
thresholdStep)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold step");
+    #endif
+
+    switch (thresholdStep) {
+    case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) );
+    case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) );
+    case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) );
+    case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) );
+    case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) );
+    case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) );
+    case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) );
+    case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) );
+    default:     INVALID_PARAM;
+    }
+}
+
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement
thresholdDecrement)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: threshold decrement");
+    #endif
+
+    switch (thresholdDecrement) {
+    case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) );
+    case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) );
+    case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) );
+    case dec_once:       return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK)
& ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) );
+    case dec_twice:       return WRITE_REG(REG_OOKPEAK, (
(READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) );
+    case dec_4times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) );
+    case dec_8times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) );
+    case dec_16times:  return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) &
~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) );
+    default:       INVALID_PARAM;
+    }
+}
+
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+{
+    u8 mask;
+    u8 shift;
+    u8 regaddr;
+    u8 regValue;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: DIO mapping");
+    #endif
+
+    // check DIO number
+    if (DIONumber > 5) INVALID_PARAM;
+
+    switch (DIONumber) {
+    case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break;
+    case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break;
+    case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break;
+    case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break;
+    case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break;
+    case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break;
+    }
+
+    // read reg
+    regValue=READ_REG(regaddr);
+    // delete old value
+    regValue = regValue & ~mask;
+    // add new value
+    regValue = regValue | value << shift;
+    // write back
+    return WRITE_REG(regaddr,regValue);
+}
+
+bool rf69_get_flag(struct spi_device *spi, enum flag flag)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: flag");
+    #endif
+
+    switch(flag) {
+    case modeSwitchCompleted:     return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_MODE_READY);
+    case readyToReceive:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_RX_READY);
+    case readyToSend:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_TX_READY);
+    case pllLocked:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_PLL_LOCK);
+    case rssiExceededThreshold:   return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_RSSI);
+    case timeout:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_TIMEOUT);
+    case automode:              return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_AUTOMODE);
+    case syncAddressMatch:          return (READ_REG(REG_IRQFLAGS1) &
MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+    case fifoFull:              return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_FULL);
+/*    case fifoNotEmpty:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */
+    case fifoEmpty:              return !(READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_NOT_EMPTY);
+    case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_LEVEL);
+    case fifoOverrun:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_FIFO_OVERRUN);
+    case packetSent:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_PACKET_SENT);
+    case payloadReady:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_PAYLOAD_READY);
+    case crcOk:              return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_CRC_OK);
+    case batteryLow:          return (READ_REG(REG_IRQFLAGS2) &
MASK_IRQFLAGS2_LOW_BAT);
+    default:              return false;
+    }
+}
+
+int rf69_reset_flag(struct spi_device *spi, enum flag flag)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "reset: flag");
+    #endif
+
+    switch(flag) {
+    case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1,
MASK_IRQFLAGS1_RSSI);
+    case syncAddressMatch:        return WRITE_REG(REG_IRQFLAGS1,
MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+    case fifoOverrun:        return WRITE_REG(REG_IRQFLAGS2,
MASK_IRQFLAGS2_FIFO_OVERRUN);
+    default:            INVALID_PARAM;
+    }
+}
+
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: rssi threshold");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RSSITHRESH, threshold);
+}
+
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: start timeout");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RXTIMEOUT1, timeout);
+}
+
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: rssi timeout");
+    #endif
+
+    /* no value check needed - u8 exactly matches register size */
+
+    return WRITE_REG(REG_RXTIMEOUT2, timeout);
+}
+
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+{
+    int retval;
+    u8 msb, lsb;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: preample length");
+    #endif
+
+    /* no value check needed - u16 exactly matches register size */
+
+    /* calculate reg settings */
+    msb = (preambleLength&0xff00)   >>  8;
+    lsb = (preambleLength&0xff);
+
+    /* transmit to chip */
+    retval = WRITE_REG(REG_PREAMBLE_MSB, msb);
+    if (retval) return retval;
+    retval = WRITE_REG(REG_PREAMBLE_LSB, lsb);
+
+    return retval;
+}
+
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync enable");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_SYNC_ON) );
+    case optionOff:    return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition
fifoFillCondition)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: fifo fill condition");
+    #endif
+
+    switch(fifoFillCondition) {
+    case always:         return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+    case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG,
(READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+    default:         INVALID_PARAM;
+    }
+}
+
+int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync size");
+    #endif
+
+    // check input value
+    if (syncSize > 0x07)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) &
~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) );
+}
+
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync tolerance");
+    #endif
+
+    // check input value
+    if (syncTolerance > 0x07)
+        INVALID_PARAM;
+
+    // write value
+    return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) &
~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance);
+}
+
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+{
+    int retval = 0;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: sync values");
+    #endif
+
+    retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]);
+    retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]);
+    retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]);
+    retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]);
+    retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]);
+    retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]);
+    retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]);
+    retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]);
+
+    return retval;
+}
+
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat
packetFormat)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: packet format");
+    #endif
+
+    switch(packetFormat) {
+    case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+    case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+    default:          INVALID_PARAM;
+    }
+}
+
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: crc enable");
+    #endif
+
+    switch(optionOnOff) {
+    case optionOn:    return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_CRC_ON) );
+    case optionOff:    return WRITE_REG(REG_PACKETCONFIG1,
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) );
+    default:    INVALID_PARAM;
+    }
+}
+
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering
addressFiltering)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: address filtering");
+    #endif
+
+    switch (addressFiltering) {
+    case filteringOff:         return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_OFF) );
+    case nodeAddress:         return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_NODE) );
+    case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, (
(READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) |
PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) );
+    default:             INVALID_PARAM;
+    }
+}
+
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: payload length");
+    #endif
+
+    return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength);
+}
+
+u8  rf69_get_payload_length(struct spi_device *spi)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "get: payload length");
+    #endif
+
+    return (u8) READ_REG(REG_PAYLOAD_LENGTH);
+}
+
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: node address");
+    #endif
+
+    return WRITE_REG(REG_NODEADRS, nodeAddress);
+}
+
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: broadcast address");
+    #endif
+
+    return WRITE_REG(REG_BROADCASTADRS, broadcastAddress);
+}
+
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition
txStartCondition)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: start condition");
+    #endif
+
+    switch(txStartCondition) {
+    case fifoLevel:       return WRITE_REG(REG_FIFO_THRESH,
(READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) );
+    case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH,
(READ_REG(REG_FIFO_THRESH) |  MASK_FIFO_THRESH_TXSTART) );
+    default:       INVALID_PARAM;
+    }
+}
+
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
+{
+    int retval;
+
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: fifo threshold");
+    #endif
+
+    // check input value
+    if (threshold & 0x80)
+        INVALID_PARAM;
+
+    // write value
+    retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) &
~MASK_FIFO_THRESH_VALUE) | threshold);
+    if (retval)
+        return retval;
+
+    // access the fifo to activate new threshold
+    return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer
+}
+
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
+{
+    #ifdef DEBUG
+        dev_dbg(&spi->dev, "set: dagc");
+    #endif
+
+    switch(dagc) {
+    case normalMode:         return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL);
+    case improve:             return WRITE_REG(REG_TESTDAGC,
DAGC_IMPROVED_LOWBETA0);
+    case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC,
DAGC_IMPROVED_LOWBETA1);
+    default:             INVALID_PARAM;
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+    #ifdef DEBUG_FIFO_ACCESS    
+        int i;
+    #endif
+    struct spi_transfer transfer;
+    u8 local_buffer[FIFO_SIZE + 1];
+    int retval;
+
+    if (size > FIFO_SIZE)
+    {
+        #ifdef DEBUG
+            dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then
internal buffer \n");
+        #endif
+        return -EMSGSIZE;
+    }
+
+    /* prepare a bidirectional transfer */
+    local_buffer[0] = REG_FIFO;
+    memset(&transfer, 0, sizeof(transfer));
+      transfer.tx_buf = local_buffer;
+      transfer.rx_buf = local_buffer;
+    transfer.len    = size+1;
+
+    retval = spi_sync_transfer(spi, &transfer, 1);
+
+    #ifdef DEBUG_FIFO_ACCESS
+        for (i=0; i<size; i++)
+            dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]);
+    #endif
+
+    memcpy(buffer, &local_buffer[1], size);  // TODO: ohne memcopy wäre schöner
+
+    return retval;
+}
+
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+    #ifdef DEBUG_FIFO_ACCESS    
+        int i;
+    #endif
+    char spi_address = REG_FIFO | WRITE_BIT;
+    u8 local_buffer[FIFO_SIZE + 1];
+
+    if (size > FIFO_SIZE)
+    {
+        #ifdef DEBUG
+            dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then
internal buffer \n");
+        #endif
+        return -EMSGSIZE;
+    }
+
+    local_buffer[0] = spi_address;
+    memcpy(&local_buffer[1], buffer, size);  // TODO: ohne memcopy wäre schöner
+
+    #ifdef DEBUG_FIFO_ACCESS
+        for (i=0; i<size; i++)
+            dev_dbg(&spi->dev, "0x%x\n",buffer[i]);
+    #endif
+
+    return spi_write (spi, local_buffer, size + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+u8 rf69_read_reg(struct spi_device *spi, u8 addr)
+{
+    int retval;
+
+    retval = spi_w8r8(spi, addr);
+
+    #ifdef DEBUG_VALUES
+        if (retval < 0)
+            /* should never happen, since we already checked,
+               that module is connected. Therefore no error
+               handling, just an optional error message... */
+            dev_dbg(&spi->dev, "read 0x%x FAILED\n",
+                addr);
+        else
+            dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n",
+                retval,
+                addr);
+    #endif
+
+    return retval;
+}
+
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value)
+{
+    int retval;
+    char buffer[2];
+    
+    buffer[0] = addr | WRITE_BIT;
+    buffer[1] = value;
+
+    retval = spi_write(spi, &buffer, 2);
+
+    #ifdef DEBUG_VALUES
+        if (retval < 0)
+            /* should never happen, since we already checked,
+               that module is connected. Therefore no error
+               handling, just an optional error message... */
+            dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n",
+                value,
+                addr);
+        else
+            dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n",
+                value,
+                addr);
+    #endif
+
+    return retval;
+}
+
+
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
new file mode 100644
index 0000000..6a6841b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.h
@@ -0,0 +1,82 @@
+/*
+ * hardware abstraction/register access for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef RF69_H
+#define RF69_H
+
+#include "rf69_enum.h"
+#include "rf69_registers.h"
+
+#define F_OSC         32000000  /* in Hz */
+#define FREQUENCY    433920000 /* in Hz, modifying this value impacts CE
certification */
+#define FIFO_SIZE     66        /* in byte */
+#define FIFO_THRESHOLD    15       /* in byte */
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode);
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode);
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
+enum modulation rf69_get_modulation(struct spi_device *spi);
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping
modShaping);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_deviation(struct spi_device *spi, u32 deviation);
+int rf69_set_frequency(struct spi_device *spi, u32 frequency);
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance
antennaImpedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi);
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum
dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent
dccPercent);
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum
dccPercent dccPercent);
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8
exponent);
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse
mantisse, u8 exponent);
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType
thresholdType);
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep
thresholdStep);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement
thresholdDecrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+bool rf69_get_flag(struct spi_device *spi, enum flag flag);
+int rf69_reset_flag(struct spi_device *spi, enum flag flag);
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition
fifoFillCondition);
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance);
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat
packetFormat);
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering
addressFiltering);
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength);
+u8  rf69_get_payload_length(struct spi_device *spi);
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition
txStartCondition);
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size);
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size);
+
+u8  rf69_read_reg (struct spi_device *spi, u8 addr);
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value);
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_enum.h
b/drivers/staging/pi433/rf69_enum.h
new file mode 100644
index 0000000..fbfb59b
--- /dev/null
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -0,0 +1,201 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_registers.h
b/drivers/staging/pi433/rf69_registers.h
new file mode 100644
index 0000000..d0c4992
--- /dev/null
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -0,0 +1,489 @@
+/*
+ * register description for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *    Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*******************************************/
+/* RF69 register addresses           */
+/*******************************************/
+#define  REG_FIFO            0x00
+#define  REG_OPMODE            0x01
+#define  REG_DATAMODUL            0x02
+#define  REG_BITRATE_MSB        0x03
+#define  REG_BITRATE_LSB        0x04
+#define  REG_FDEV_MSB            0x05
+#define  REG_FDEV_LSB            0x06
+#define  REG_FRF_MSB            0x07
+#define  REG_FRF_MID            0x08
+#define  REG_FRF_LSB            0x09
+#define  REG_OSC1            0x0A
+#define  REG_AFCCTRL            0x0B
+#define  REG_LOWBAT            0x0C
+#define  REG_LISTEN1            0x0D
+#define  REG_LISTEN2            0x0E
+#define  REG_LISTEN3            0x0F
+#define  REG_VERSION            0x10
+#define  REG_PALEVEL            0x11
+#define  REG_PARAMP            0x12
+#define  REG_OCP            0x13
+#define  REG_AGCREF            0x14 /* not available on RF69 */
+#define  REG_AGCTHRESH1            0x15 /* not available on RF69 */
+#define  REG_AGCTHRESH2            0x16 /* not available on RF69 */
+#define  REG_AGCTHRESH3            0x17 /* not available on RF69 */
+#define  REG_LNA            0x18
+#define  REG_RXBW            0x19
+#define  REG_AFCBW            0x1A
+#define  REG_OOKPEAK            0x1B
+#define  REG_OOKAVG            0x1C
+#define  REG_OOKFIX            0x1D
+#define  REG_AFCFEI            0x1E
+#define  REG_AFCMSB            0x1F
+#define  REG_AFCLSB            0x20
+#define  REG_FEIMSB            0x21
+#define  REG_FEILSB            0x22
+#define  REG_RSSICONFIG            0x23
+#define  REG_RSSIVALUE            0x24
+#define  REG_DIOMAPPING1        0x25
+#define  REG_DIOMAPPING2        0x26
+#define  REG_IRQFLAGS1            0x27
+#define  REG_IRQFLAGS2            0x28
+#define  REG_RSSITHRESH            0x29
+#define  REG_RXTIMEOUT1            0x2A
+#define  REG_RXTIMEOUT2            0x2B
+#define  REG_PREAMBLE_MSB        0x2C
+#define  REG_PREAMBLE_LSB        0x2D
+#define  REG_SYNC_CONFIG        0x2E
+#define  REG_SYNCVALUE1            0x2F
+#define  REG_SYNCVALUE2            0x30
+#define  REG_SYNCVALUE3            0x31
+#define  REG_SYNCVALUE4            0x32
+#define  REG_SYNCVALUE5            0x33
+#define  REG_SYNCVALUE6            0x34
+#define  REG_SYNCVALUE7            0x35
+#define  REG_SYNCVALUE8            0x36
+#define  REG_PACKETCONFIG1        0x37
+#define  REG_PAYLOAD_LENGTH        0x38
+#define  REG_NODEADRS            0x39
+#define  REG_BROADCASTADRS        0x3A
+#define  REG_AUTOMODES            0x3B
+#define  REG_FIFO_THRESH        0x3C
+#define  REG_PACKETCONFIG2        0x3D
+#define  REG_AESKEY1            0x3E
+#define  REG_AESKEY2            0x3F
+#define  REG_AESKEY3            0x40
+#define  REG_AESKEY4            0x41
+#define  REG_AESKEY5            0x42
+#define  REG_AESKEY6            0x43
+#define  REG_AESKEY7            0x44
+#define  REG_AESKEY8            0x45
+#define  REG_AESKEY9            0x46
+#define  REG_AESKEY10            0x47
+#define  REG_AESKEY11            0x48
+#define  REG_AESKEY12            0x49
+#define  REG_AESKEY13            0x4A
+#define  REG_AESKEY14            0x4B
+#define  REG_AESKEY15            0x4C
+#define  REG_AESKEY16            0x4D
+#define  REG_TEMP1            0x4E
+#define  REG_TEMP2            0x4F
+#define  REG_TESTPA1            0x5A /* only present on RFM69HW */
+#define  REG_TESTPA2            0x5C /* only present on RFM69HW */
+#define  REG_TESTDAGC            0x6F
+
+/******************************************************/
+/* RF69/SX1231 bit definition                */
+/******************************************************/
+/* write bit */
+#define WRITE_BIT                0x80
+
+/* RegOpMode */
+#define  MASK_OPMODE_SEQUENCER_OFF        0x80
+#define  MASK_OPMODE_LISTEN_ON            0x40
+#define  MASK_OPMODE_LISTEN_ABORT        0x20
+#define  MASK_OPMODE_MODE            0x1C
+
+#define  OPMODE_MODE_SLEEP            0x00
+#define  OPMODE_MODE_STANDBY            0x04 /* default */
+#define  OPMODE_MODE_SYNTHESIZER        0x08
+#define  OPMODE_MODE_TRANSMIT            0x0C
+#define  OPMODE_MODE_RECEIVE            0x10
+
+/* RegDataModul */
+#define  MASK_DATAMODUL_MODE            0x06
+#define  MASK_DATAMODUL_MODULATION_TYPE        0x18
+#define  MASK_DATAMODUL_MODULATION_SHAPE    0x03
+
+#define  DATAMODUL_MODE_PACKET            0x00 /* default */
+#define  DATAMODUL_MODE_CONTINUOUS        0x40
+#define  DATAMODUL_MODE_CONTINUOUS_NOSYNC    0x60
+
+#define  DATAMODUL_MODULATION_TYPE_FSK        0x00 /* default */
+#define  DATAMODUL_MODULATION_TYPE_OOK        0x08
+
+#define  DATAMODUL_MODULATION_SHAPE_NONE    0x00 /* default */
+#define  DATAMODUL_MODULATION_SHAPE_1_0        0x01
+#define  DATAMODUL_MODULATION_SHAPE_0_5        0x02
+#define  DATAMODUL_MODULATION_SHAPE_0_3        0x03
+#define  DATAMODUL_MODULATION_SHAPE_BR        0x01
+#define  DATAMODUL_MODULATION_SHAPE_2BR        0x02
+
+/* RegFDevMsb (0x05)*/
+#define FDEVMASB_MASK                0x3f
+
+/*
+// RegOsc1
+#define  OSC1_RCCAL_START            0x80
+#define  OSC1_RCCAL_DONE            0x40
+
+// RegLowBat
+#define  LOWBAT_MONITOR                0x10
+#define  LOWBAT_ON                0x08
+#define  LOWBAT_OFF                0x00  // Default
+
+#define  LOWBAT_TRIM_1695            0x00
+#define  LOWBAT_TRIM_1764            0x01
+#define  LOWBAT_TRIM_1835            0x02  // Default
+#define  LOWBAT_TRIM_1905            0x03
+#define  LOWBAT_TRIM_1976            0x04
+#define  LOWBAT_TRIM_2045            0x05
+#define  LOWBAT_TRIM_2116            0x06
+#define  LOWBAT_TRIM_2185            0x07
+
+
+// RegListen1
+#define  LISTEN1_RESOL_64            0x50
+#define  LISTEN1_RESOL_4100            0xA0  // Default
+#define  LISTEN1_RESOL_262000            0xF0
+
+#define  LISTEN1_CRITERIA_RSSI            0x00  // Default
+#define  LISTEN1_CRITERIA_RSSIANDSYNC        0x08
+
+#define  LISTEN1_END_00                0x00
+#define  LISTEN1_END_01                0x02  // Default
+#define  LISTEN1_END_10                0x04
+
+
+// RegListen2
+#define  LISTEN2_COEFIDLE_VALUE            0xF5 // Default
+
+// RegListen3
+#define  LISTEN3_COEFRX_VALUE            0x20 // Default
+*/
+
+// RegPaLevel
+#define  MASK_PALEVEL_PA0            0x80
+#define  MASK_PALEVEL_PA1            0x40
+#define  MASK_PALEVEL_PA2            0x20
+#define  MASK_PALEVEL_OUTPUT_POWER        0x1F
+
+
+
+// RegPaRamp
+#define  PARAMP_3400                0x00
+#define  PARAMP_2000                0x01
+#define  PARAMP_1000                0x02
+#define  PARAMP_500                0x03
+#define  PARAMP_250                0x04
+#define  PARAMP_125                0x05
+#define  PARAMP_100                0x06
+#define  PARAMP_62                0x07
+#define  PARAMP_50                0x08
+#define  PARAMP_40                0x09 /* default */
+#define  PARAMP_31                0x0A
+#define  PARAMP_25                0x0B
+#define  PARAMP_20                0x0C
+#define  PARAMP_15                0x0D
+#define  PARAMP_12                0x0E
+#define  PARAMP_10                0x0F
+
+#define  MASK_PARAMP                0x0F
+
+/*
+// RegOcp
+#define  OCP_OFF                0x0F
+#define  OCP_ON                    0x1A  // Default
+
+#define  OCP_TRIM_45                0x00
+#define  OCP_TRIM_50                0x01
+#define  OCP_TRIM_55                0x02
+#define  OCP_TRIM_60                0x03
+#define  OCP_TRIM_65                0x04
+#define  OCP_TRIM_70                0x05
+#define  OCP_TRIM_75                0x06
+#define  OCP_TRIM_80                0x07
+#define  OCP_TRIM_85                0x08
+#define  OCP_TRIM_90                0x09
+#define  OCP_TRIM_95                0x0A
+#define  OCP_TRIM_100                0x0B  // Default
+#define  OCP_TRIM_105                0x0C
+#define  OCP_TRIM_110                0x0D
+#define  OCP_TRIM_115                0x0E
+#define  OCP_TRIM_120                0x0F
+*/
+
+/* RegLna (0x18) */
+#define  MASK_LNA_ZIN                0x80
+#define  MASK_LNA_CURRENT_GAIN            0x38
+#define  MASK_LNA_GAIN                0x07
+
+#define  LNA_GAIN_AUTO                0x00 /* default */
+#define  LNA_GAIN_MAX                0x01
+#define  LNA_GAIN_MAX_MINUS_6            0x02
+#define  LNA_GAIN_MAX_MINUS_12            0x03
+#define  LNA_GAIN_MAX_MINUS_24            0x04
+#define  LNA_GAIN_MAX_MINUS_36            0x05
+#define  LNA_GAIN_MAX_MINUS_48            0x06
+
+
+/* RegRxBw (0x19) and RegAfcBw (0x1A) */
+#define  MASK_BW_DCC_FREQ            0xE0
+#define  MASK_BW_MANTISSE            0x18
+#define  MASK_BW_EXPONENT            0x07
+
+#define  BW_DCC_16_PERCENT            0x00
+#define  BW_DCC_8_PERCENT            0x20
+#define  BW_DCC_4_PERCENT            0x40 /* default */
+#define  BW_DCC_2_PERCENT            0x60
+#define  BW_DCC_1_PERCENT            0x80
+#define  BW_DCC_0_5_PERCENT            0xA0
+#define  BW_DCC_0_25_PERCENT            0xC0
+#define  BW_DCC_0_125_PERCENT            0xE0
+
+#define  BW_MANT_16                0x00
+#define  BW_MANT_20                0x08
+#define  BW_MANT_24                0x10 /* default */
+
+
+/* RegOokPeak (0x1B) */
+#define  MASK_OOKPEAK_THRESTYPE            0xc0
+#define  MASK_OOKPEAK_THRESSTEP            0x38
+#define  MASK_OOKPEAK_THRESDEC            0x07
+
+#define  OOKPEAK_THRESHTYPE_FIXED        0x00
+#define  OOKPEAK_THRESHTYPE_PEAK        0x40 /* default */
+#define  OOKPEAK_THRESHTYPE_AVERAGE        0x80
+
+#define  OOKPEAK_THRESHSTEP_0_5_DB        0x00 /* default */
+#define  OOKPEAK_THRESHSTEP_1_0_DB        0x08
+#define  OOKPEAK_THRESHSTEP_1_5_DB        0x10
+#define  OOKPEAK_THRESHSTEP_2_0_DB        0x18
+#define  OOKPEAK_THRESHSTEP_3_0_DB        0x20
+#define  OOKPEAK_THRESHSTEP_4_0_DB        0x28
+#define  OOKPEAK_THRESHSTEP_5_0_DB        0x30
+#define  OOKPEAK_THRESHSTEP_6_0_DB        0x38
+
+#define  OOKPEAK_THRESHDEC_ONCE            0x00 /* default */
+#define  OOKPEAK_THRESHDEC_EVERY_2ND        0x01
+#define  OOKPEAK_THRESHDEC_EVERY_4TH        0x02
+#define  OOKPEAK_THRESHDEC_EVERY_8TH        0x03
+#define  OOKPEAK_THRESHDEC_TWICE        0x04
+#define  OOKPEAK_THRESHDEC_4_TIMES        0x05
+#define  OOKPEAK_THRESHDEC_8_TIMES        0x06
+#define  OOKPEAK_THRESHDEC_16_TIMES        0x07
+
+/*
+// RegOokAvg
+#define  OOKAVG_AVERAGETHRESHFILT_00        0x00
+#define  OOKAVG_AVERAGETHRESHFILT_01        0x40
+#define  OOKAVG_AVERAGETHRESHFILT_10        0x80  // Default
+#define  OOKAVG_AVERAGETHRESHFILT_11        0xC0
+
+
+// RegAfcFei
+#define  AFCFEI_FEI_DONE            0x40
+#define  AFCFEI_FEI_START            0x20
+#define  AFCFEI_AFC_DONE            0x10
+#define  AFCFEI_AFCAUTOCLEAR_ON            0x08
+#define  AFCFEI_AFCAUTOCLEAR_OFF        0x00  // Default
+
+#define  AFCFEI_AFCAUTO_ON            0x04
+#define  AFCFEI_AFCAUTO_OFF            0x00  // Default
+
+#define  AFCFEI_AFC_CLEAR            0x02
+#define  AFCFEI_AFC_START            0x01
+
+// RegRssiConfig
+#define  RSSI_FASTRX_ON                0x08
+#define  RSSI_FASTRX_OFF            0x00  // Default
+#define  RSSI_DONE                0x02
+#define  RSSI_START                0x01
+*/
+
+/* RegDioMapping1 */
+#define  MASK_DIO0                0xC0
+#define  MASK_DIO1                0x30
+#define  MASK_DIO2                0x0C
+#define  MASK_DIO3                0x03
+#define  SHIFT_DIO0                6
+#define  SHIFT_DIO1                4
+#define  SHIFT_DIO2                2
+#define  SHIFT_DIO3                0
+
+/* RegDioMapping2 */
+#define  MASK_DIO4                0xC0
+#define  MASK_DIO5                0x30
+#define  SHIFT_DIO4                6
+#define  SHIFT_DIO5                4
+
+/* DIO numbers */
+#define  DIO0                    0
+#define  DIO1                    1
+#define  DIO2                    2
+#define  DIO3                    3
+#define  DIO4                    4
+#define  DIO5                    5
+
+/* DIO Mapping values (packet mode) */
+#define  DIO_ModeReady_DIO4            0x00
+#define  DIO_ModeReady_DIO5            0x03
+#define  DIO_ClkOut                0x00
+#define  DIO_Data                0x01
+#define  DIO_TimeOut_DIO1            0x03
+#define  DIO_TimeOut_DIO4            0x00
+#define  DIO_Rssi_DIO0                0x03
+#define  DIO_Rssi_DIO3_4            0x01
+#define  DIO_RxReady                0x02
+#define  DIO_PLLLock                0x03
+#define  DIO_TxReady                0x01
+#define  DIO_FifoFull_DIO1            0x01
+#define  DIO_FifoFull_DIO3            0x00
+#define  DIO_SyncAddress            0x02
+#define  DIO_FifoNotEmpty_DIO1            0x02
+#define  DIO_FifoNotEmpty_FIO2            0x00
+#define  DIO_Automode                0x04
+#define  DIO_FifoLevel                0x00
+#define  DIO_CrcOk                0x00
+#define  DIO_PayloadReady            0x01
+#define  DIO_PacketSent                0x00
+#define  DIO_Dclk                0x00
+
+/* RegDioMapping2 CLK_OUT part */
+#define  MASK_DIOMAPPING2_CLK_OUT        0x07
+
+#define  DIOMAPPING2_CLK_OUT_NO_DIV        0x00
+#define  DIOMAPPING2_CLK_OUT_DIV_2        0x01
+#define  DIOMAPPING2_CLK_OUT_DIV_4        0x02
+#define  DIOMAPPING2_CLK_OUT_DIV_8        0x03
+#define  DIOMAPPING2_CLK_OUT_DIV_16        0x04
+#define  DIOMAPPING2_CLK_OUT_DIV_32        0x05
+#define  DIOMAPPING2_CLK_OUT_RC            0x06
+#define  DIOMAPPING2_CLK_OUT_OFF        0x07 /* default */
+
+/* RegIrqFlags1 */
+#define  MASK_IRQFLAGS1_MODE_READY        0x80
+#define  MASK_IRQFLAGS1_RX_READY        0x40
+#define  MASK_IRQFLAGS1_TX_READY        0x20
+#define  MASK_IRQFLAGS1_PLL_LOCK        0x10
+#define  MASK_IRQFLAGS1_RSSI            0x08
+#define  MASK_IRQFLAGS1_TIMEOUT            0x04
+#define  MASK_IRQFLAGS1_AUTOMODE        0x02
+#define  MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH    0x01
+
+/* RegIrqFlags2 */
+#define  MASK_IRQFLAGS2_FIFO_FULL        0x80
+#define  MASK_IRQFLAGS2_FIFO_NOT_EMPTY        0x40
+#define  MASK_IRQFLAGS2_FIFO_LEVEL        0x20
+#define  MASK_IRQFLAGS2_FIFO_OVERRUN        0x10
+#define  MASK_IRQFLAGS2_PACKET_SENT        0x08
+#define  MASK_IRQFLAGS2_PAYLOAD_READY        0x04
+#define  MASK_IRQFLAGS2_CRC_OK            0x02
+#define  MASK_IRQFLAGS2_LOW_BAT            0x01
+
+/* RegSyncConfig */
+#define  MASK_SYNC_CONFIG_SYNC_ON        0x80 /* default */
+#define  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION    0x40
+#define  MASK_SYNC_CONFIG_SYNC_SIZE        0x38
+#define  MASK_SYNC_CONFIG_SYNC_TOLERANCE    0x07
+
+/* RegPacketConfig1 */
+#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE    0x80
+#define  MASK_PACKETCONFIG1_DCFREE            0x60
+#define  MASK_PACKETCONFIG1_CRC_ON            0x10 /* default */
+#define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF        0x08
+#define  MASK_PACKETCONFIG1_ADDRESSFILTERING        0x06
+
+#define  PACKETCONFIG1_DCFREE_OFF            0x00 /* default */
+#define  PACKETCONFIG1_DCFREE_MANCHESTER        0x20
+#define  PACKETCONFIG1_DCFREE_WHITENING            0x40
+#define  PACKETCONFIG1_ADDRESSFILTERING_OFF        0x00 /* default */
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODE        0x02
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST    0x04
+
+/*
+// RegAutoModes
+#define  AUTOMODES_ENTER_OFF            0x00  // Default
+#define  AUTOMODES_ENTER_FIFONOTEMPTY        0x20
+#define  AUTOMODES_ENTER_FIFOLEVEL        0x40
+#define  AUTOMODES_ENTER_CRCOK            0x60
+#define  AUTOMODES_ENTER_PAYLOADREADY        0x80
+#define  AUTOMODES_ENTER_SYNCADRSMATCH        0xA0
+#define  AUTOMODES_ENTER_PACKETSENT        0xC0
+#define  AUTOMODES_ENTER_FIFOEMPTY        0xE0
+
+#define  AUTOMODES_EXIT_OFF            0x00  // Default
+#define  AUTOMODES_EXIT_FIFOEMPTY        0x04
+#define  AUTOMODES_EXIT_FIFOLEVEL        0x08
+#define  AUTOMODES_EXIT_CRCOK            0x0C
+#define  AUTOMODES_EXIT_PAYLOADREADY        0x10
+#define  AUTOMODES_EXIT_SYNCADRSMATCH        0x14
+#define  AUTOMODES_EXIT_PACKETSENT        0x18
+#define  AUTOMODES_EXIT_RXTIMEOUT        0x1C
+
+#define  AUTOMODES_INTERMEDIATE_SLEEP        0x00  // Default
+#define  AUTOMODES_INTERMEDIATE_STANDBY        0x01
+#define  AUTOMODES_INTERMEDIATE_RECEIVER    0x02
+#define  AUTOMODES_INTERMEDIATE_TRANSMITTER    0x03
+
+*/
+/* RegFifoThresh (0x3c) */
+#define  MASK_FIFO_THRESH_TXSTART        0x80
+#define  MASK_FIFO_THRESH_VALUE            0x7F
+
+/*
+
+// RegPacketConfig2
+#define  PACKET2_RXRESTARTDELAY_1BIT        0x00  // Default
+#define  PACKET2_RXRESTARTDELAY_2BITS        0x10
+#define  PACKET2_RXRESTARTDELAY_4BITS        0x20
+#define  PACKET2_RXRESTARTDELAY_8BITS        0x30
+#define  PACKET2_RXRESTARTDELAY_16BITS        0x40
+#define  PACKET2_RXRESTARTDELAY_32BITS        0x50
+#define  PACKET2_RXRESTARTDELAY_64BITS        0x60
+#define  PACKET2_RXRESTARTDELAY_128BITS        0x70
+#define  PACKET2_RXRESTARTDELAY_256BITS        0x80
+#define  PACKET2_RXRESTARTDELAY_512BITS        0x90
+#define  PACKET2_RXRESTARTDELAY_1024BITS    0xA0
+#define  PACKET2_RXRESTARTDELAY_2048BITS    0xB0
+#define  PACKET2_RXRESTARTDELAY_NONE        0xC0
+#define  PACKET2_RXRESTART            0x04
+
+#define  PACKET2_AUTORXRESTART_ON        0x02  // Default
+#define  PACKET2_AUTORXRESTART_OFF        0x00
+
+#define  PACKET2_AES_ON                0x01
+#define  PACKET2_AES_OFF            0x00  // Default
+
+
+// RegTemp1
+#define  TEMP1_MEAS_START            0x08
+#define  TEMP1_MEAS_RUNNING            0x04
+#define  TEMP1_ADCLOWPOWER_ON            0x01  // Default
+#define  TEMP1_ADCLOWPOWER_OFF            0x00
+*/
+
+// RegTestDagc (0x6F)
+#define  DAGC_NORMAL                0x00 /* Reset value */
+#define  DAGC_IMPROVED_LOWBETA1            0x20
+#define  DAGC_IMPROVED_LOWBETA0            0x30 /* Recommended val */
 
 

> Greg KH <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org> hat am 15. Juli 2017 um 15:02
> geschrieben:
>
>
> On Sat, Jul 15, 2017 at 02:59:25PM +0200, Marcus Wolf wrote:
> > Hi!
> >
> > It's me again. Seems like I also need help on sending the email :-/
> >
> > I checked the whitespace/line wrap problem, but couldn't find any suspicious
> > lines.
> >
> > What I did:
> > * Looked into my outbox - the copy of my mail to you seems to be okay...
> > * I sent the patch once again (just to me) - result: Seems to be fine, too.
> >
> > Maybe you can bounce back my mail? Maybe I'll get an idea what went wrong,
> > if I
> > see the smashed code...
>
> You sent the patch in html format, which caused all of the whitespace
> corruption. html will not work for kernel patches for obvious reasons
> :)
>
> thanks,
>
> greg k-h
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 13:16               ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-15 13:16 UTC (permalink / raw)
  To: Marcus Wolf; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

On Sat, Jul 15, 2017 at 03:10:48PM +0200, Marcus Wolf wrote:
> Hi!
>  
> Ok. Thanks for the info. Didn't observe that.
>  I'll give the old patch another try.
>  
> I will send a new patch as soon, as I know. how to produce the 
> poper format (with subjects, signing and so on).

Documentation/SubmittingPatches should have all of the information you
need for this type of thing.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 13:16               ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-15 13:16 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Sat, Jul 15, 2017 at 03:10:48PM +0200, Marcus Wolf wrote:
> Hi!
>  
> Ok. Thanks for the info. Didn't observe that.
>  I'll give the old patch another try.
>  
> I will send a new patch as soon, as I know. how to produce the 
> poper format (with subjects, signing and so on).

Documentation/SubmittingPatches should have all of the information you
need for this type of thing.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
  2017-07-15 13:16               ` Greg KH
  (?)
@ 2017-07-15 13:40               ` Marcus Wolf
  2017-07-15 13:47                   ` Greg KH
  -1 siblings, 1 reply; 49+ messages in thread
From: Marcus Wolf @ 2017-07-15 13:40 UTC (permalink / raw)
  To: Greg KH; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

[-- Attachment #1: Type: text/plain, Size: 807 bytes --]

Hi Greg,
 
I absolutly agree. My patch should meet the needs of an official patch.
 
But I don't know about the exact needs. Can you please help me? What is needed /
missing in my patch and how do I produce it?
Maybe you can pass me a link, where I can read, what to do?
 
Thanks a lot,
 
Marcus

> Greg KH <gregkh@linuxfoundation.org> hat am 15. Juli 2017 um 15:16
> geschrieben:
>
>
> On Sat, Jul 15, 2017 at 03:10:48PM +0200, Marcus Wolf wrote:
> > Hi!
> >
> > Ok. Thanks for the info. Didn't observe that.
> > I'll give the old patch another try.
> >
> > I will send a new patch as soon, as I know. how to produce the
> > poper format (with subjects, signing and so on).
>
> Documentation/SubmittingPatches should have all of the information you
> need for this type of thing.
>
> thanks,
>
> greg k-h
>

[-- Attachment #2: Type: text/html, Size: 1231 bytes --]

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 13:47                   ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-15 13:47 UTC (permalink / raw)
  To: Marcus Wolf; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

On Sat, Jul 15, 2017 at 03:40:30PM +0200, Marcus Wolf wrote:
> Hi Greg,
>  
> I absolutly agree. My patch should meet the needs of an official patch.

Again, don't use html email :)

> But I don't know about the exact needs. Can you please help me? What is needed
> / missing in my patch and how do I produce it?
> Maybe you can pass me a link, where I can read, what to do?

The link I sent you, Documentation/SubmittingPatches in the kernel
source tree, should contain everything you need to know.  As a minimum
you need a good subject, a good changelog body text, and a
signed-off-by: line.  The file should tell you all about how to create
this.

If you have specific questions after reading that about these things,
please let us know.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 13:47                   ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-15 13:47 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Sat, Jul 15, 2017 at 03:40:30PM +0200, Marcus Wolf wrote:
> Hi Greg,
>  
> I absolutly agree. My patch should meet the needs of an official patch.

Again, don't use html email :)

> But I don't know about the exact needs. Can you please help me? What is needed
> / missing in my patch and how do I produce it?
> Maybe you can pass me a link, where I can read, what to do?

The link I sent you, Documentation/SubmittingPatches in the kernel
source tree, should contain everything you need to know.  As a minimum
you need a good subject, a good changelog body text, and a
signed-off-by: line.  The file should tell you all about how to create
this.

If you have specific questions after reading that about these things,
please let us know.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 17:05                     ` Wolf Entwicklungen
  0 siblings, 0 replies; 49+ messages in thread
From: Wolf Entwicklungen @ 2017-07-15 17:05 UTC (permalink / raw)
  To: Greg KH; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

Am Sa, 15.07.2017, 15:47 schrieb Greg KH:
> On Sat, Jul 15, 2017 at 03:40:30PM +0200, Marcus Wolf wrote:
>> Hi Greg,
>>

Hi Greg,

now I added a TODO file and did a manual patchwork with lines of the old patch
(git format-patch master --stdout -p > pi433_patch) and the newer patch (git
diff master > pi433_patch). Stil don't know how to retreive multiple commits
in one single patch directly from git :-/
I did my best to meet a lot of rules of the link, you send me.If
there is stil something essential wrong or missing, please excuse and let me know.

Especially I was in doubt about the verbosity of the change log. If you'd like
to see the list of features of the driver over there (please see my first mail),
let me know and I'll add.

Sorry for posting in HTML once again on last mail. Now I changed the frontend of my
mailtool. Hope this works better. If not, excuse and let me know.
I Think about moving to gits mail function for my next patches.

Cheers,

Marcus


From: Marcus Wolf <linux@Wolf-Entwicklungen.de>
Date: Tue,15 Jul 2017 17:52:06 +0100
Subject: [PATCH 1/1] drivers/staging/pi433: New driver

Added a driver for the pi433 radio module
(see https://www.pi433.de/en.html for details).
Signed-off-by: Marcus Wolf <linux@Wolf-Entwicklungen.de>
Tested-by: Marcus Wolf <linux@Wolf-Entwicklungen.de> on Raspbian, running Kernel v4.12
---
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 268d4e6..fdf060c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"

 source "drivers/staging/typec/Kconfig"

+source "drivers/staging/pi433/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b93e6f5..998f644 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)		+= ks7010/
 obj-$(CONFIG_GREYBUS)		+= greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)	+= vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)	+= ccree/
+obj-$(CONFIG_PI433)		+= pi433/
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
new file mode 100644
index 0000000..004b502
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
@@ -0,0 +1,53 @@
+// Definitions for Pi433
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			pi433_pins: pi433_pins {
+				brcm,pins = <7 25 24>;
+				brcm,function = <0 0 0>; // in in in
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pi433: pi433@0 {
+				compatible = "Smarthome-Wolf,pi433";
+				reg = <0>;
+				spi-max-frequency = <10000000>;
+				status = "okay";
+
+				pinctrl-0 = <&pi433_pins>;
+				DIO0-gpio = <&gpio 24 0>;
+				DIO1-gpio = <&gpio 25 0>;
+				DIO2-gpio = <&gpio  7 0>;
+			};
+		};
+	};
+};
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
new file mode 100644
index 0000000..14197c6
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
@@ -0,0 +1,62 @@
+* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see www.pi433.de)
+
+Required properties:
+- compatible: must be "Smarthome-Wolf,pi433"
+- reg: chip select of SPI Interface
+- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69 module
+
+
+Example:
+
+With the following lines in gpio-section, the gpio pins, connected with pi433 are
+reserved/declared.
+
+&gpio{
+	[...]
+
+	pi433_pins: pi433_pins {
+		brcm,pins = <7 25 24>;
+		brcm,function = <0 0 0>; // in in in
+	};
+
+	[...]
+}
+
+With the following lines in spi section, the device pi433 is declared.
+It consists of the three gpio pins and an spi interface (here chip select 0)
+
+&spi0{
+	[...]
+
+	pi433: pi433@0 {
+		compatible = "Smarthome-Wolf,pi433";
+		reg = <0>; /* CE 0 */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-max-frequency = <10000000>;
+
+		pinctrl-0 = <&pi433_pins>;
+		DIO0-gpio = <&gpio 24 0>;
+		DIO1-gpio = <&gpio 25 0>;
+		DIO2-gpio = <&gpio  7 0>;
+	};
+}
+
+
+
+For Raspbian users only
+=======================
+Since Raspbian supports device tree overlays, you may use and overlay, instead
+of editing your boards device tree.
+For using the overlay, you need to compile the file pi433-overlay.dts you can
+find aside to this documentation.
+The file needs to be compiled - either manually or by integration in your kernel
+source tree. For a manual compile, you may use a command line like the following:
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+arch/arm/boot/dts/overlays and you need to add the file to the list of files
+in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
+kernel make files compile the device tree overlay for you.
+
+
diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt
new file mode 100644
index 0000000..860dd0f
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -0,0 +1,274 @@
+=====
+Pi433
+=====
+
+
+Introduction
+============
+This driver is for controlling pi433, a radio module for the Raspberry Pi
+(www.pi433.de). It supports transmission and reception. It can be opened
+by multiple applications for transmission and reception. While transmit
+jobs were queued and process automatically in the background, the first
+application asking for reception will block out all other applications
+until something gets received terminates the read request.
+The driver supports on the fly reloading of the hardware fifo of the rf
+chip, thus enabling for much longer telegrams then hardware fifo size.
+
+Discription of driver operation
+===============================
+
+a) transmission
+
+Each transmission can take place with a different configuration of the rf
+module. Therfore each application can set its own set of parameters. The driver
+takes care, that each transmission takes place with the parameterset of the
+application, that requests the transmission. To allow the transmission to take
+place in the background, a tx thread is introduced.
+The transfer of data from the main thread to the tx thread is realised by a
+kfifo. With each write request of an application, the passed in data and the
+corresponding parameter set gets written to the kfifo.
+On the other "side" of the kfifo, the tx thread continuously checks, whether the
+kfifo is empty. If not, it gets one set of config and data from the kfifo. If
+there is no receive request or the receiver is still waiting for something in
+the air, the rf module is set to standby, the parameters for transmission gets
+set, the hardware fifo of the rf chip gets preloaded and the transmission gets
+started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling
+much longer telegrams then hardware fifo size. If the telegram is send and there
+is more data available in the kfifo, the procedure is repeated. If not the
+transmission cycle ends.
+
+b) reception
+
+Since there is only one application allowed to receive data at a time, for
+reception there is only one configuration set.
+As soon as an application sets an request for receiving a telegram, the reception
+configuration set is written to the rf module and it gets set into receiving mode.
+Now the driver is waiting, that a predefined RSSI level (signal strength at the
+receiver) is reached. Until this hasn't happened, the reception can be
+interrupted by the transmission thread at any time to insert a transmission cycle.
+As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar
+as described for the transmission cycle the read out of the hardware fifo is done
+dynamically. Upon each hardware fifo threshold interrupt, a portion of data gets
+read. So also for reception it is possible to receive more data then the hardware
+fifo can hold.
+
+
+Driver API
+==========
+
+The driver is currently implemented as a character device. Therefore it supports
+the calls open, ioctl, read, write and close.
+
+
+params for ioctl
+----------------
+
+There are four options:
+PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver
+PI433_IOC_WR_TX_CFG - set the transmission parameters
+PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver
+PI433_IOC_WR_RX_CFG - set the receiving parameters
+
+The tx configuration is transfered via struct pi433_tx_cfg, the parameterset for transmission.
+It is devided into two sections: rf parameters and packet format.
+
+rf params:
+	frequency
+		frequency used for transmission.
+		Allowed values: 433050000...434790000
+	bit_rate
+		bit rate used for transmission.
+		Allowed values: #####
+	dev_frequency
+		frequency deviation in case of FSK.
+		Allowed values: 600...500000
+	modulation
+		FSK - frequency shift key
+		OOK - On-Off-key
+	modShaping
+		shapingOff	- no shaping
+		shaping1_0	- gauss filter with BT 1 (FSK only)
+		shaping0_5	- gauss filter with BT 0.5 (FSK only)
+		shaping0_3	- gauss filter with BT 0.3 (FSK only)
+		shapingBR	- filter cut off at BR (OOK only)
+		shaping2BR	- filter cut off at 2*BR (OOK only)
+	paRamp (FSK only)
+		ramp3400	- amp ramps up in 3.4ms
+		ramp2000	- amp ramps up in 2.0ms
+		ramp1000	- amp ramps up in 1ms
+		ramp500		- amp ramps up in 500us
+		ramp250		- amp ramps up in 250us
+		ramp125		- amp ramps up in 125us
+		ramp100		- amp ramps up in 100us
+		ramp62		- amp ramps up in 62us
+		ramp50		- amp ramps up in 50us
+		ramp40		- amp ramps up in 40us
+		ramp31		- amp ramps up in 31us
+		ramp25		- amp ramps up in 25us
+		ramp20		- amp ramps up in 20us
+		ramp15		- amp ramps up in 15us
+		ramp12		- amp ramps up in 12us
+		ramp10		- amp ramps up in 10us
+	tx_start_condition
+		fifoLevel	- transmission starts, if fifo is filled to
+				  threshold level
+		fifoNotEmpty	- transmission starts, as soon as there is one
+				  byte in internal fifo
+	repetitions
+		This gives the option, to send a telegram multiple times. Default: 1
+
+packet format:
+	enable_preamble
+		optionOn	- a preamble will be automatically generated
+		optionOff	- no preamble will be generated
+	enable_sync
+		optionOn	- a sync word will be automatically added to
+				  the telegram after preamble
+		optionOff	- no sync word will be added
+		Attention: While possible to generate sync without preamble, the
+		receiver won't be able to detect the sync without preamble.
+	enable_length_byte
+		optionOn	- the length of the telegram will be automatically
+				  added to the telegram. It's part of the payload
+		optionOff	- no length information will be automatically added
+				  to the telegram.
+		Attention: For telegram length over 255 bytes, this option can't be used
+		Attention: should be used in combination with sync, only
+	enable_address_byte
+		optionOn	- the address byte will be automatically added to the
+				  telgram. It's part of the payload
+		optionOff	- the address byte will not be added to the telegram.
+		The address byte can be used for address filtering, so the receiver
+		will only receive telegrams with a given address byte.
+		Attention: should be used in combination with sync, only
+	enable_crc
+		optionOn	- an crc will be automatically calculated over the
+				  payload of the telegram and added to the telegram
+				  after payload.
+		optionOff	- no crc will be calculated
+	preamble_length
+		length of the preamble. Allowed values: 0...65536
+	sync_length
+		length of the sync word. Allowed values: 0...8
+	fixed_message_length
+		length of the payload of the telegram. Will override the length
+		given by the buffer, passed in with the write command. Will be
+		ignored if set to zero.
+	sync_pattern[8]
+		contains up to eight values, that are used as the sync pattern
+		on sync option
+	address_byte
+		one byte, used as address byte on address byte option.
+
+
+The rx configuration is transfered via struct pi433_rx_cfg, the parameterset for receiving. It is devided into two sections: rf parameters and packet format.
+
+rf params:
+	frequency
+		frequency used for transmission.
+		Allowed values: 433050000...434790000
+	bit_rate
+		bit rate used for transmission.
+		Allowed values: #####
+	dev_frequency
+		frequency deviation in case of FSK.
+		Allowed values: 600...500000
+	modulation
+		FSK - frequency shift key
+		OOK - on off key
+	rssi_threshold
+		threshold value for the signal strength on the receiver input.
+		If this value is exeeded, a reception cycle starts
+		Allowed values: 0...255
+	thresholdDecrement
+		in order to adapt to different levels of singnal strength, over
+		time the receiver gets more and more sensitive. This value
+		determs, how fast the sensitivity increases.
+		step_0_5db	- increase in 0,5dB steps
+		step_1_0db	- increase in 1 db steps
+		step_1_5db	- increase in 1,5dB steps
+		step_2_0db	- increase in 2 db steps
+		step_3_0db	- increase in 3 db steps
+		step_4_0db	- increase in 4 db steps
+		step_5_0db	- increase in 5 db steps
+		step_6_0db	- increase in 6 db steps
+	antennaImpedance
+		sets the electrical adoption of the antenna
+		fiftyOhm	- for antennas with an impedance of 50Ohm
+		twohundretOhm	- for antennas with an impedance of 200Ohm
+	lnaGain
+		sets the gain of the low noise amp
+		automatic	- lna gain is determed by an agc
+		max		- lna gain is set to maximum
+		maxMinus6	- lna gain is set to  6db below max
+		maxMinus12	- lna gain is set to 12db below max
+		maxMinus24	- lna gain is set to 24db below max
+		maxMinus36	- lna gain is set to 36db below max
+		maxMinus48	- lna gain is set to 48db below max
+	bw_mantisse
+		sets the bandwidth of the channel filter - part one: mantisse.
+		mantisse16	- mantisse is set to 16
+		mantisse20	- mantisse is set to 20
+		mantisse24	- mantisse is set to 24
+	bw_exponent
+		sets the bandwidth of the channel filter - part two: exponent.
+		Allowd values: 0...7
+	dagc;
+		operation mode of the digital automatic gain control
+		normalMode
+		improve
+		improve4LowModulationIndex
+
+ packet format:
+	enable_sync
+		optionOn  - sync detection is enabled. If configured sync pattern
+			    isn't found, telegram will be internally discarded
+		optionOff - sync detection is disabled.
+	enable_length_byte
+		optionOn   - First byte of payload will be used as length byte,
+			     regardless of the amount of bytes that were requested
+			     by the read request.
+		optionOff  - Number of bytes to be read will be set according to
+			     amount of bytes that were requested by the read request.
+		Attention: should be used in combination with sync, only
+	enable_address_filtering;
+		filteringOff		- no adress filtering will take place
+		nodeAddress		- all telegrams, not matching the node
+					  address will be internally discarded
+		nodeOrBroadcastAddress	- all telegrams, neither matching the
+					  node, nor the broadcast address will
+					  be internally discarded
+		Attention: Sync option must be enabled in order to use this feature
+	enable_crc
+		optionOn	- a crc will be calculated over the payload of
+				  the telegram, that was received. If the
+				  calculated crc doesn't match to two bytes,
+				  that follow the payload, the telegram will be
+				  internally discarded.
+		Attention: This option is only operational, if sync on and fixed length
+		or length byte is used
+	sync_length
+		Gives the length of the payload.
+		Attention: This setting must meet the setting of the transmitter,
+		if sync option is used.
+	fixed_message_length
+		Overrides the telegram length either given by the first byte of
+		payload or by the read request.
+	bytes_to_drop
+		gives the number of bytes, that will be dropped before transfering
+		data to the read buffer
+		This option is only usefull, if all packet helper are switched
+		off and the rf chip is used in raw receiving mode. This may be
+		needed, if a telegram of a third party device should be received,
+		using a protocol not compatible with the packet engine of the rf69 chip.
+	sync_pattern[8]
+		contains up to eight values, that are used as the sync pattern
+		on sync option.
+		This setting must meet the configuration of the transmitting device,
+		if sync option is enabled.
+	node_address
+		one byte, used as node address byte on address byte option.
+	broadcast_address
+		one byte, used as broadcast address byte on address byte option.
+
+
diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
new file mode 100644
index 0000000..61b4b4e
--- /dev/null
+++ b/drivers/staging/pi433/Kconfig
@@ -0,0 +1,16 @@
+config PI433
+        tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
+        default n
+        ---help---
+          This option allows you to enable support for the radio module Pi433.
+
+          Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi
+          or compatible. It extends the Raspberry Pi with the option, to
+          send and receive data in the 433MHz ISM band - for example to
+          communicate between two systems without using ethernet or bluetooth
+          or for control or read sockets, actors, sensors, widely available
+          for low price.
+
+          For details or the option to buy, please visit https://pi433.de/en.html
+
+          If in doubt, say N here, but saying yes most probably won't hurt
diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile
new file mode 100644
index 0000000..417f3e4
--- /dev/null
+++ b/drivers/staging/pi433/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PI433) += pi433.o
+
+pi433-objs := pi433_if.o rf69.o
diff --git a/drivers/staging/pi433/TODO b/drivers/staging/pi433/TODO
new file mode 100644
index 0000000..63a40bf
--- /dev/null
+++ b/drivers/staging/pi433/TODO
@@ -0,0 +1,5 @@
+* coding style does not fully comply with the kernel style guide.
+* still TODOs, annotated in the code
+* currently the code introduces new IOCTLs. I'm afraid this is a bad idea.
+  -> Replace this with another interface, hints are welcome!
+* Some missing data (marked with ###) needs to be added in the documentation
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
new file mode 100644
index 0000000..57edf91
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.c
@@ -0,0 +1,1315 @@
+/*
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+#endif
+
+#include "pi433_if.h"
+#include "rf69.h"
+
+
+#define N_PI433_MINORS			(1U << MINORBITS) /*32*/	/* ... up to 256 */
+#define MAX_MSG_SIZE			900	/* min: FIFO_SIZE! */
+#define MSG_FIFO_SIZE			65536   /* 65536 = 2^16  */
+#define NUM_DIO				2
+
+static dev_t pi433_dev;
+static DEFINE_IDR(pi433_idr);
+static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+
+static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
+
+/* tx config is instance specific
+	so with each open a new tx config struct is needed */
+/* rx config is device specific
+	so we have just one rx config, ebedded in device struct */
+struct pi433_device {
+	/* device handling related values */
+	dev_t			devt;
+	int			minor;
+	struct device		*dev;
+	struct cdev		*cdev;
+	struct spi_device	*spi;
+	unsigned		users;
+
+	/* irq related values */
+	struct gpio_desc	*gpiod[NUM_DIO];
+	int			irq_num[NUM_DIO];
+	u8			irq_state[NUM_DIO];
+
+	/* tx related values */
+	STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
+	struct mutex		tx_fifo_lock; // TODO: check, whether necessary or obsolete
+	struct task_struct	*tx_task_struct;
+	wait_queue_head_t	tx_wait_queue;
+	u8			free_in_fifo;
+
+	/* rx related values */
+	struct pi433_rx_cfg	rx_cfg;
+	u8			*rx_buffer;
+	unsigned int		rx_buffer_size;
+	u32			rx_bytes_to_drop;
+	u32			rx_bytes_dropped;
+	unsigned int		rx_position;
+	struct mutex		rx_lock;
+	wait_queue_head_t	rx_wait_queue;
+
+	/* fifo wait queue */
+	struct task_struct	*fifo_task_struct;
+	wait_queue_head_t	fifo_wait_queue;
+
+	/* flags */
+	bool			rx_active;
+	bool			tx_active;
+	bool			interrupt_rx_allowed;
+};
+
+struct pi433_instance {
+	struct pi433_device	*device;
+	struct pi433_tx_cfg	tx_cfg;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* macro for checked access of registers of radio module */
+#define SET_CHECKED(retval) \
+	if (retval < 0) \
+		return retval;
+
+/*-------------------------------------------------------------------------*/
+
+/* GPIO interrupt handlers */
+static irq_handler_t
+DIO0_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pi433_device *device = dev_id;
+
+	if      (device->irq_state[DIO0] == DIO_PacketSent)
+	{
+		device->free_in_fifo = FIFO_SIZE;
+		printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include KERN_ facility level
+		wake_up_interruptible(&device->fifo_wait_queue);
+	}
+	else if (device->irq_state[DIO0] == DIO_Rssi_DIO0)
+	{
+		printk("DIO0 irq: RSSI level over threshold\n");
+		wake_up_interruptible(&device->rx_wait_queue);
+	}
+	else if (device->irq_state[DIO0] == DIO_PayloadReady)
+	{
+		printk("DIO0 irq: PayloadReady\n");
+		device->free_in_fifo = 0;
+		wake_up_interruptible(&device->fifo_wait_queue);
+	}
+
+	return (irq_handler_t) IRQ_HANDLED;
+}
+
+static irq_handler_t
+DIO1_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pi433_device *device = dev_id;
+
+	if      (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1)
+	{
+		device->free_in_fifo = FIFO_SIZE;
+	}
+	else if (device->irq_state[DIO1] == DIO_FifoLevel)
+	{
+		if (device->rx_active)	device->free_in_fifo = FIFO_THRESHOLD - 1;
+		else			device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1;
+	}
+	printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO: printk() should include KERN_ facility level
+	wake_up_interruptible(&device->fifo_wait_queue);
+
+	return (irq_handler_t) IRQ_HANDLED;
+}
+
+static void *DIO_irq_handler[NUM_DIO] = {
+	DIO0_irq_handler,
+	DIO1_irq_handler
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
+{
+	int payload_length;
+
+	/* receiver config */
+	SET_CHECKED(rf69_set_frequency	(dev->spi, rx_cfg->frequency));
+	SET_CHECKED(rf69_set_bit_rate	(dev->spi, rx_cfg->bit_rate));
+	SET_CHECKED(rf69_set_modulation	(dev->spi, rx_cfg->modulation));
+	SET_CHECKED(rf69_set_antenna_impedance	 (dev->spi, rx_cfg->antenna_impedance));
+	SET_CHECKED(rf69_set_rssi_threshold	 (dev->spi, rx_cfg->rssi_threshold));
+	SET_CHECKED(rf69_set_ook_threshold_dec	 (dev->spi, rx_cfg->thresholdDecrement));
+	SET_CHECKED(rf69_set_bandwidth 		 (dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent));
+	SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent));
+	SET_CHECKED(rf69_set_dagc 		 (dev->spi, rx_cfg->dagc));
+
+	dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop;
+
+	/* packet config */
+	/* enable */
+	SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync));
+	if (rx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always));
+	}
+	SET_CHECKED(rf69_set_packet_format  (dev->spi, rx_cfg->enable_length_byte));
+	SET_CHECKED(rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering));
+	SET_CHECKED(rf69_set_crc_enable	    (dev->spi, rx_cfg->enable_crc));
+
+	/* lengths */
+	SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
+	if (rx_cfg->enable_length_byte == optionOn)
+	{
+		SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff));
+	}
+	else if (rx_cfg->fixed_message_length != 0)
+	{
+		payload_length = rx_cfg->fixed_message_length;
+		if (rx_cfg->enable_length_byte  == optionOn) payload_length++;
+		if (rx_cfg->enable_address_filtering != filteringOff) payload_length++;
+		SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
+	}
+
+	/* values */
+	if (rx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern));
+	}
+	if (rx_cfg->enable_address_filtering != filteringOff)
+	{
+		SET_CHECKED(rf69_set_node_address     (dev->spi, rx_cfg->node_address));
+		SET_CHECKED(rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address));
+	}
+
+	return 0;
+}
+
+static int
+rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
+{
+	SET_CHECKED(rf69_set_frequency	(dev->spi, tx_cfg->frequency));
+	SET_CHECKED(rf69_set_bit_rate	(dev->spi, tx_cfg->bit_rate));
+	SET_CHECKED(rf69_set_modulation	(dev->spi, tx_cfg->modulation));
+	SET_CHECKED(rf69_set_deviation	(dev->spi, tx_cfg->dev_frequency));
+	SET_CHECKED(rf69_set_pa_ramp	(dev->spi, tx_cfg->pa_ramp));
+	SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping));
+	SET_CHECKED(rf69_set_tx_start_condition(dev->spi, tx_cfg->tx_start_condition));
+
+	/* packet format enable */
+	if (tx_cfg->enable_preamble == optionOn)
+	{
+		SET_CHECKED(rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
+	}
+	SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
+	SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
+	SET_CHECKED(rf69_set_crc_enable	  (dev->spi, tx_cfg->enable_crc));
+
+	/* configure sync, if enabled */
+	if (tx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length));
+		SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern));
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pi433_start_rx(struct pi433_device *dev)
+{
+	int retval;
+
+	/* return without action, if no pending read request */
+	if (!dev->rx_active)
+		return 0;
+
+	/* setup for receiving */
+	retval = rf69_set_rx_cfg(dev, &dev->rx_cfg);
+	if (retval) return retval;
+
+	/* setup rssi irq */
+	SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0));
+	dev->irq_state[DIO0] = DIO_Rssi_DIO0;
+	irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+	/* setup fifo level interrupt */
+	SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD));
+	SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel));
+	dev->irq_state[DIO1] = DIO_FifoLevel;
+	irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING);
+
+	/* set module to receiving mode */
+	SET_CHECKED(rf69_set_mode(dev->spi, receive));
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int
+pi433_receive(void *data)
+{
+	struct pi433_device *dev = data;
+	struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */
+	int bytes_to_read, bytes_total;
+	int retval;
+
+	dev->interrupt_rx_allowed = false;
+
+	/* wait for any tx to finish */
+	dev_dbg(dev->dev,"rx: going to wait for any tx to finish");
+	retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
+	if(retval) /* wait was interrupted */
+	{
+		dev->interrupt_rx_allowed = true;
+		wake_up_interruptible(&dev->tx_wait_queue);
+		return retval;
+	}
+
+	/* prepare status vars */
+	dev->free_in_fifo = FIFO_SIZE;
+	dev->rx_position = 0;
+	dev->rx_bytes_dropped = 0;
+
+	/* setup radio module to listen for something "in the air" */
+	retval = pi433_start_rx(dev);
+	if (retval)
+		return retval;
+
+	/* now check RSSI, if low wait for getting high (RSSI interrupt) */
+	while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) )
+	{
+		/* allow tx to interrupt us while waiting for high RSSI */
+		dev->interrupt_rx_allowed = true;
+		wake_up_interruptible(&dev->tx_wait_queue);
+
+		/* wait for RSSI level to become high */
+		dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
+		retval = wait_event_interruptible(dev->rx_wait_queue,
+			                          rf69_get_flag(dev->spi,
+		                                                rssiExceededThreshold));
+		if (retval) goto abort; /* wait was interrupted */
+		dev->interrupt_rx_allowed = false;
+
+		/* cross check for ongoing tx */
+		if (!dev->tx_active) break;
+	}
+
+	/* configure payload ready irq */
+	SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady));
+	dev->irq_state[DIO0] = DIO_PayloadReady;
+	irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+	/* fixed or unlimited length? */
+	if (dev->rx_cfg.fixed_message_length != 0)
+	{
+		if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size)
+		{
+			retval = -1;
+			goto abort;
+		}
+		bytes_total = dev->rx_cfg.fixed_message_length;
+		dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total);
+	}
+	else
+	{
+		bytes_total = dev->rx_buffer_size;
+		dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total);
+	}
+
+	/* length byte enabled? */
+	if (dev->rx_cfg.enable_length_byte == optionOn)
+	{
+		retval = wait_event_interruptible(dev->fifo_wait_queue,
+						  dev->free_in_fifo < FIFO_SIZE);
+		if (retval) goto abort; /* wait was interrupted */
+
+		rf69_read_fifo(spi, (u8 *)&bytes_total, 1);
+		if (bytes_total > dev->rx_buffer_size)
+		{
+			retval = -1;
+			goto abort;
+		}
+		dev->free_in_fifo++;
+		dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total);
+	}
+
+	/* address byte enabled? */
+	if (dev->rx_cfg.enable_address_filtering != filteringOff)
+	{
+		u8 dummy;
+
+		bytes_total--;
+
+		retval = wait_event_interruptible(dev->fifo_wait_queue,
+						  dev->free_in_fifo < FIFO_SIZE);
+		if (retval) goto abort; /* wait was interrupted */
+
+		rf69_read_fifo(spi, &dummy, 1);
+		dev->free_in_fifo++;
+		dev_dbg(dev->dev, "rx: address byte stripped off");
+	}
+
+	/* get payload */
+	while (dev->rx_position < bytes_total)
+	{
+		if ( !rf69_get_flag(dev->spi, payloadReady) )
+		{
+			retval = wait_event_interruptible(dev->fifo_wait_queue,
+							  dev->free_in_fifo < FIFO_SIZE);
+			if (retval) goto abort; /* wait was interrupted */
+		}
+
+		/* need to drop bytes or acquire? */
+		if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+			bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+		else
+			bytes_to_read = bytes_total - dev->rx_position;
+
+
+		/* access the fifo */
+		if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo)
+			bytes_to_read = FIFO_SIZE - dev->free_in_fifo;
+		retval = rf69_read_fifo(spi,
+					&dev->rx_buffer[dev->rx_position],
+					bytes_to_read);
+		if (retval) goto abort; /* read failed */
+		dev->free_in_fifo += bytes_to_read;
+
+		/* adjust status vars */
+		if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+			dev->rx_bytes_dropped += bytes_to_read;
+		else
+			dev->rx_position += bytes_to_read;
+	}
+
+
+	/* rx done, wait was interrupted or error occured */
+abort:
+	dev->interrupt_rx_allowed = true;
+	SET_CHECKED(rf69_set_mode(dev->spi, standby));
+	wake_up_interruptible(&dev->tx_wait_queue);
+
+	if (retval)
+		return retval;
+	else
+		return bytes_total;
+}
+
+int
+pi433_tx_thread(void *data)
+{
+	struct pi433_device *device = data;
+	struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
+	struct pi433_tx_cfg tx_cfg;
+	u8     buffer[MAX_MSG_SIZE];
+	size_t size;
+	bool   rx_interrupted = false;
+	int    position, repetitions;
+	int    retval;
+
+	while (1)
+	{
+		/* wait for fifo to be populated or for request to terminate*/
+		dev_dbg(device->dev, "thread: going to wait for new messages");
+		wait_event_interruptible(device->tx_wait_queue,
+					 ( !kfifo_is_empty(&device->tx_fifo) ||
+					    kthread_should_stop() ));
+		if ( kthread_should_stop() )
+			return 0;
+
+		/* get data from fifo in the following order:
+		   - tx_cfg
+		   - size of message
+		   - message */
+		mutex_lock(&device->tx_fifo_lock);
+
+		retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
+		if (retval != sizeof(tx_cfg))
+		{
+			dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) );
+			mutex_unlock(&device->tx_fifo_lock);
+			continue;
+		}
+
+		retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
+		if (retval != sizeof(size_t))
+		{
+			dev_dbg(device->dev, "reading msg size from fifo failed: got %d, expected %d", retval, (unsigned int)sizeof(size_t) );
+			mutex_unlock(&device->tx_fifo_lock);
+			continue;
+		}
+
+		/* use fixed message length, if requested */
+		if (tx_cfg.fixed_message_length != 0)
+			size = tx_cfg.fixed_message_length;
+
+		/* increase size, if len byte is requested */
+		if (tx_cfg.enable_length_byte == optionOn)
+			size++;
+
+		/* increase size, if adr byte is requested */
+		if (tx_cfg.enable_address_byte == optionOn)
+			size++;
+
+		/* prime buffer */
+		memset(buffer, 0, size);
+		position = 0;
+
+		/* add length byte, if requested */
+		if (tx_cfg.enable_length_byte  == optionOn)
+			buffer[position++] = size-1; /* according to spec length byte itself must be excluded from the length calculation */
+
+		/* add adr byte, if requested */
+		if (tx_cfg.enable_address_byte == optionOn)
+			buffer[position++] = tx_cfg.address_byte;
+
+		/* finally get message data from fifo */
+		retval = kfifo_out(&device->tx_fifo, &buffer[position], sizeof(buffer)-position );
+		dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval);
+		mutex_unlock(&device->tx_fifo_lock);
+
+		/* if rx is active, we need to interrupt the waiting for
+		   incoming telegrams, to be able to send something.
+		   We are only allowed, if currently no reception takes
+		   place otherwise we need to  wait for the incoming telegram
+		   to finish */
+		wait_event_interruptible(device->tx_wait_queue,
+					 !device->rx_active ||
+					  device->interrupt_rx_allowed == true);
+
+		/* prevent race conditions
+		   irq will be reenabled after tx config is set */
+		disable_irq(device->irq_num[DIO0]);
+		device->tx_active = true;
+
+		if (device->rx_active && rx_interrupted == false)
+		{
+			/* rx is currently waiting for a telegram;
+			   we need to set the radio module to standby */
+			SET_CHECKED(rf69_set_mode(device->spi, standby));
+			rx_interrupted = true;
+		}
+
+		/* clear fifo, set fifo threshold, set payload length */
+		SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */
+		SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD));
+		if (tx_cfg.enable_length_byte == optionOn)
+		{
+			SET_CHECKED(rf69_set_payload_length(spi, size * tx_cfg.repetitions));
+		}
+		else
+		{
+			SET_CHECKED(rf69_set_payload_length(spi, 0));
+		}
+
+		/* configure the rf chip */
+		rf69_set_tx_cfg(device, &tx_cfg);
+
+		/* enable fifo level interrupt */
+		SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel));
+		device->irq_state[DIO1] = DIO_FifoLevel;
+		irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING);
+
+		/* enable packet sent interrupt */
+		SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent));
+		device->irq_state[DIO0] = DIO_PacketSent;
+		irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+		enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check */
+
+		/* enable transmission */
+		SET_CHECKED(rf69_set_mode(spi, transmit));
+
+		/* transfer this msg (and repetitions) to chip fifo */
+		device->free_in_fifo = FIFO_SIZE;
+		position = 0;
+		repetitions = tx_cfg.repetitions;
+		while( (repetitions > 0) && (size > position) )
+		{
+			if ( (size - position) > device->free_in_fifo)
+			{	/* msg to big for fifo - take a part */
+				int temp = device->free_in_fifo;
+				device->free_in_fifo = 0;
+				rf69_write_fifo(spi,
+				                &buffer[position],
+				                temp);
+				position +=temp;
+			}
+			else
+			{	/* msg fits into fifo - take all */
+				device->free_in_fifo -= size;
+				repetitions--;
+				rf69_write_fifo(spi,
+						&buffer[position],
+						(size - position) );
+				position = 0; /* reset for next repetition */
+			}
+
+			retval = wait_event_interruptible(device->fifo_wait_queue,
+							  device->free_in_fifo > 0);
+			if (retval) { printk("ABORT\n"); goto abort; }
+		}
+
+		/* we are done. Wait for packet to get sent */
+		dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be empty");
+		wait_event_interruptible(device->fifo_wait_queue,
+					 device->free_in_fifo == FIFO_SIZE ||
+					 kthread_should_stop() );
+		if ( kthread_should_stop() )	printk("ABORT\n");
+
+
+		/* STOP_TRANSMISSION */
+		dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.");
+		SET_CHECKED(rf69_set_mode(spi, standby));
+
+		/* everything sent? */
+		if ( kfifo_is_empty(&device->tx_fifo) )
+		{
+abort:
+			if (rx_interrupted)
+			{
+				rx_interrupted = false;
+				pi433_start_rx(device);
+			}
+			device->tx_active = false;
+			wake_up_interruptible(&device->rx_wait_queue);
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t
+pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	unsigned int		bytes_received;
+	ssize_t			retval;
+
+	/* check, whether internal buffer is big enough for requested size */
+	if (size > MAX_MSG_SIZE)
+		return -EMSGSIZE;
+
+	instance = filp->private_data;
+	device = instance->device;
+
+	/* just one read request at a time */
+	mutex_lock(&device->rx_lock);
+	if (device->rx_active)
+	{
+		mutex_unlock(&device->rx_lock);
+		return -EAGAIN;
+	}
+	else
+	{
+		device->rx_active = true;
+		mutex_unlock(&device->rx_lock);
+	}
+
+	/* start receiving */
+	/* will block until something was received*/
+	device->rx_buffer_size = size;
+	bytes_received = pi433_receive(device);
+
+	/* release rx */
+	mutex_lock(&device->rx_lock);
+	device->rx_active = false;
+	mutex_unlock(&device->rx_lock);
+
+	/* if read was successful copy to user space*/
+	if (bytes_received >= 0)
+	{
+		retval = copy_to_user(buf, device->rx_buffer, bytes_received);
+		if (retval)
+			return retval;
+	}
+
+	return bytes_received;
+}
+
+
+static ssize_t
+pi433_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	int                     copied, retval;
+
+	instance = filp->private_data;
+	device = instance->device;
+
+	/* check, whether internal buffer (tx thread) is big enough for requested size */
+	if (count > MAX_MSG_SIZE)
+		return -EMSGSIZE;
+
+	/* write the following sequence into fifo:
+	   - tx_cfg
+	   - size of message
+	   - message */
+	mutex_lock(&device->tx_fifo_lock);
+	retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg));
+	if ( retval != sizeof(instance->tx_cfg) )
+		goto abort;
+
+	retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t));
+	if ( retval != sizeof(size_t) )
+		goto abort;
+
+	retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied);
+	if (retval || copied != count)
+		goto abort;
+
+	mutex_unlock(&device->tx_fifo_lock);
+
+	/* start transfer */
+	wake_up_interruptible(&device->tx_wait_queue);
+	dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied);
+
+	return 0;
+
+abort:
+	dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
+	kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to discard already stored, valid entries
+	mutex_unlock(&device->tx_fifo_lock);
+	return -EAGAIN;
+}
+
+
+static long
+pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int			err = 0;
+	int			retval = 0;
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	u32			tmp;
+
+	/* Check type and command number */
+	if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
+		return -ENOTTY;
+
+	/* Check access direction once here; don't repeat below.
+	 * IOC_DIR is from the user perspective, while access_ok is
+	 * from the kernel perspective; so they look reversed.
+	 */
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok(VERIFY_WRITE,
+				 (void __user *)arg,
+				 _IOC_SIZE(cmd));
+
+	if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok(VERIFY_READ,
+				 (void __user *)arg,
+				 _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	/* TODO? guard against device removal before, or while,
+	 * we issue this ioctl. --> device_get()
+	 */
+	instance = filp->private_data;
+	device = instance->device;
+
+	if (device == NULL)
+		return -ESHUTDOWN;
+
+	switch (cmd) {
+	case PI433_IOC_RD_TX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+		{
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_to_user((void __user *)arg,
+				    &instance->tx_cfg,
+				    tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+	case PI433_IOC_WR_TX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+		{
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_from_user(&instance->tx_cfg,
+				     (void __user *)arg,
+				     tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+
+	case PI433_IOC_RD_RX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_to_user((void __user *)arg,
+				   &device->rx_cfg,
+				   tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+	case PI433_IOC_WR_RX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		mutex_lock(&device->rx_lock);
+
+		/* during pendig read request, change of config not allowed */
+		if (device->rx_active) {
+			retval = -EAGAIN;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+			retval = -EINVAL;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		if (__copy_from_user(&device->rx_cfg,
+				     (void __user *)arg,
+				     tmp))
+		{
+			retval = -EFAULT;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		mutex_unlock(&device->rx_lock);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define pi433_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_open(struct inode *inode, struct file *filp)
+{
+	struct pi433_device	*device;
+	struct pi433_instance	*instance;
+
+	mutex_lock(&minor_lock);
+	device = idr_find(&pi433_idr, iminor(inode));
+
+	mutex_unlock(&minor_lock);
+	if (!device) {
+		dev_dbg(device->dev, "device: minor %d unknown.\n", iminor(inode));
+		return -ENODEV;
+	}
+
+	if (!device->rx_buffer) {
+		device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL);
+		if (!device->rx_buffer)
+		{
+			dev_dbg(device->dev, "open/ENOMEM\n");
+			return -ENOMEM;
+		}
+	}
+
+	device->users++;
+	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+	if (!instance)
+	{
+		kfree(device->rx_buffer);
+		device->rx_buffer = NULL;
+		return -ENOMEM;
+	}
+
+	/* setup instance data*/
+	instance->device = device;
+	instance->tx_cfg.bit_rate = 4711;
+	// TODO: fill instance->tx_cfg;
+
+	/* instance data as context */
+	filp->private_data = instance;
+	nonseekable_open(inode, filp);
+
+	return 0;
+}
+
+static int pi433_release(struct inode *inode, struct file *filp)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+
+	instance = filp->private_data;
+	device = instance->device;
+	kfree(instance);
+	filp->private_data = NULL;
+
+	/* last close? */
+	device->users--;
+
+	if (!device->users) {
+		kfree(device->rx_buffer);
+		device->rx_buffer = NULL;
+		if (device->spi == NULL)
+			kfree(device);
+	}
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int setup_GPIOs(struct pi433_device *device)
+{
+	char 	name[5];
+	int	retval;
+	int	i;
+
+	for (i=0; i<NUM_DIO; i++)
+	{
+		/* "construct" name and get the gpio descriptor */
+		snprintf(name, sizeof(name), "DIO%d", i);
+		device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+
+		if (device->gpiod[i] == ERR_PTR(-ENOENT))
+		{
+			dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name);
+			continue;
+		}
+
+		if (device->gpiod[i] == ERR_PTR(-EBUSY))
+			dev_dbg(&device->spi->dev, "%s is busy.", name);
+
+		if ( IS_ERR(device->gpiod[i]) )
+		{
+			retval = PTR_ERR(device->gpiod[i]);
+			/* release already allocated gpios */
+			for (i--; i>=0; i--)
+			{
+				free_irq(device->irq_num[i], device);
+				gpiod_put(device->gpiod[i]);
+			}
+			return retval;
+		}
+
+
+		/* configure the pin */
+		gpiod_unexport(device->gpiod[i]);
+		retval = gpiod_direction_input(device->gpiod[i]);
+		if (retval) return retval;
+
+
+		/* configure irq */
+		device->irq_num[i] = gpiod_to_irq(device->gpiod[i]);
+		if (device->irq_num[i] < 0)
+		{
+			device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc *)device->irq_num[i];
+			return device->irq_num[i];
+		}
+		retval = request_irq(device->irq_num[i],
+				     DIO_irq_handler[i],
+				     0, /* flags */
+				     name,
+				     device);
+
+		if (retval)
+			return retval;
+
+		dev_dbg(&device->spi->dev, "%s succesfully configured", name);
+	}
+
+	return 0;
+}
+
+static void free_GPIOs(struct pi433_device *device)
+{
+	int i;
+
+	for (i=0; i<NUM_DIO; i++)
+	{
+		/* check if gpiod is valid */
+		if ( IS_ERR(device->gpiod[i]) )
+			continue;
+
+		free_irq(device->irq_num[i], device);
+		gpiod_put(device->gpiod[i]);
+	}
+	return;
+}
+
+static int pi433_get_minor(struct pi433_device *device)
+{
+	int retval = -ENOMEM;
+
+	mutex_lock(&minor_lock);
+	retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL);
+	if (retval >= 0) {
+		device->minor = retval;
+		retval = 0;
+	} else if (retval == -ENOSPC) {
+		dev_err(device->dev, "too many pi433 devices\n");
+		retval = -EINVAL;
+	}
+	mutex_unlock(&minor_lock);
+	return retval;
+}
+
+static void pi433_free_minor(struct pi433_device *dev)
+{
+	mutex_lock(&minor_lock);
+	idr_remove(&pi433_idr, dev->minor);
+	mutex_unlock(&minor_lock);
+}
+/*-------------------------------------------------------------------------*/
+
+static const struct file_operations pi433_fops = {
+	.owner =	THIS_MODULE,
+	/* REVISIT switch to aio primitives, so that userspace
+	 * gets more complete API coverage.  It'll simplify things
+	 * too, except for the locking.
+	 */
+	.write =	pi433_write,
+	.read =		pi433_read,
+	.unlocked_ioctl = pi433_ioctl,
+	.compat_ioctl = pi433_compat_ioctl,
+	.open =		pi433_open,
+	.release =	pi433_release,
+	.llseek =	no_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_probe(struct spi_device *spi)
+{
+	struct pi433_device	*device;
+	int			retval;
+
+	/* setup spi parameters */
+	spi->mode = 0x00;
+	spi->bits_per_word = 8;
+	/* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay */
+
+	retval = spi_setup(spi);
+	if (retval)
+	{
+		dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
+		return retval;
+	}
+	else
+	{
+		dev_dbg(&spi->dev,
+			"spi interface setup: mode 0x%2x, %d bits per word, %dhz max speed",
+			spi->mode, spi->bits_per_word, spi->max_speed_hz);
+	}
+
+	/* Ping the chip by reading the version register */
+	retval = spi_w8r8(spi, 0x10);
+	if (retval < 0)
+		return retval;
+
+	switch(retval)
+	{
+		case 0x24:
+			dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
+			break;
+		default:
+			dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
+			return -ENODEV;
+	}
+
+	/* Allocate driver data */
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	/* Initialize the driver data */
+	device->spi = spi;
+	device->rx_active = false;
+	device->tx_active = false;
+	device->interrupt_rx_allowed = false;
+
+	/* init wait queues */
+	init_waitqueue_head(&device->tx_wait_queue);
+	init_waitqueue_head(&device->rx_wait_queue);
+	init_waitqueue_head(&device->fifo_wait_queue);
+
+	/* init fifo */
+	INIT_KFIFO(device->tx_fifo);
+
+	/* init mutexes and locks */
+	mutex_init(&device->tx_fifo_lock);
+	mutex_init(&device->rx_lock);
+
+	/* setup GPIO (including irq_handler) for the different DIOs */
+	retval = setup_GPIOs(device);
+	if (retval)
+	{
+		dev_dbg(&spi->dev, "setup of GPIOs failed");
+		goto GPIO_failed;
+	}
+
+	/* setup the radio module */
+	SET_CHECKED(rf69_set_mode		(spi, standby));
+	SET_CHECKED(rf69_set_data_mode		(spi, packet));
+	SET_CHECKED(rf69_set_amplifier_0	(spi, optionOn));
+	SET_CHECKED(rf69_set_amplifier_1	(spi, optionOff));
+	SET_CHECKED(rf69_set_amplifier_2	(spi, optionOff));
+	SET_CHECKED(rf69_set_output_power_level	(spi, 13));
+	SET_CHECKED(rf69_set_antenna_impedance	(spi, fiftyOhm));
+
+	/* start tx thread */
+	device->tx_task_struct = kthread_run(pi433_tx_thread,
+					     device,
+					     "pi433_tx_task");
+	if (device->tx_task_struct < 0)
+	{
+		dev_dbg(device->dev, "start of send thread failed");
+		goto send_thread_failed;
+	}
+
+	/* determ minor number */
+	retval = pi433_get_minor(device);
+	if (retval)
+	{
+		dev_dbg(device->dev, "get of minor number failed");
+		goto minor_failed;
+	}
+
+	/* create device */
+	device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
+	device->dev = device_create(pi433_class,
+				    &spi->dev,
+				    device->devt,
+				    device,
+				    "pi433");
+	if (IS_ERR(device->dev)) {
+		pr_err("pi433: device register failed\n");
+		retval = PTR_ERR(device->dev);
+		goto device_create_failed;
+	}
+	else {
+		dev_dbg(device->dev,
+			"created device for major %d, minor %d\n",
+			MAJOR(pi433_dev),
+			device->minor);
+	}
+
+	/* create cdev */
+	device->cdev = cdev_alloc();
+	device->cdev->owner = THIS_MODULE;
+	cdev_init(device->cdev, &pi433_fops);
+	retval = cdev_add(device->cdev, device->devt, 1);
+	if (retval)
+	{
+		dev_dbg(device->dev, "register of cdev failed");
+		goto cdev_failed;
+	}
+
+	/* spi setup */
+	spi_set_drvdata(spi, device);
+
+	return 0;
+
+cdev_failed:
+	device_destroy(pi433_class, device->devt);
+device_create_failed:
+	pi433_free_minor(device);
+minor_failed:
+	kthread_stop(device->tx_task_struct);
+send_thread_failed:
+	free_GPIOs(device);
+GPIO_failed:
+	kfree(device);
+
+	return retval;
+}
+
+static int pi433_remove(struct spi_device *spi)
+{
+	struct pi433_device	*device = spi_get_drvdata(spi);
+
+	/* free GPIOs */
+	free_GPIOs(device);
+
+	/* make sure ops on existing fds can abort cleanly */
+	device->spi = NULL;
+
+	kthread_stop(device->tx_task_struct);
+
+	device_destroy(pi433_class, device->devt);
+
+	cdev_del(device->cdev);
+
+	pi433_free_minor(device);
+
+	if (device->users == 0)
+		kfree(device);
+
+	return 0;
+}
+
+static const struct of_device_id pi433_dt_ids[] = {
+	{ .compatible = "Smarthome-Wolf,pi433" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, pi433_dt_ids);
+
+static struct spi_driver pi433_spi_driver = {
+	.driver = {
+		.name =		"pi433",
+		.owner =	THIS_MODULE,
+		.of_match_table = of_match_ptr(pi433_dt_ids),
+	},
+	.probe =	pi433_probe,
+	.remove =	pi433_remove,
+
+	/* NOTE:  suspend/resume methods are not necessary here.
+	 * We don't do anything except pass the requests to/from
+	 * the underlying controller.  The refrigerator handles
+	 * most issues; the controller driver handles the rest.
+	 */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init pi433_init(void)
+{
+	int status;
+
+	/* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't
+           work stable - risk of buffer overflow */
+	if (MAX_MSG_SIZE < FIFO_SIZE)
+		return -EINVAL;
+
+	/* Claim device numbers.  Then register a class
+	 * that will key udev/mdev to add/remove /dev nodes.  Last, register
+	 * Last, register the driver which manages those device numbers.
+	 */
+	status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/);
+	if (status < 0)
+		return status;
+
+	pi433_class = class_create(THIS_MODULE, "pi433");
+	if (IS_ERR(pi433_class))
+	{
+		unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+		return PTR_ERR(pi433_class);
+	}
+
+	status = spi_register_driver(&pi433_spi_driver);
+	if (status < 0)
+	{
+		class_destroy(pi433_class);
+		unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+	}
+
+	return status;
+}
+
+module_init(pi433_init);
+
+static void __exit pi433_exit(void)
+{
+	spi_unregister_driver(&pi433_spi_driver);
+	class_destroy(pi433_class);
+	unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+}
+module_exit(pi433_exit);
+
+MODULE_AUTHOR("Marcus Wolf, <linux@wolf-entwicklungen.de>");
+MODULE_DESCRIPTION("Driver for Pi433");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:pi433");
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
new file mode 100644
index 0000000..e6ed3cd
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.h
@@ -0,0 +1,152 @@
+/*
+ * include/linux/TODO
+ *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR 	0
+struct pi433_tx_cfg
+{
+	__u32			frequency;
+	__u16			bit_rate;
+	__u32			dev_frequency;
+	enum modulation		modulation;
+	enum modShaping		modShaping;
+
+	enum paRamp		pa_ramp;
+
+	enum txStartCondition	tx_start_condition;
+
+	__u16			repetitions;
+
+
+	/* packet format */
+	enum optionOnOff	enable_preamble;
+	enum optionOnOff	enable_sync;
+	enum optionOnOff	enable_length_byte;
+	enum optionOnOff	enable_address_byte;
+	enum optionOnOff	enable_crc;
+
+	__u16			preamble_length;
+	__u8			sync_length;
+	__u8			fixed_message_length;
+
+	__u8			sync_pattern[8];
+	__u8			address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR 	1
+struct pi433_rx_cfg {
+	__u32			frequency;
+	__u16			bit_rate;
+	__u32			dev_frequency;
+
+	enum modulation		modulation;
+
+	__u8			rssi_threshold;
+	enum thresholdDecrement	thresholdDecrement;
+	enum antennaImpedance	antenna_impedance;
+	enum lnaGain		lna_gain;
+	enum mantisse		bw_mantisse;	/* normal: 0x50 */
+	__u8			bw_exponent;	/* during AFC: 0x8b */
+	enum dagc		dagc;
+
+
+
+	/* packet format */
+	enum optionOnOff	enable_sync;
+	enum optionOnOff	enable_length_byte;	  /* should be used in combination with sync, only */
+	enum addressFiltering	enable_address_filtering; /* operational with sync, only */
+	enum optionOnOff	enable_crc;		  /* only operational, if sync on and fixed length or length byte is used */
+
+	__u8			sync_length;
+	__u8			fixed_message_length;
+	__u32			bytes_to_drop;
+
+	__u8			sync_pattern[8];
+	__u8			node_address;
+	__u8			broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC			'r'
+
+#define PI433_IOC_RD_TX_CFG	_IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG	_IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG	_IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG	_IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
new file mode 100644
index 0000000..b6bc45b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.c
@@ -0,0 +1,982 @@
+/*
+ * abstraction of the spi interface of HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* enable prosa debug info */
+#undef DEBUG
+/* enable print of values on reg access */
+#undef DEBUG_VALUES
+/* enable print of values on fifo access */
+#undef DEBUG_FIFO_ACCESS
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include "rf69.h"
+#include "rf69_registers.h"
+
+#define F_OSC	  32000000 /* in Hz */
+#define FIFO_SIZE 66 	   /* in byte */
+
+/*-------------------------------------------------------------------------*/
+
+#define READ_REG(x)	rf69_read_reg (spi, x)
+#define WRITE_REG(x,y)	rf69_write_reg(spi, x, y)
+#define INVALID_PARAM \
+	{ \
+		dev_dbg(&spi->dev, "set: illegal input param"); \
+		return -EINVAL; \
+	}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: mode");
+	#endif
+
+	switch (mode){
+	case transmit:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT);
+	case receive:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE);
+	case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER);
+	case standby:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY);
+	case mode_sleep:  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP);
+	default:	  INVALID_PARAM;
+	}
+
+	// we are using packet mode, so this check is not really needed
+	// but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode
+	//while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
+
+}
+
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: data mode");
+	#endif
+
+	switch (dataMode) {
+	case packet:		return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET);
+	case continuous:	return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS);
+	case continuousNoSync:  return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS_NOSYNC);
+	default:		INVALID_PARAM;
+	}
+}
+
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: modulation");
+	#endif
+
+	switch (modulation) {
+	case OOK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK);
+	case FSK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK);
+	default:    INVALID_PARAM;
+	}
+}
+
+enum modulation rf69_get_modulation(struct spi_device *spi)
+{
+	u8 currentValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: mode");
+	#endif
+
+	currentValue = READ_REG(REG_DATAMODUL);
+
+	switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3)  // TODO improvement: change 3 to define
+	{
+	case DATAMODUL_MODULATION_TYPE_OOK: return OOK;
+	case DATAMODUL_MODULATION_TYPE_FSK: return FSK;
+	default:			    return undefined;
+	}
+}
+
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: mod shaping");
+	#endif
+
+	if (rf69_get_modulation(spi) == FSK)
+	{
+		switch (modShaping) {
+		case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE);
+		case shaping1_0: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_1_0);
+		case shaping0_5: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_3);
+		case shaping0_3: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_5);
+		default:	 INVALID_PARAM;
+		}
+	}
+	else
+	{
+		switch (modShaping) {
+		case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE);
+		case shapingBR:	 return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_BR);
+		case shaping2BR: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_2BR);
+		default:	 INVALID_PARAM;
+		}
+	}
+}
+
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+{
+	int retval;
+	u32 bitRate_min;
+	u32 bitRate_reg;
+	u8 msb;
+	u8 lsb;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: bit rate");
+	#endif
+
+	// check input value
+	bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
+	if (bitRate < bitRate_min)
+	{
+		dev_dbg(&spi->dev, "setBitRate: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculate reg settings
+	bitRate_reg = (F_OSC / bitRate);
+
+	msb = (bitRate_reg&0xff00)   >>  8;
+	lsb = (bitRate_reg&0xff);
+
+	// transmit to RF 69
+	retval = WRITE_REG(REG_BITRATE_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_BITRATE_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_deviation(struct spi_device *spi, u32 deviation)
+{
+	int retval;
+//	u32 f_max; TODO: Abhängigkeit von Bitrate beachten!!
+	u64 f_reg;
+	u64 f_step;
+	u8 msb;
+	u8 lsb;
+	u64 factor = 1000000; // to improve precision of calculation
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: deviation");
+	#endif
+
+	if (deviation < 600 || deviation > 500000) //TODO: Abhängigkeit von Bitrate beachten!!
+	{
+		dev_dbg(&spi->dev, "set_deviation: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculat f step
+	f_step = F_OSC * factor;
+	do_div(f_step, 524288); //  524288 = 2^19
+
+	// calculate register settings
+	f_reg = deviation * factor;
+	do_div(f_reg  , f_step);
+
+	msb = (f_reg&0xff00)   >>  8;
+	lsb = (f_reg&0xff);
+
+	// check msb
+	if (msb & !FDEVMASB_MASK)
+	{
+		dev_dbg(&spi->dev, "set_deviation: err in calc of msb");
+		INVALID_PARAM;
+	}
+
+	// write to chip
+	retval = WRITE_REG(REG_FDEV_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FDEV_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_frequency(struct spi_device *spi, u32 frequency)
+{
+	int retval;
+	u32 f_max;
+	u64 f_reg;
+	u64 f_step;
+	u8 msb;
+	u8 mid;
+	u8 lsb;
+	u64 factor = 1000000; // to improve precision of calculation
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: frequency");
+	#endif
+
+	// calculat f step
+	f_step = F_OSC * factor;
+	do_div(f_step, 524288); //  524288 = 2^19
+
+	// check input value
+	f_max = f_step * 8388608 / factor;
+	if (frequency > f_max)
+	{
+		dev_dbg(&spi->dev, "setFrequency: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculate reg settings
+	f_reg = frequency * factor;
+	do_div(f_reg  , f_step);
+
+	msb = (f_reg&0xff0000) >> 16;
+	mid = (f_reg&0xff00)   >>  8;
+	lsb = (f_reg&0xff);
+
+	// write to chip
+	retval = WRITE_REG(REG_FRF_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FRF_MID, mid);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FRF_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #0");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA0) );
+	case optionOff:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA0) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #1");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA1) );
+	case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA1) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #2");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA2) );
+	case optionOff:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA2) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: power level");
+	#endif
+
+	powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting
+
+	// check input value
+	if (powerLevel > 0x1f)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_OUTPUT_POWER) | powerLevel);
+}
+
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: pa ramp");
+	#endif
+
+	switch(paRamp) {
+	case ramp3400:	return WRITE_REG(REG_PARAMP, PARAMP_3400);
+	case ramp2000:	return WRITE_REG(REG_PARAMP, PARAMP_2000);
+	case ramp1000:	return WRITE_REG(REG_PARAMP, PARAMP_1000);
+	case ramp500:	return WRITE_REG(REG_PARAMP, PARAMP_500);
+	case ramp250:	return WRITE_REG(REG_PARAMP, PARAMP_250);
+	case ramp125:	return WRITE_REG(REG_PARAMP, PARAMP_125);
+	case ramp100:	return WRITE_REG(REG_PARAMP, PARAMP_100);
+	case ramp62:	return WRITE_REG(REG_PARAMP, PARAMP_62);
+	case ramp50:	return WRITE_REG(REG_PARAMP, PARAMP_50);
+	case ramp40:	return WRITE_REG(REG_PARAMP, PARAMP_40);
+	case ramp31:	return WRITE_REG(REG_PARAMP, PARAMP_31);
+	case ramp25:	return WRITE_REG(REG_PARAMP, PARAMP_25);
+	case ramp20:	return WRITE_REG(REG_PARAMP, PARAMP_20);
+	case ramp15:	return WRITE_REG(REG_PARAMP, PARAMP_15);
+	case ramp12:	return WRITE_REG(REG_PARAMP, PARAMP_12);
+	case ramp10:	return WRITE_REG(REG_PARAMP, PARAMP_10);
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: antenna impedance");
+	#endif
+
+	switch(antennaImpedance) {
+	case fiftyOhm:	    return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) & ~MASK_LNA_ZIN) );
+	case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) |  MASK_LNA_ZIN) );
+	default:	    INVALID_PARAM;
+	}
+}
+
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: lna gain");
+	#endif
+
+	switch(lnaGain) {
+	case automatic:	 return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_AUTO) );
+	case max:	 return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX) );
+	case maxMinus6:  return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) );
+	case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) );
+	case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) );
+	case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) );
+	case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) );
+	default:	 INVALID_PARAM;
+	}
+}
+
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi)
+{
+	u8 currentValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: lna gain");
+	#endif
+
+	currentValue = READ_REG(REG_LNA);
+
+	switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3)  // improvement: change 3 to define
+	{
+	case LNA_GAIN_AUTO:	    return automatic;
+	case LNA_GAIN_MAX:	    return max;
+	case LNA_GAIN_MAX_MINUS_6:  return maxMinus6;
+	case LNA_GAIN_MAX_MINUS_12: return maxMinus12;
+	case LNA_GAIN_MAX_MINUS_24: return maxMinus24;
+	case LNA_GAIN_MAX_MINUS_36: return maxMinus36;
+	case LNA_GAIN_MAX_MINUS_48: return maxMinus48;
+	default:		    return undefined;
+	}
+}
+
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum dccPercent dccPercent)
+{
+	switch (dccPercent) {
+	case dcc16Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) );
+	case dcc8Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) );
+	case dcc4Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) );
+	case dcc2Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) );
+	case dcc1Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) );
+	case dcc0_5Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) );
+	case dcc0_25Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) );
+	case dcc0_125Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) );
+	default:		INVALID_PARAM;
+	}
+}
+
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: cut off freq");
+	#endif
+
+	return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent);
+}
+
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: cut off freq during afc");
+	#endif
+
+	return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent);
+}
+
+int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse mantisse, u8 exponent)
+{
+	u8 newValue;
+
+	// check value for mantisse and exponent
+	if (exponent > 7)   INVALID_PARAM;
+	if ( (mantisse!=mantisse16) &&
+	     (mantisse!=mantisse20) &&
+             (mantisse!=mantisse24) ) INVALID_PARAM;
+
+	// read old value
+	newValue = READ_REG(reg);
+
+	// "delete" mantisse and exponent = just keep the DCC setting
+	newValue = newValue & MASK_BW_DCC_FREQ;
+
+	// add new mantisse
+	switch(mantisse) {
+	case mantisse16: newValue = newValue | BW_MANT_16;	break;
+	case mantisse20: newValue = newValue | BW_MANT_20;	break;
+	case mantisse24: newValue = newValue | BW_MANT_24;	break;
+	}
+
+	// add new exponent
+	newValue = newValue | exponent;
+
+	// write back
+	return WRITE_REG(reg, newValue);
+}
+
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: band width");
+	#endif
+
+	return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent);
+}
+
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: band width during afc");
+	#endif
+
+	return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
+}
+
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold type");
+	#endif
+
+	switch (thresholdType)
+	{
+	case fixed:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) );
+	case peak:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) );
+	case average:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold step");
+	#endif
+
+	switch (thresholdStep) {
+	case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) );
+	case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) );
+	case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) );
+	case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) );
+	case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) );
+	case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) );
+	case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) );
+	case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) );
+	default:	 INVALID_PARAM;
+	}
+}
+
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold decrement");
+	#endif
+
+	switch (thresholdDecrement) {
+	case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) );
+	case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) );
+	case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) );
+	case dec_once:	   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) );
+	case dec_twice:	   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) );
+	case dec_4times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) );
+	case dec_8times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) );
+	case dec_16times:  return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) );
+	default:	   INVALID_PARAM;
+	}
+}
+
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+{
+	u8 mask;
+	u8 shift;
+	u8 regaddr;
+	u8 regValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: DIO mapping");
+	#endif
+
+	// check DIO number
+	if (DIONumber > 5) INVALID_PARAM;
+
+	switch (DIONumber) {
+	case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break;
+	case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break;
+	case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break;
+	case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break;
+	case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break;
+	case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break;
+	}
+
+	// read reg
+	regValue=READ_REG(regaddr);
+	// delete old value
+	regValue = regValue & ~mask;
+	// add new value
+	regValue = regValue | value << shift;
+	// write back
+	return WRITE_REG(regaddr,regValue);
+}
+
+bool rf69_get_flag(struct spi_device *spi, enum flag flag)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: flag");
+	#endif
+
+	switch(flag) {
+	case modeSwitchCompleted:     return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_MODE_READY);
+	case readyToReceive:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RX_READY);
+	case readyToSend:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TX_READY);
+	case pllLocked:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_PLL_LOCK);
+	case rssiExceededThreshold:   return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI);
+	case timeout:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TIMEOUT);
+	case automode:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_AUTOMODE);
+	case syncAddressMatch:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+	case fifoFull:		      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_FULL);
+/*	case fifoNotEmpty:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */
+	case fifoEmpty:		      return !(READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY);
+	case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_LEVEL);
+	case fifoOverrun:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_OVERRUN);
+	case packetSent:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PACKET_SENT);
+	case payloadReady:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PAYLOAD_READY);
+	case crcOk:		      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_CRC_OK);
+	case batteryLow:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_LOW_BAT);
+	default:		      return false;
+	}
+}
+
+int rf69_reset_flag(struct spi_device *spi, enum flag flag)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "reset: flag");
+	#endif
+
+	switch(flag) {
+	case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_RSSI);
+	case syncAddressMatch:	    return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+	case fifoOverrun:	    return WRITE_REG(REG_IRQFLAGS2, MASK_IRQFLAGS2_FIFO_OVERRUN);
+	default:		    INVALID_PARAM;
+	}
+}
+
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: rssi threshold");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RSSITHRESH, threshold);
+}
+
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: start timeout");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RXTIMEOUT1, timeout);
+}
+
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: rssi timeout");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RXTIMEOUT2, timeout);
+}
+
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+{
+	int retval;
+	u8 msb, lsb;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: preample length");
+	#endif
+
+	/* no value check needed - u16 exactly matches register size */
+
+	/* calculate reg settings */
+	msb = (preambleLength&0xff00)   >>  8;
+	lsb = (preambleLength&0xff);
+
+	/* transmit to chip */
+	retval = WRITE_REG(REG_PREAMBLE_MSB, msb);
+	if (retval) return retval;
+	retval = WRITE_REG(REG_PREAMBLE_LSB, lsb);
+
+	return retval;
+}
+
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync enable");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_SYNC_ON) );
+	case optionOff:	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: fifo fill condition");
+	#endif
+
+	switch(fifoFillCondition) {
+	case always:		 return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+	case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+	default:		 INVALID_PARAM;
+	}
+}
+
+int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync size");
+	#endif
+
+	// check input value
+	if (syncSize > 0x07)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) );
+}
+
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync tolerance");
+	#endif
+
+	// check input value
+	if (syncTolerance > 0x07)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance);
+}
+
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+{
+	int retval = 0;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync values");
+	#endif
+
+	retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]);
+	retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]);
+	retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]);
+	retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]);
+	retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]);
+	retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]);
+	retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]);
+	retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]);
+
+	return retval;
+}
+
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat packetFormat)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: packet format");
+	#endif
+
+	switch(packetFormat) {
+	case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+	case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+	default:	      INVALID_PARAM;
+	}
+}
+
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: crc enable");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_CRC_ON) );
+	case optionOff:	return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: address filtering");
+	#endif
+
+	switch (addressFiltering) {
+	case filteringOff:	     return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_OFF) );
+	case nodeAddress:	     return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODE) );
+	case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) );
+	default:		     INVALID_PARAM;
+	}
+}
+
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: payload length");
+	#endif
+
+	return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength);
+}
+
+u8  rf69_get_payload_length(struct spi_device *spi)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: payload length");
+	#endif
+
+	return (u8) READ_REG(REG_PAYLOAD_LENGTH);
+}
+
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: node address");
+	#endif
+
+	return WRITE_REG(REG_NODEADRS, nodeAddress);
+}
+
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: broadcast address");
+	#endif
+
+	return WRITE_REG(REG_BROADCASTADRS, broadcastAddress);
+}
+
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: start condition");
+	#endif
+
+	switch(txStartCondition) {
+	case fifoLevel:	   return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) );
+	case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) |  MASK_FIFO_THRESH_TXSTART) );
+	default:	   INVALID_PARAM;
+	}
+}
+
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
+{
+	int retval;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: fifo threshold");
+	#endif
+
+	// check input value
+	if (threshold & 0x80)
+		INVALID_PARAM;
+
+	// write value
+	retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_VALUE) | threshold);
+	if (retval)
+		return retval;
+
+	// access the fifo to activate new threshold
+	return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer
+}
+
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: dagc");
+	#endif
+
+	switch(dagc) {
+	case normalMode:		 return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL);
+	case improve:			 return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA0);
+	case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA1);
+	default:			 INVALID_PARAM;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+	#ifdef DEBUG_FIFO_ACCESS
+		int i;
+	#endif
+	struct spi_transfer transfer;
+	u8 local_buffer[FIFO_SIZE + 1];
+	int retval;
+
+	if (size > FIFO_SIZE)
+	{
+		#ifdef DEBUG
+			dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n");
+		#endif
+		return -EMSGSIZE;
+	}
+
+	/* prepare a bidirectional transfer */
+	local_buffer[0] = REG_FIFO;
+	memset(&transfer, 0, sizeof(transfer));
+  	transfer.tx_buf = local_buffer;
+  	transfer.rx_buf = local_buffer;
+	transfer.len	= size+1;
+
+	retval = spi_sync_transfer(spi, &transfer, 1);
+
+	#ifdef DEBUG_FIFO_ACCESS
+		for (i=0; i<size; i++)
+			dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]);
+	#endif
+
+	memcpy(buffer, &local_buffer[1], size);  // TODO: ohne memcopy wäre schöner
+
+	return retval;
+}
+
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+	#ifdef DEBUG_FIFO_ACCESS
+		int i;
+	#endif
+	char spi_address = REG_FIFO | WRITE_BIT;
+	u8 local_buffer[FIFO_SIZE + 1];
+
+	if (size > FIFO_SIZE)
+	{
+		#ifdef DEBUG
+			dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n");
+		#endif
+		return -EMSGSIZE;
+	}
+
+	local_buffer[0] = spi_address;
+	memcpy(&local_buffer[1], buffer, size);  // TODO: ohne memcopy wäre schöner
+
+	#ifdef DEBUG_FIFO_ACCESS
+		for (i=0; i<size; i++)
+			dev_dbg(&spi->dev, "0x%x\n",buffer[i]);
+	#endif
+
+	return spi_write (spi, local_buffer, size + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+u8 rf69_read_reg(struct spi_device *spi, u8 addr)
+{
+	int retval;
+
+	retval = spi_w8r8(spi, addr);
+
+	#ifdef DEBUG_VALUES
+		if (retval < 0)
+			/* should never happen, since we already checked,
+			   that module is connected. Therefore no error
+			   handling, just an optional error message... */
+			dev_dbg(&spi->dev, "read 0x%x FAILED\n",
+				addr);
+		else
+			dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n",
+				retval,
+				addr);
+	#endif
+
+	return retval;
+}
+
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value)
+{
+	int retval;
+	char buffer[2];
+
+	buffer[0] = addr | WRITE_BIT;
+	buffer[1] = value;
+
+	retval = spi_write(spi, &buffer, 2);
+
+	#ifdef DEBUG_VALUES
+		if (retval < 0)
+			/* should never happen, since we already checked,
+			   that module is connected. Therefore no error
+			   handling, just an optional error message... */
+			dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n",
+				value,
+				addr);
+		else
+			dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n",
+				value,
+				addr);
+	#endif
+
+	return retval;
+}
+
+
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
new file mode 100644
index 0000000..6a6841b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.h
@@ -0,0 +1,82 @@
+/*
+ * hardware abstraction/register access for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef RF69_H
+#define RF69_H
+
+#include "rf69_enum.h"
+#include "rf69_registers.h"
+
+#define F_OSC 		32000000  /* in Hz */
+#define FREQUENCY	433920000 /* in Hz, modifying this value impacts CE certification */
+#define FIFO_SIZE 	66        /* in byte */
+#define FIFO_THRESHOLD	15 	  /* in byte */
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode);
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode);
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
+enum modulation rf69_get_modulation(struct spi_device *spi);
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_deviation(struct spi_device *spi, u32 deviation);
+int rf69_set_frequency(struct spi_device *spi, u32 frequency);
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi);
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent);
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType);
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+bool rf69_get_flag(struct spi_device *spi, enum flag flag);
+int rf69_reset_flag(struct spi_device *spi, enum flag flag);
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition);
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance);
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat packetFormat);
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering);
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength);
+u8  rf69_get_payload_length(struct spi_device *spi);
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition);
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size);
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size);
+
+u8  rf69_read_reg (struct spi_device *spi, u8 addr);
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value);
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_enum.h b/drivers/staging/pi433/rf69_enum.h
new file mode 100644
index 0000000..fbfb59b
--- /dev/null
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -0,0 +1,201 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_registers.h b/drivers/staging/pi433/rf69_registers.h
new file mode 100644
index 0000000..d0c4992
--- /dev/null
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -0,0 +1,489 @@
+/*
+ * register description for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*******************************************/
+/* RF69 register addresses		   */
+/*******************************************/
+#define  REG_FIFO			0x00
+#define  REG_OPMODE			0x01
+#define  REG_DATAMODUL			0x02
+#define  REG_BITRATE_MSB		0x03
+#define  REG_BITRATE_LSB		0x04
+#define  REG_FDEV_MSB			0x05
+#define  REG_FDEV_LSB			0x06
+#define  REG_FRF_MSB			0x07
+#define  REG_FRF_MID			0x08
+#define  REG_FRF_LSB			0x09
+#define  REG_OSC1			0x0A
+#define  REG_AFCCTRL			0x0B
+#define  REG_LOWBAT			0x0C
+#define  REG_LISTEN1			0x0D
+#define  REG_LISTEN2			0x0E
+#define  REG_LISTEN3			0x0F
+#define  REG_VERSION			0x10
+#define  REG_PALEVEL			0x11
+#define  REG_PARAMP			0x12
+#define  REG_OCP			0x13
+#define  REG_AGCREF			0x14 /* not available on RF69 */
+#define  REG_AGCTHRESH1			0x15 /* not available on RF69 */
+#define  REG_AGCTHRESH2			0x16 /* not available on RF69 */
+#define  REG_AGCTHRESH3			0x17 /* not available on RF69 */
+#define  REG_LNA			0x18
+#define  REG_RXBW			0x19
+#define  REG_AFCBW			0x1A
+#define  REG_OOKPEAK			0x1B
+#define  REG_OOKAVG			0x1C
+#define  REG_OOKFIX			0x1D
+#define  REG_AFCFEI			0x1E
+#define  REG_AFCMSB			0x1F
+#define  REG_AFCLSB			0x20
+#define  REG_FEIMSB			0x21
+#define  REG_FEILSB			0x22
+#define  REG_RSSICONFIG			0x23
+#define  REG_RSSIVALUE			0x24
+#define  REG_DIOMAPPING1		0x25
+#define  REG_DIOMAPPING2		0x26
+#define  REG_IRQFLAGS1			0x27
+#define  REG_IRQFLAGS2			0x28
+#define  REG_RSSITHRESH			0x29
+#define  REG_RXTIMEOUT1			0x2A
+#define  REG_RXTIMEOUT2			0x2B
+#define  REG_PREAMBLE_MSB		0x2C
+#define  REG_PREAMBLE_LSB		0x2D
+#define  REG_SYNC_CONFIG		0x2E
+#define  REG_SYNCVALUE1			0x2F
+#define  REG_SYNCVALUE2			0x30
+#define  REG_SYNCVALUE3			0x31
+#define  REG_SYNCVALUE4			0x32
+#define  REG_SYNCVALUE5			0x33
+#define  REG_SYNCVALUE6			0x34
+#define  REG_SYNCVALUE7			0x35
+#define  REG_SYNCVALUE8			0x36
+#define  REG_PACKETCONFIG1		0x37
+#define  REG_PAYLOAD_LENGTH		0x38
+#define  REG_NODEADRS			0x39
+#define  REG_BROADCASTADRS		0x3A
+#define  REG_AUTOMODES			0x3B
+#define  REG_FIFO_THRESH		0x3C
+#define  REG_PACKETCONFIG2		0x3D
+#define  REG_AESKEY1			0x3E
+#define  REG_AESKEY2			0x3F
+#define  REG_AESKEY3			0x40
+#define  REG_AESKEY4			0x41
+#define  REG_AESKEY5			0x42
+#define  REG_AESKEY6			0x43
+#define  REG_AESKEY7			0x44
+#define  REG_AESKEY8			0x45
+#define  REG_AESKEY9			0x46
+#define  REG_AESKEY10			0x47
+#define  REG_AESKEY11			0x48
+#define  REG_AESKEY12			0x49
+#define  REG_AESKEY13			0x4A
+#define  REG_AESKEY14			0x4B
+#define  REG_AESKEY15			0x4C
+#define  REG_AESKEY16			0x4D
+#define  REG_TEMP1			0x4E
+#define  REG_TEMP2			0x4F
+#define  REG_TESTPA1			0x5A /* only present on RFM69HW */
+#define  REG_TESTPA2			0x5C /* only present on RFM69HW */
+#define  REG_TESTDAGC			0x6F
+
+/******************************************************/
+/* RF69/SX1231 bit definition				*/
+/******************************************************/
+/* write bit */
+#define WRITE_BIT				0x80
+
+/* RegOpMode */
+#define  MASK_OPMODE_SEQUENCER_OFF		0x80
+#define  MASK_OPMODE_LISTEN_ON			0x40
+#define  MASK_OPMODE_LISTEN_ABORT		0x20
+#define  MASK_OPMODE_MODE			0x1C
+
+#define  OPMODE_MODE_SLEEP			0x00
+#define  OPMODE_MODE_STANDBY			0x04 /* default */
+#define  OPMODE_MODE_SYNTHESIZER		0x08
+#define  OPMODE_MODE_TRANSMIT			0x0C
+#define  OPMODE_MODE_RECEIVE			0x10
+
+/* RegDataModul */
+#define  MASK_DATAMODUL_MODE			0x06
+#define  MASK_DATAMODUL_MODULATION_TYPE		0x18
+#define  MASK_DATAMODUL_MODULATION_SHAPE	0x03
+
+#define  DATAMODUL_MODE_PACKET			0x00 /* default */
+#define  DATAMODUL_MODE_CONTINUOUS		0x40
+#define  DATAMODUL_MODE_CONTINUOUS_NOSYNC	0x60
+
+#define  DATAMODUL_MODULATION_TYPE_FSK		0x00 /* default */
+#define  DATAMODUL_MODULATION_TYPE_OOK		0x08
+
+#define  DATAMODUL_MODULATION_SHAPE_NONE	0x00 /* default */
+#define  DATAMODUL_MODULATION_SHAPE_1_0		0x01
+#define  DATAMODUL_MODULATION_SHAPE_0_5		0x02
+#define  DATAMODUL_MODULATION_SHAPE_0_3		0x03
+#define  DATAMODUL_MODULATION_SHAPE_BR		0x01
+#define  DATAMODUL_MODULATION_SHAPE_2BR		0x02
+
+/* RegFDevMsb (0x05)*/
+#define FDEVMASB_MASK				0x3f
+
+/*
+// RegOsc1
+#define  OSC1_RCCAL_START			0x80
+#define  OSC1_RCCAL_DONE			0x40
+
+// RegLowBat
+#define  LOWBAT_MONITOR				0x10
+#define  LOWBAT_ON				0x08
+#define  LOWBAT_OFF				0x00  // Default
+
+#define  LOWBAT_TRIM_1695			0x00
+#define  LOWBAT_TRIM_1764			0x01
+#define  LOWBAT_TRIM_1835			0x02  // Default
+#define  LOWBAT_TRIM_1905			0x03
+#define  LOWBAT_TRIM_1976			0x04
+#define  LOWBAT_TRIM_2045			0x05
+#define  LOWBAT_TRIM_2116			0x06
+#define  LOWBAT_TRIM_2185			0x07
+
+
+// RegListen1
+#define  LISTEN1_RESOL_64			0x50
+#define  LISTEN1_RESOL_4100			0xA0  // Default
+#define  LISTEN1_RESOL_262000			0xF0
+
+#define  LISTEN1_CRITERIA_RSSI			0x00  // Default
+#define  LISTEN1_CRITERIA_RSSIANDSYNC		0x08
+
+#define  LISTEN1_END_00				0x00
+#define  LISTEN1_END_01				0x02  // Default
+#define  LISTEN1_END_10				0x04
+
+
+// RegListen2
+#define  LISTEN2_COEFIDLE_VALUE			0xF5 // Default
+
+// RegListen3
+#define  LISTEN3_COEFRX_VALUE			0x20 // Default
+*/
+
+// RegPaLevel
+#define  MASK_PALEVEL_PA0			0x80
+#define  MASK_PALEVEL_PA1			0x40
+#define  MASK_PALEVEL_PA2			0x20
+#define  MASK_PALEVEL_OUTPUT_POWER		0x1F
+
+
+
+// RegPaRamp
+#define  PARAMP_3400				0x00
+#define  PARAMP_2000				0x01
+#define  PARAMP_1000				0x02
+#define  PARAMP_500				0x03
+#define  PARAMP_250				0x04
+#define  PARAMP_125				0x05
+#define  PARAMP_100				0x06
+#define  PARAMP_62				0x07
+#define  PARAMP_50				0x08
+#define  PARAMP_40				0x09 /* default */
+#define  PARAMP_31				0x0A
+#define  PARAMP_25				0x0B
+#define  PARAMP_20				0x0C
+#define  PARAMP_15				0x0D
+#define  PARAMP_12				0x0E
+#define  PARAMP_10				0x0F
+
+#define  MASK_PARAMP				0x0F
+
+/*
+// RegOcp
+#define  OCP_OFF				0x0F
+#define  OCP_ON					0x1A  // Default
+
+#define  OCP_TRIM_45				0x00
+#define  OCP_TRIM_50				0x01
+#define  OCP_TRIM_55				0x02
+#define  OCP_TRIM_60				0x03
+#define  OCP_TRIM_65				0x04
+#define  OCP_TRIM_70				0x05
+#define  OCP_TRIM_75				0x06
+#define  OCP_TRIM_80				0x07
+#define  OCP_TRIM_85				0x08
+#define  OCP_TRIM_90				0x09
+#define  OCP_TRIM_95				0x0A
+#define  OCP_TRIM_100				0x0B  // Default
+#define  OCP_TRIM_105				0x0C
+#define  OCP_TRIM_110				0x0D
+#define  OCP_TRIM_115				0x0E
+#define  OCP_TRIM_120				0x0F
+*/
+
+/* RegLna (0x18) */
+#define  MASK_LNA_ZIN				0x80
+#define  MASK_LNA_CURRENT_GAIN			0x38
+#define  MASK_LNA_GAIN				0x07
+
+#define  LNA_GAIN_AUTO				0x00 /* default */
+#define  LNA_GAIN_MAX				0x01
+#define  LNA_GAIN_MAX_MINUS_6			0x02
+#define  LNA_GAIN_MAX_MINUS_12			0x03
+#define  LNA_GAIN_MAX_MINUS_24			0x04
+#define  LNA_GAIN_MAX_MINUS_36			0x05
+#define  LNA_GAIN_MAX_MINUS_48			0x06
+
+
+/* RegRxBw (0x19) and RegAfcBw (0x1A) */
+#define  MASK_BW_DCC_FREQ			0xE0
+#define  MASK_BW_MANTISSE			0x18
+#define  MASK_BW_EXPONENT			0x07
+
+#define  BW_DCC_16_PERCENT			0x00
+#define  BW_DCC_8_PERCENT			0x20
+#define  BW_DCC_4_PERCENT			0x40 /* default */
+#define  BW_DCC_2_PERCENT			0x60
+#define  BW_DCC_1_PERCENT			0x80
+#define  BW_DCC_0_5_PERCENT			0xA0
+#define  BW_DCC_0_25_PERCENT			0xC0
+#define  BW_DCC_0_125_PERCENT			0xE0
+
+#define  BW_MANT_16				0x00
+#define  BW_MANT_20				0x08
+#define  BW_MANT_24				0x10 /* default */
+
+
+/* RegOokPeak (0x1B) */
+#define  MASK_OOKPEAK_THRESTYPE			0xc0
+#define  MASK_OOKPEAK_THRESSTEP			0x38
+#define  MASK_OOKPEAK_THRESDEC			0x07
+
+#define  OOKPEAK_THRESHTYPE_FIXED		0x00
+#define  OOKPEAK_THRESHTYPE_PEAK		0x40 /* default */
+#define  OOKPEAK_THRESHTYPE_AVERAGE		0x80
+
+#define  OOKPEAK_THRESHSTEP_0_5_DB		0x00 /* default */
+#define  OOKPEAK_THRESHSTEP_1_0_DB		0x08
+#define  OOKPEAK_THRESHSTEP_1_5_DB		0x10
+#define  OOKPEAK_THRESHSTEP_2_0_DB		0x18
+#define  OOKPEAK_THRESHSTEP_3_0_DB		0x20
+#define  OOKPEAK_THRESHSTEP_4_0_DB		0x28
+#define  OOKPEAK_THRESHSTEP_5_0_DB		0x30
+#define  OOKPEAK_THRESHSTEP_6_0_DB		0x38
+
+#define  OOKPEAK_THRESHDEC_ONCE			0x00 /* default */
+#define  OOKPEAK_THRESHDEC_EVERY_2ND		0x01
+#define  OOKPEAK_THRESHDEC_EVERY_4TH		0x02
+#define  OOKPEAK_THRESHDEC_EVERY_8TH		0x03
+#define  OOKPEAK_THRESHDEC_TWICE		0x04
+#define  OOKPEAK_THRESHDEC_4_TIMES		0x05
+#define  OOKPEAK_THRESHDEC_8_TIMES		0x06
+#define  OOKPEAK_THRESHDEC_16_TIMES		0x07
+
+/*
+// RegOokAvg
+#define  OOKAVG_AVERAGETHRESHFILT_00		0x00
+#define  OOKAVG_AVERAGETHRESHFILT_01		0x40
+#define  OOKAVG_AVERAGETHRESHFILT_10		0x80  // Default
+#define  OOKAVG_AVERAGETHRESHFILT_11		0xC0
+
+
+// RegAfcFei
+#define  AFCFEI_FEI_DONE			0x40
+#define  AFCFEI_FEI_START			0x20
+#define  AFCFEI_AFC_DONE			0x10
+#define  AFCFEI_AFCAUTOCLEAR_ON			0x08
+#define  AFCFEI_AFCAUTOCLEAR_OFF		0x00  // Default
+
+#define  AFCFEI_AFCAUTO_ON			0x04
+#define  AFCFEI_AFCAUTO_OFF			0x00  // Default
+
+#define  AFCFEI_AFC_CLEAR			0x02
+#define  AFCFEI_AFC_START			0x01
+
+// RegRssiConfig
+#define  RSSI_FASTRX_ON				0x08
+#define  RSSI_FASTRX_OFF			0x00  // Default
+#define  RSSI_DONE				0x02
+#define  RSSI_START				0x01
+*/
+
+/* RegDioMapping1 */
+#define  MASK_DIO0				0xC0
+#define  MASK_DIO1				0x30
+#define  MASK_DIO2				0x0C
+#define  MASK_DIO3				0x03
+#define  SHIFT_DIO0				6
+#define  SHIFT_DIO1				4
+#define  SHIFT_DIO2				2
+#define  SHIFT_DIO3				0
+
+/* RegDioMapping2 */
+#define  MASK_DIO4				0xC0
+#define  MASK_DIO5				0x30
+#define  SHIFT_DIO4				6
+#define  SHIFT_DIO5				4
+
+/* DIO numbers */
+#define  DIO0					0
+#define  DIO1					1
+#define  DIO2					2
+#define  DIO3					3
+#define  DIO4					4
+#define  DIO5					5
+
+/* DIO Mapping values (packet mode) */
+#define  DIO_ModeReady_DIO4			0x00
+#define  DIO_ModeReady_DIO5			0x03
+#define  DIO_ClkOut				0x00
+#define  DIO_Data				0x01
+#define  DIO_TimeOut_DIO1			0x03
+#define  DIO_TimeOut_DIO4			0x00
+#define  DIO_Rssi_DIO0				0x03
+#define  DIO_Rssi_DIO3_4			0x01
+#define  DIO_RxReady				0x02
+#define  DIO_PLLLock				0x03
+#define  DIO_TxReady				0x01
+#define  DIO_FifoFull_DIO1			0x01
+#define  DIO_FifoFull_DIO3			0x00
+#define  DIO_SyncAddress			0x02
+#define  DIO_FifoNotEmpty_DIO1			0x02
+#define  DIO_FifoNotEmpty_FIO2			0x00
+#define  DIO_Automode				0x04
+#define  DIO_FifoLevel				0x00
+#define  DIO_CrcOk				0x00
+#define  DIO_PayloadReady			0x01
+#define  DIO_PacketSent				0x00
+#define  DIO_Dclk				0x00
+
+/* RegDioMapping2 CLK_OUT part */
+#define  MASK_DIOMAPPING2_CLK_OUT		0x07
+
+#define  DIOMAPPING2_CLK_OUT_NO_DIV		0x00
+#define  DIOMAPPING2_CLK_OUT_DIV_2		0x01
+#define  DIOMAPPING2_CLK_OUT_DIV_4		0x02
+#define  DIOMAPPING2_CLK_OUT_DIV_8		0x03
+#define  DIOMAPPING2_CLK_OUT_DIV_16		0x04
+#define  DIOMAPPING2_CLK_OUT_DIV_32		0x05
+#define  DIOMAPPING2_CLK_OUT_RC			0x06
+#define  DIOMAPPING2_CLK_OUT_OFF		0x07 /* default */
+
+/* RegIrqFlags1 */
+#define  MASK_IRQFLAGS1_MODE_READY		0x80
+#define  MASK_IRQFLAGS1_RX_READY		0x40
+#define  MASK_IRQFLAGS1_TX_READY		0x20
+#define  MASK_IRQFLAGS1_PLL_LOCK		0x10
+#define  MASK_IRQFLAGS1_RSSI			0x08
+#define  MASK_IRQFLAGS1_TIMEOUT			0x04
+#define  MASK_IRQFLAGS1_AUTOMODE		0x02
+#define  MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH	0x01
+
+/* RegIrqFlags2 */
+#define  MASK_IRQFLAGS2_FIFO_FULL		0x80
+#define  MASK_IRQFLAGS2_FIFO_NOT_EMPTY		0x40
+#define  MASK_IRQFLAGS2_FIFO_LEVEL		0x20
+#define  MASK_IRQFLAGS2_FIFO_OVERRUN		0x10
+#define  MASK_IRQFLAGS2_PACKET_SENT		0x08
+#define  MASK_IRQFLAGS2_PAYLOAD_READY		0x04
+#define  MASK_IRQFLAGS2_CRC_OK			0x02
+#define  MASK_IRQFLAGS2_LOW_BAT			0x01
+
+/* RegSyncConfig */
+#define  MASK_SYNC_CONFIG_SYNC_ON		0x80 /* default */
+#define  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION	0x40
+#define  MASK_SYNC_CONFIG_SYNC_SIZE		0x38
+#define  MASK_SYNC_CONFIG_SYNC_TOLERANCE	0x07
+
+/* RegPacketConfig1 */
+#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE	0x80
+#define  MASK_PACKETCONFIG1_DCFREE			0x60
+#define  MASK_PACKETCONFIG1_CRC_ON			0x10 /* default */
+#define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF		0x08
+#define  MASK_PACKETCONFIG1_ADDRESSFILTERING		0x06
+
+#define  PACKETCONFIG1_DCFREE_OFF			0x00 /* default */
+#define  PACKETCONFIG1_DCFREE_MANCHESTER		0x20
+#define  PACKETCONFIG1_DCFREE_WHITENING			0x40
+#define  PACKETCONFIG1_ADDRESSFILTERING_OFF		0x00 /* default */
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODE		0x02
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST	0x04
+
+/*
+// RegAutoModes
+#define  AUTOMODES_ENTER_OFF			0x00  // Default
+#define  AUTOMODES_ENTER_FIFONOTEMPTY		0x20
+#define  AUTOMODES_ENTER_FIFOLEVEL		0x40
+#define  AUTOMODES_ENTER_CRCOK			0x60
+#define  AUTOMODES_ENTER_PAYLOADREADY		0x80
+#define  AUTOMODES_ENTER_SYNCADRSMATCH		0xA0
+#define  AUTOMODES_ENTER_PACKETSENT		0xC0
+#define  AUTOMODES_ENTER_FIFOEMPTY		0xE0
+
+#define  AUTOMODES_EXIT_OFF			0x00  // Default
+#define  AUTOMODES_EXIT_FIFOEMPTY		0x04
+#define  AUTOMODES_EXIT_FIFOLEVEL		0x08
+#define  AUTOMODES_EXIT_CRCOK			0x0C
+#define  AUTOMODES_EXIT_PAYLOADREADY		0x10
+#define  AUTOMODES_EXIT_SYNCADRSMATCH		0x14
+#define  AUTOMODES_EXIT_PACKETSENT		0x18
+#define  AUTOMODES_EXIT_RXTIMEOUT		0x1C
+
+#define  AUTOMODES_INTERMEDIATE_SLEEP		0x00  // Default
+#define  AUTOMODES_INTERMEDIATE_STANDBY		0x01
+#define  AUTOMODES_INTERMEDIATE_RECEIVER	0x02
+#define  AUTOMODES_INTERMEDIATE_TRANSMITTER	0x03
+
+*/
+/* RegFifoThresh (0x3c) */
+#define  MASK_FIFO_THRESH_TXSTART		0x80
+#define  MASK_FIFO_THRESH_VALUE			0x7F
+
+/*
+
+// RegPacketConfig2
+#define  PACKET2_RXRESTARTDELAY_1BIT		0x00  // Default
+#define  PACKET2_RXRESTARTDELAY_2BITS		0x10
+#define  PACKET2_RXRESTARTDELAY_4BITS		0x20
+#define  PACKET2_RXRESTARTDELAY_8BITS		0x30
+#define  PACKET2_RXRESTARTDELAY_16BITS		0x40
+#define  PACKET2_RXRESTARTDELAY_32BITS		0x50
+#define  PACKET2_RXRESTARTDELAY_64BITS		0x60
+#define  PACKET2_RXRESTARTDELAY_128BITS		0x70
+#define  PACKET2_RXRESTARTDELAY_256BITS		0x80
+#define  PACKET2_RXRESTARTDELAY_512BITS		0x90
+#define  PACKET2_RXRESTARTDELAY_1024BITS	0xA0
+#define  PACKET2_RXRESTARTDELAY_2048BITS	0xB0
+#define  PACKET2_RXRESTARTDELAY_NONE		0xC0
+#define  PACKET2_RXRESTART			0x04
+
+#define  PACKET2_AUTORXRESTART_ON		0x02  // Default
+#define  PACKET2_AUTORXRESTART_OFF		0x00
+
+#define  PACKET2_AES_ON				0x01
+#define  PACKET2_AES_OFF			0x00  // Default
+
+
+// RegTemp1
+#define  TEMP1_MEAS_START			0x08
+#define  TEMP1_MEAS_RUNNING			0x04
+#define  TEMP1_ADCLOWPOWER_ON			0x01  // Default
+#define  TEMP1_ADCLOWPOWER_OFF			0x00
+*/
+
+// RegTestDagc (0x6F)
+#define  DAGC_NORMAL				0x00 /* Reset value */
+#define  DAGC_IMPROVED_LOWBETA1			0x20
+#define  DAGC_IMPROVED_LOWBETA0			0x30 /* Recommended val */
>> I absolutly agree. My patch should meet the needs of an official patch.
>
> Again, don't use html email :)
>
>> But I don't know about the exact needs. Can you please help me? What is needed
>> / missing in my patch and how do I produce it?
>> Maybe you can pass me a link, where I can read, what to do?
>
> The link I sent you, Documentation/SubmittingPatches in the kernel
> source tree, should contain everything you need to know.  As a minimum
> you need a good subject, a good changelog body text, and a
> signed-off-by: line.  The file should tell you all about how to create
> this.
>
> If you have specific questions after reading that about these things,
> please let us know.
>
> thanks,
>
> greg k-h
>
>

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
@ 2017-07-15 17:05                     ` Wolf Entwicklungen
  0 siblings, 0 replies; 49+ messages in thread
From: Wolf Entwicklungen @ 2017-07-15 17:05 UTC (permalink / raw)
  To: Greg KH
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Am Sa, 15.07.2017, 15:47 schrieb Greg KH:
> On Sat, Jul 15, 2017 at 03:40:30PM +0200, Marcus Wolf wrote:
>> Hi Greg,
>>

Hi Greg,

now I added a TODO file and did a manual patchwork with lines of the old patch
(git format-patch master --stdout -p > pi433_patch) and the newer patch (git
diff master > pi433_patch). Stil don't know how to retreive multiple commits
in one single patch directly from git :-/
I did my best to meet a lot of rules of the link, you send me.If
there is stil something essential wrong or missing, please excuse and let me know.

Especially I was in doubt about the verbosity of the change log. If you'd like
to see the list of features of the driver over there (please see my first mail),
let me know and I'll add.

Sorry for posting in HTML once again on last mail. Now I changed the frontend of my
mailtool. Hope this works better. If not, excuse and let me know.
I Think about moving to gits mail function for my next patches.

Cheers,

Marcus


From: Marcus Wolf <linux-79IPTMiko8heq5RAq1AYSxS11BummzK+@public.gmane.org>
Date: Tue,15 Jul 2017 17:52:06 +0100
Subject: [PATCH 1/1] drivers/staging/pi433: New driver

Added a driver for the pi433 radio module
(see https://www.pi433.de/en.html for details).
Signed-off-by: Marcus Wolf <linux-79IPTMiko8heq5RAq1AYSxS11BummzK+@public.gmane.org>
Tested-by: Marcus Wolf <linux-79IPTMiko8heq5RAq1AYSxS11BummzK+@public.gmane.org> on Raspbian, running Kernel v4.12
---
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 268d4e6..fdf060c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"

 source "drivers/staging/typec/Kconfig"

+source "drivers/staging/pi433/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b93e6f5..998f644 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)		+= ks7010/
 obj-$(CONFIG_GREYBUS)		+= greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)	+= vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)	+= ccree/
+obj-$(CONFIG_PI433)		+= pi433/
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
new file mode 100644
index 0000000..004b502
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
@@ -0,0 +1,53 @@
+// Definitions for Pi433
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			pi433_pins: pi433_pins {
+				brcm,pins = <7 25 24>;
+				brcm,function = <0 0 0>; // in in in
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pi433: pi433@0 {
+				compatible = "Smarthome-Wolf,pi433";
+				reg = <0>;
+				spi-max-frequency = <10000000>;
+				status = "okay";
+
+				pinctrl-0 = <&pi433_pins>;
+				DIO0-gpio = <&gpio 24 0>;
+				DIO1-gpio = <&gpio 25 0>;
+				DIO2-gpio = <&gpio  7 0>;
+			};
+		};
+	};
+};
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
new file mode 100644
index 0000000..14197c6
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
@@ -0,0 +1,62 @@
+* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see www.pi433.de)
+
+Required properties:
+- compatible: must be "Smarthome-Wolf,pi433"
+- reg: chip select of SPI Interface
+- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69 module
+
+
+Example:
+
+With the following lines in gpio-section, the gpio pins, connected with pi433 are
+reserved/declared.
+
+&gpio{
+	[...]
+
+	pi433_pins: pi433_pins {
+		brcm,pins = <7 25 24>;
+		brcm,function = <0 0 0>; // in in in
+	};
+
+	[...]
+}
+
+With the following lines in spi section, the device pi433 is declared.
+It consists of the three gpio pins and an spi interface (here chip select 0)
+
+&spi0{
+	[...]
+
+	pi433: pi433@0 {
+		compatible = "Smarthome-Wolf,pi433";
+		reg = <0>; /* CE 0 */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-max-frequency = <10000000>;
+
+		pinctrl-0 = <&pi433_pins>;
+		DIO0-gpio = <&gpio 24 0>;
+		DIO1-gpio = <&gpio 25 0>;
+		DIO2-gpio = <&gpio  7 0>;
+	};
+}
+
+
+
+For Raspbian users only
+=======================
+Since Raspbian supports device tree overlays, you may use and overlay, instead
+of editing your boards device tree.
+For using the overlay, you need to compile the file pi433-overlay.dts you can
+find aside to this documentation.
+The file needs to be compiled - either manually or by integration in your kernel
+source tree. For a manual compile, you may use a command line like the following:
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+arch/arm/boot/dts/overlays and you need to add the file to the list of files
+in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
+kernel make files compile the device tree overlay for you.
+
+
diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt
new file mode 100644
index 0000000..860dd0f
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -0,0 +1,274 @@
+=====
+Pi433
+=====
+
+
+Introduction
+============
+This driver is for controlling pi433, a radio module for the Raspberry Pi
+(www.pi433.de). It supports transmission and reception. It can be opened
+by multiple applications for transmission and reception. While transmit
+jobs were queued and process automatically in the background, the first
+application asking for reception will block out all other applications
+until something gets received terminates the read request.
+The driver supports on the fly reloading of the hardware fifo of the rf
+chip, thus enabling for much longer telegrams then hardware fifo size.
+
+Discription of driver operation
+===============================
+
+a) transmission
+
+Each transmission can take place with a different configuration of the rf
+module. Therfore each application can set its own set of parameters. The driver
+takes care, that each transmission takes place with the parameterset of the
+application, that requests the transmission. To allow the transmission to take
+place in the background, a tx thread is introduced.
+The transfer of data from the main thread to the tx thread is realised by a
+kfifo. With each write request of an application, the passed in data and the
+corresponding parameter set gets written to the kfifo.
+On the other "side" of the kfifo, the tx thread continuously checks, whether the
+kfifo is empty. If not, it gets one set of config and data from the kfifo. If
+there is no receive request or the receiver is still waiting for something in
+the air, the rf module is set to standby, the parameters for transmission gets
+set, the hardware fifo of the rf chip gets preloaded and the transmission gets
+started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling
+much longer telegrams then hardware fifo size. If the telegram is send and there
+is more data available in the kfifo, the procedure is repeated. If not the
+transmission cycle ends.
+
+b) reception
+
+Since there is only one application allowed to receive data at a time, for
+reception there is only one configuration set.
+As soon as an application sets an request for receiving a telegram, the reception
+configuration set is written to the rf module and it gets set into receiving mode.
+Now the driver is waiting, that a predefined RSSI level (signal strength at the
+receiver) is reached. Until this hasn't happened, the reception can be
+interrupted by the transmission thread at any time to insert a transmission cycle.
+As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar
+as described for the transmission cycle the read out of the hardware fifo is done
+dynamically. Upon each hardware fifo threshold interrupt, a portion of data gets
+read. So also for reception it is possible to receive more data then the hardware
+fifo can hold.
+
+
+Driver API
+==========
+
+The driver is currently implemented as a character device. Therefore it supports
+the calls open, ioctl, read, write and close.
+
+
+params for ioctl
+----------------
+
+There are four options:
+PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver
+PI433_IOC_WR_TX_CFG - set the transmission parameters
+PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver
+PI433_IOC_WR_RX_CFG - set the receiving parameters
+
+The tx configuration is transfered via struct pi433_tx_cfg, the parameterset for transmission.
+It is devided into two sections: rf parameters and packet format.
+
+rf params:
+	frequency
+		frequency used for transmission.
+		Allowed values: 433050000...434790000
+	bit_rate
+		bit rate used for transmission.
+		Allowed values: #####
+	dev_frequency
+		frequency deviation in case of FSK.
+		Allowed values: 600...500000
+	modulation
+		FSK - frequency shift key
+		OOK - On-Off-key
+	modShaping
+		shapingOff	- no shaping
+		shaping1_0	- gauss filter with BT 1 (FSK only)
+		shaping0_5	- gauss filter with BT 0.5 (FSK only)
+		shaping0_3	- gauss filter with BT 0.3 (FSK only)
+		shapingBR	- filter cut off at BR (OOK only)
+		shaping2BR	- filter cut off at 2*BR (OOK only)
+	paRamp (FSK only)
+		ramp3400	- amp ramps up in 3.4ms
+		ramp2000	- amp ramps up in 2.0ms
+		ramp1000	- amp ramps up in 1ms
+		ramp500		- amp ramps up in 500us
+		ramp250		- amp ramps up in 250us
+		ramp125		- amp ramps up in 125us
+		ramp100		- amp ramps up in 100us
+		ramp62		- amp ramps up in 62us
+		ramp50		- amp ramps up in 50us
+		ramp40		- amp ramps up in 40us
+		ramp31		- amp ramps up in 31us
+		ramp25		- amp ramps up in 25us
+		ramp20		- amp ramps up in 20us
+		ramp15		- amp ramps up in 15us
+		ramp12		- amp ramps up in 12us
+		ramp10		- amp ramps up in 10us
+	tx_start_condition
+		fifoLevel	- transmission starts, if fifo is filled to
+				  threshold level
+		fifoNotEmpty	- transmission starts, as soon as there is one
+				  byte in internal fifo
+	repetitions
+		This gives the option, to send a telegram multiple times. Default: 1
+
+packet format:
+	enable_preamble
+		optionOn	- a preamble will be automatically generated
+		optionOff	- no preamble will be generated
+	enable_sync
+		optionOn	- a sync word will be automatically added to
+				  the telegram after preamble
+		optionOff	- no sync word will be added
+		Attention: While possible to generate sync without preamble, the
+		receiver won't be able to detect the sync without preamble.
+	enable_length_byte
+		optionOn	- the length of the telegram will be automatically
+				  added to the telegram. It's part of the payload
+		optionOff	- no length information will be automatically added
+				  to the telegram.
+		Attention: For telegram length over 255 bytes, this option can't be used
+		Attention: should be used in combination with sync, only
+	enable_address_byte
+		optionOn	- the address byte will be automatically added to the
+				  telgram. It's part of the payload
+		optionOff	- the address byte will not be added to the telegram.
+		The address byte can be used for address filtering, so the receiver
+		will only receive telegrams with a given address byte.
+		Attention: should be used in combination with sync, only
+	enable_crc
+		optionOn	- an crc will be automatically calculated over the
+				  payload of the telegram and added to the telegram
+				  after payload.
+		optionOff	- no crc will be calculated
+	preamble_length
+		length of the preamble. Allowed values: 0...65536
+	sync_length
+		length of the sync word. Allowed values: 0...8
+	fixed_message_length
+		length of the payload of the telegram. Will override the length
+		given by the buffer, passed in with the write command. Will be
+		ignored if set to zero.
+	sync_pattern[8]
+		contains up to eight values, that are used as the sync pattern
+		on sync option
+	address_byte
+		one byte, used as address byte on address byte option.
+
+
+The rx configuration is transfered via struct pi433_rx_cfg, the parameterset for receiving. It is devided into two sections: rf parameters and packet format.
+
+rf params:
+	frequency
+		frequency used for transmission.
+		Allowed values: 433050000...434790000
+	bit_rate
+		bit rate used for transmission.
+		Allowed values: #####
+	dev_frequency
+		frequency deviation in case of FSK.
+		Allowed values: 600...500000
+	modulation
+		FSK - frequency shift key
+		OOK - on off key
+	rssi_threshold
+		threshold value for the signal strength on the receiver input.
+		If this value is exeeded, a reception cycle starts
+		Allowed values: 0...255
+	thresholdDecrement
+		in order to adapt to different levels of singnal strength, over
+		time the receiver gets more and more sensitive. This value
+		determs, how fast the sensitivity increases.
+		step_0_5db	- increase in 0,5dB steps
+		step_1_0db	- increase in 1 db steps
+		step_1_5db	- increase in 1,5dB steps
+		step_2_0db	- increase in 2 db steps
+		step_3_0db	- increase in 3 db steps
+		step_4_0db	- increase in 4 db steps
+		step_5_0db	- increase in 5 db steps
+		step_6_0db	- increase in 6 db steps
+	antennaImpedance
+		sets the electrical adoption of the antenna
+		fiftyOhm	- for antennas with an impedance of 50Ohm
+		twohundretOhm	- for antennas with an impedance of 200Ohm
+	lnaGain
+		sets the gain of the low noise amp
+		automatic	- lna gain is determed by an agc
+		max		- lna gain is set to maximum
+		maxMinus6	- lna gain is set to  6db below max
+		maxMinus12	- lna gain is set to 12db below max
+		maxMinus24	- lna gain is set to 24db below max
+		maxMinus36	- lna gain is set to 36db below max
+		maxMinus48	- lna gain is set to 48db below max
+	bw_mantisse
+		sets the bandwidth of the channel filter - part one: mantisse.
+		mantisse16	- mantisse is set to 16
+		mantisse20	- mantisse is set to 20
+		mantisse24	- mantisse is set to 24
+	bw_exponent
+		sets the bandwidth of the channel filter - part two: exponent.
+		Allowd values: 0...7
+	dagc;
+		operation mode of the digital automatic gain control
+		normalMode
+		improve
+		improve4LowModulationIndex
+
+ packet format:
+	enable_sync
+		optionOn  - sync detection is enabled. If configured sync pattern
+			    isn't found, telegram will be internally discarded
+		optionOff - sync detection is disabled.
+	enable_length_byte
+		optionOn   - First byte of payload will be used as length byte,
+			     regardless of the amount of bytes that were requested
+			     by the read request.
+		optionOff  - Number of bytes to be read will be set according to
+			     amount of bytes that were requested by the read request.
+		Attention: should be used in combination with sync, only
+	enable_address_filtering;
+		filteringOff		- no adress filtering will take place
+		nodeAddress		- all telegrams, not matching the node
+					  address will be internally discarded
+		nodeOrBroadcastAddress	- all telegrams, neither matching the
+					  node, nor the broadcast address will
+					  be internally discarded
+		Attention: Sync option must be enabled in order to use this feature
+	enable_crc
+		optionOn	- a crc will be calculated over the payload of
+				  the telegram, that was received. If the
+				  calculated crc doesn't match to two bytes,
+				  that follow the payload, the telegram will be
+				  internally discarded.
+		Attention: This option is only operational, if sync on and fixed length
+		or length byte is used
+	sync_length
+		Gives the length of the payload.
+		Attention: This setting must meet the setting of the transmitter,
+		if sync option is used.
+	fixed_message_length
+		Overrides the telegram length either given by the first byte of
+		payload or by the read request.
+	bytes_to_drop
+		gives the number of bytes, that will be dropped before transfering
+		data to the read buffer
+		This option is only usefull, if all packet helper are switched
+		off and the rf chip is used in raw receiving mode. This may be
+		needed, if a telegram of a third party device should be received,
+		using a protocol not compatible with the packet engine of the rf69 chip.
+	sync_pattern[8]
+		contains up to eight values, that are used as the sync pattern
+		on sync option.
+		This setting must meet the configuration of the transmitting device,
+		if sync option is enabled.
+	node_address
+		one byte, used as node address byte on address byte option.
+	broadcast_address
+		one byte, used as broadcast address byte on address byte option.
+
+
diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
new file mode 100644
index 0000000..61b4b4e
--- /dev/null
+++ b/drivers/staging/pi433/Kconfig
@@ -0,0 +1,16 @@
+config PI433
+        tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
+        default n
+        ---help---
+          This option allows you to enable support for the radio module Pi433.
+
+          Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi
+          or compatible. It extends the Raspberry Pi with the option, to
+          send and receive data in the 433MHz ISM band - for example to
+          communicate between two systems without using ethernet or bluetooth
+          or for control or read sockets, actors, sensors, widely available
+          for low price.
+
+          For details or the option to buy, please visit https://pi433.de/en.html
+
+          If in doubt, say N here, but saying yes most probably won't hurt
diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile
new file mode 100644
index 0000000..417f3e4
--- /dev/null
+++ b/drivers/staging/pi433/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PI433) += pi433.o
+
+pi433-objs := pi433_if.o rf69.o
diff --git a/drivers/staging/pi433/TODO b/drivers/staging/pi433/TODO
new file mode 100644
index 0000000..63a40bf
--- /dev/null
+++ b/drivers/staging/pi433/TODO
@@ -0,0 +1,5 @@
+* coding style does not fully comply with the kernel style guide.
+* still TODOs, annotated in the code
+* currently the code introduces new IOCTLs. I'm afraid this is a bad idea.
+  -> Replace this with another interface, hints are welcome!
+* Some missing data (marked with ###) needs to be added in the documentation
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
new file mode 100644
index 0000000..57edf91
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.c
@@ -0,0 +1,1315 @@
+/*
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+#endif
+
+#include "pi433_if.h"
+#include "rf69.h"
+
+
+#define N_PI433_MINORS			(1U << MINORBITS) /*32*/	/* ... up to 256 */
+#define MAX_MSG_SIZE			900	/* min: FIFO_SIZE! */
+#define MSG_FIFO_SIZE			65536   /* 65536 = 2^16  */
+#define NUM_DIO				2
+
+static dev_t pi433_dev;
+static DEFINE_IDR(pi433_idr);
+static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+
+static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
+
+/* tx config is instance specific
+	so with each open a new tx config struct is needed */
+/* rx config is device specific
+	so we have just one rx config, ebedded in device struct */
+struct pi433_device {
+	/* device handling related values */
+	dev_t			devt;
+	int			minor;
+	struct device		*dev;
+	struct cdev		*cdev;
+	struct spi_device	*spi;
+	unsigned		users;
+
+	/* irq related values */
+	struct gpio_desc	*gpiod[NUM_DIO];
+	int			irq_num[NUM_DIO];
+	u8			irq_state[NUM_DIO];
+
+	/* tx related values */
+	STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
+	struct mutex		tx_fifo_lock; // TODO: check, whether necessary or obsolete
+	struct task_struct	*tx_task_struct;
+	wait_queue_head_t	tx_wait_queue;
+	u8			free_in_fifo;
+
+	/* rx related values */
+	struct pi433_rx_cfg	rx_cfg;
+	u8			*rx_buffer;
+	unsigned int		rx_buffer_size;
+	u32			rx_bytes_to_drop;
+	u32			rx_bytes_dropped;
+	unsigned int		rx_position;
+	struct mutex		rx_lock;
+	wait_queue_head_t	rx_wait_queue;
+
+	/* fifo wait queue */
+	struct task_struct	*fifo_task_struct;
+	wait_queue_head_t	fifo_wait_queue;
+
+	/* flags */
+	bool			rx_active;
+	bool			tx_active;
+	bool			interrupt_rx_allowed;
+};
+
+struct pi433_instance {
+	struct pi433_device	*device;
+	struct pi433_tx_cfg	tx_cfg;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* macro for checked access of registers of radio module */
+#define SET_CHECKED(retval) \
+	if (retval < 0) \
+		return retval;
+
+/*-------------------------------------------------------------------------*/
+
+/* GPIO interrupt handlers */
+static irq_handler_t
+DIO0_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pi433_device *device = dev_id;
+
+	if      (device->irq_state[DIO0] == DIO_PacketSent)
+	{
+		device->free_in_fifo = FIFO_SIZE;
+		printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include KERN_ facility level
+		wake_up_interruptible(&device->fifo_wait_queue);
+	}
+	else if (device->irq_state[DIO0] == DIO_Rssi_DIO0)
+	{
+		printk("DIO0 irq: RSSI level over threshold\n");
+		wake_up_interruptible(&device->rx_wait_queue);
+	}
+	else if (device->irq_state[DIO0] == DIO_PayloadReady)
+	{
+		printk("DIO0 irq: PayloadReady\n");
+		device->free_in_fifo = 0;
+		wake_up_interruptible(&device->fifo_wait_queue);
+	}
+
+	return (irq_handler_t) IRQ_HANDLED;
+}
+
+static irq_handler_t
+DIO1_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pi433_device *device = dev_id;
+
+	if      (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1)
+	{
+		device->free_in_fifo = FIFO_SIZE;
+	}
+	else if (device->irq_state[DIO1] == DIO_FifoLevel)
+	{
+		if (device->rx_active)	device->free_in_fifo = FIFO_THRESHOLD - 1;
+		else			device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1;
+	}
+	printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO: printk() should include KERN_ facility level
+	wake_up_interruptible(&device->fifo_wait_queue);
+
+	return (irq_handler_t) IRQ_HANDLED;
+}
+
+static void *DIO_irq_handler[NUM_DIO] = {
+	DIO0_irq_handler,
+	DIO1_irq_handler
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
+{
+	int payload_length;
+
+	/* receiver config */
+	SET_CHECKED(rf69_set_frequency	(dev->spi, rx_cfg->frequency));
+	SET_CHECKED(rf69_set_bit_rate	(dev->spi, rx_cfg->bit_rate));
+	SET_CHECKED(rf69_set_modulation	(dev->spi, rx_cfg->modulation));
+	SET_CHECKED(rf69_set_antenna_impedance	 (dev->spi, rx_cfg->antenna_impedance));
+	SET_CHECKED(rf69_set_rssi_threshold	 (dev->spi, rx_cfg->rssi_threshold));
+	SET_CHECKED(rf69_set_ook_threshold_dec	 (dev->spi, rx_cfg->thresholdDecrement));
+	SET_CHECKED(rf69_set_bandwidth 		 (dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent));
+	SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent));
+	SET_CHECKED(rf69_set_dagc 		 (dev->spi, rx_cfg->dagc));
+
+	dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop;
+
+	/* packet config */
+	/* enable */
+	SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync));
+	if (rx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always));
+	}
+	SET_CHECKED(rf69_set_packet_format  (dev->spi, rx_cfg->enable_length_byte));
+	SET_CHECKED(rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering));
+	SET_CHECKED(rf69_set_crc_enable	    (dev->spi, rx_cfg->enable_crc));
+
+	/* lengths */
+	SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
+	if (rx_cfg->enable_length_byte == optionOn)
+	{
+		SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff));
+	}
+	else if (rx_cfg->fixed_message_length != 0)
+	{
+		payload_length = rx_cfg->fixed_message_length;
+		if (rx_cfg->enable_length_byte  == optionOn) payload_length++;
+		if (rx_cfg->enable_address_filtering != filteringOff) payload_length++;
+		SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
+	}
+
+	/* values */
+	if (rx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern));
+	}
+	if (rx_cfg->enable_address_filtering != filteringOff)
+	{
+		SET_CHECKED(rf69_set_node_address     (dev->spi, rx_cfg->node_address));
+		SET_CHECKED(rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address));
+	}
+
+	return 0;
+}
+
+static int
+rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
+{
+	SET_CHECKED(rf69_set_frequency	(dev->spi, tx_cfg->frequency));
+	SET_CHECKED(rf69_set_bit_rate	(dev->spi, tx_cfg->bit_rate));
+	SET_CHECKED(rf69_set_modulation	(dev->spi, tx_cfg->modulation));
+	SET_CHECKED(rf69_set_deviation	(dev->spi, tx_cfg->dev_frequency));
+	SET_CHECKED(rf69_set_pa_ramp	(dev->spi, tx_cfg->pa_ramp));
+	SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping));
+	SET_CHECKED(rf69_set_tx_start_condition(dev->spi, tx_cfg->tx_start_condition));
+
+	/* packet format enable */
+	if (tx_cfg->enable_preamble == optionOn)
+	{
+		SET_CHECKED(rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
+	}
+	SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
+	SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
+	SET_CHECKED(rf69_set_crc_enable	  (dev->spi, tx_cfg->enable_crc));
+
+	/* configure sync, if enabled */
+	if (tx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length));
+		SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern));
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pi433_start_rx(struct pi433_device *dev)
+{
+	int retval;
+
+	/* return without action, if no pending read request */
+	if (!dev->rx_active)
+		return 0;
+
+	/* setup for receiving */
+	retval = rf69_set_rx_cfg(dev, &dev->rx_cfg);
+	if (retval) return retval;
+
+	/* setup rssi irq */
+	SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0));
+	dev->irq_state[DIO0] = DIO_Rssi_DIO0;
+	irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+	/* setup fifo level interrupt */
+	SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD));
+	SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel));
+	dev->irq_state[DIO1] = DIO_FifoLevel;
+	irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING);
+
+	/* set module to receiving mode */
+	SET_CHECKED(rf69_set_mode(dev->spi, receive));
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int
+pi433_receive(void *data)
+{
+	struct pi433_device *dev = data;
+	struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */
+	int bytes_to_read, bytes_total;
+	int retval;
+
+	dev->interrupt_rx_allowed = false;
+
+	/* wait for any tx to finish */
+	dev_dbg(dev->dev,"rx: going to wait for any tx to finish");
+	retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
+	if(retval) /* wait was interrupted */
+	{
+		dev->interrupt_rx_allowed = true;
+		wake_up_interruptible(&dev->tx_wait_queue);
+		return retval;
+	}
+
+	/* prepare status vars */
+	dev->free_in_fifo = FIFO_SIZE;
+	dev->rx_position = 0;
+	dev->rx_bytes_dropped = 0;
+
+	/* setup radio module to listen for something "in the air" */
+	retval = pi433_start_rx(dev);
+	if (retval)
+		return retval;
+
+	/* now check RSSI, if low wait for getting high (RSSI interrupt) */
+	while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) )
+	{
+		/* allow tx to interrupt us while waiting for high RSSI */
+		dev->interrupt_rx_allowed = true;
+		wake_up_interruptible(&dev->tx_wait_queue);
+
+		/* wait for RSSI level to become high */
+		dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
+		retval = wait_event_interruptible(dev->rx_wait_queue,
+			                          rf69_get_flag(dev->spi,
+		                                                rssiExceededThreshold));
+		if (retval) goto abort; /* wait was interrupted */
+		dev->interrupt_rx_allowed = false;
+
+		/* cross check for ongoing tx */
+		if (!dev->tx_active) break;
+	}
+
+	/* configure payload ready irq */
+	SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady));
+	dev->irq_state[DIO0] = DIO_PayloadReady;
+	irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+	/* fixed or unlimited length? */
+	if (dev->rx_cfg.fixed_message_length != 0)
+	{
+		if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size)
+		{
+			retval = -1;
+			goto abort;
+		}
+		bytes_total = dev->rx_cfg.fixed_message_length;
+		dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total);
+	}
+	else
+	{
+		bytes_total = dev->rx_buffer_size;
+		dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total);
+	}
+
+	/* length byte enabled? */
+	if (dev->rx_cfg.enable_length_byte == optionOn)
+	{
+		retval = wait_event_interruptible(dev->fifo_wait_queue,
+						  dev->free_in_fifo < FIFO_SIZE);
+		if (retval) goto abort; /* wait was interrupted */
+
+		rf69_read_fifo(spi, (u8 *)&bytes_total, 1);
+		if (bytes_total > dev->rx_buffer_size)
+		{
+			retval = -1;
+			goto abort;
+		}
+		dev->free_in_fifo++;
+		dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total);
+	}
+
+	/* address byte enabled? */
+	if (dev->rx_cfg.enable_address_filtering != filteringOff)
+	{
+		u8 dummy;
+
+		bytes_total--;
+
+		retval = wait_event_interruptible(dev->fifo_wait_queue,
+						  dev->free_in_fifo < FIFO_SIZE);
+		if (retval) goto abort; /* wait was interrupted */
+
+		rf69_read_fifo(spi, &dummy, 1);
+		dev->free_in_fifo++;
+		dev_dbg(dev->dev, "rx: address byte stripped off");
+	}
+
+	/* get payload */
+	while (dev->rx_position < bytes_total)
+	{
+		if ( !rf69_get_flag(dev->spi, payloadReady) )
+		{
+			retval = wait_event_interruptible(dev->fifo_wait_queue,
+							  dev->free_in_fifo < FIFO_SIZE);
+			if (retval) goto abort; /* wait was interrupted */
+		}
+
+		/* need to drop bytes or acquire? */
+		if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+			bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+		else
+			bytes_to_read = bytes_total - dev->rx_position;
+
+
+		/* access the fifo */
+		if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo)
+			bytes_to_read = FIFO_SIZE - dev->free_in_fifo;
+		retval = rf69_read_fifo(spi,
+					&dev->rx_buffer[dev->rx_position],
+					bytes_to_read);
+		if (retval) goto abort; /* read failed */
+		dev->free_in_fifo += bytes_to_read;
+
+		/* adjust status vars */
+		if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+			dev->rx_bytes_dropped += bytes_to_read;
+		else
+			dev->rx_position += bytes_to_read;
+	}
+
+
+	/* rx done, wait was interrupted or error occured */
+abort:
+	dev->interrupt_rx_allowed = true;
+	SET_CHECKED(rf69_set_mode(dev->spi, standby));
+	wake_up_interruptible(&dev->tx_wait_queue);
+
+	if (retval)
+		return retval;
+	else
+		return bytes_total;
+}
+
+int
+pi433_tx_thread(void *data)
+{
+	struct pi433_device *device = data;
+	struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
+	struct pi433_tx_cfg tx_cfg;
+	u8     buffer[MAX_MSG_SIZE];
+	size_t size;
+	bool   rx_interrupted = false;
+	int    position, repetitions;
+	int    retval;
+
+	while (1)
+	{
+		/* wait for fifo to be populated or for request to terminate*/
+		dev_dbg(device->dev, "thread: going to wait for new messages");
+		wait_event_interruptible(device->tx_wait_queue,
+					 ( !kfifo_is_empty(&device->tx_fifo) ||
+					    kthread_should_stop() ));
+		if ( kthread_should_stop() )
+			return 0;
+
+		/* get data from fifo in the following order:
+		   - tx_cfg
+		   - size of message
+		   - message */
+		mutex_lock(&device->tx_fifo_lock);
+
+		retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
+		if (retval != sizeof(tx_cfg))
+		{
+			dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) );
+			mutex_unlock(&device->tx_fifo_lock);
+			continue;
+		}
+
+		retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
+		if (retval != sizeof(size_t))
+		{
+			dev_dbg(device->dev, "reading msg size from fifo failed: got %d, expected %d", retval, (unsigned int)sizeof(size_t) );
+			mutex_unlock(&device->tx_fifo_lock);
+			continue;
+		}
+
+		/* use fixed message length, if requested */
+		if (tx_cfg.fixed_message_length != 0)
+			size = tx_cfg.fixed_message_length;
+
+		/* increase size, if len byte is requested */
+		if (tx_cfg.enable_length_byte == optionOn)
+			size++;
+
+		/* increase size, if adr byte is requested */
+		if (tx_cfg.enable_address_byte == optionOn)
+			size++;
+
+		/* prime buffer */
+		memset(buffer, 0, size);
+		position = 0;
+
+		/* add length byte, if requested */
+		if (tx_cfg.enable_length_byte  == optionOn)
+			buffer[position++] = size-1; /* according to spec length byte itself must be excluded from the length calculation */
+
+		/* add adr byte, if requested */
+		if (tx_cfg.enable_address_byte == optionOn)
+			buffer[position++] = tx_cfg.address_byte;
+
+		/* finally get message data from fifo */
+		retval = kfifo_out(&device->tx_fifo, &buffer[position], sizeof(buffer)-position );
+		dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval);
+		mutex_unlock(&device->tx_fifo_lock);
+
+		/* if rx is active, we need to interrupt the waiting for
+		   incoming telegrams, to be able to send something.
+		   We are only allowed, if currently no reception takes
+		   place otherwise we need to  wait for the incoming telegram
+		   to finish */
+		wait_event_interruptible(device->tx_wait_queue,
+					 !device->rx_active ||
+					  device->interrupt_rx_allowed == true);
+
+		/* prevent race conditions
+		   irq will be reenabled after tx config is set */
+		disable_irq(device->irq_num[DIO0]);
+		device->tx_active = true;
+
+		if (device->rx_active && rx_interrupted == false)
+		{
+			/* rx is currently waiting for a telegram;
+			   we need to set the radio module to standby */
+			SET_CHECKED(rf69_set_mode(device->spi, standby));
+			rx_interrupted = true;
+		}
+
+		/* clear fifo, set fifo threshold, set payload length */
+		SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */
+		SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD));
+		if (tx_cfg.enable_length_byte == optionOn)
+		{
+			SET_CHECKED(rf69_set_payload_length(spi, size * tx_cfg.repetitions));
+		}
+		else
+		{
+			SET_CHECKED(rf69_set_payload_length(spi, 0));
+		}
+
+		/* configure the rf chip */
+		rf69_set_tx_cfg(device, &tx_cfg);
+
+		/* enable fifo level interrupt */
+		SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel));
+		device->irq_state[DIO1] = DIO_FifoLevel;
+		irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING);
+
+		/* enable packet sent interrupt */
+		SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent));
+		device->irq_state[DIO0] = DIO_PacketSent;
+		irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+		enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check */
+
+		/* enable transmission */
+		SET_CHECKED(rf69_set_mode(spi, transmit));
+
+		/* transfer this msg (and repetitions) to chip fifo */
+		device->free_in_fifo = FIFO_SIZE;
+		position = 0;
+		repetitions = tx_cfg.repetitions;
+		while( (repetitions > 0) && (size > position) )
+		{
+			if ( (size - position) > device->free_in_fifo)
+			{	/* msg to big for fifo - take a part */
+				int temp = device->free_in_fifo;
+				device->free_in_fifo = 0;
+				rf69_write_fifo(spi,
+				                &buffer[position],
+				                temp);
+				position +=temp;
+			}
+			else
+			{	/* msg fits into fifo - take all */
+				device->free_in_fifo -= size;
+				repetitions--;
+				rf69_write_fifo(spi,
+						&buffer[position],
+						(size - position) );
+				position = 0; /* reset for next repetition */
+			}
+
+			retval = wait_event_interruptible(device->fifo_wait_queue,
+							  device->free_in_fifo > 0);
+			if (retval) { printk("ABORT\n"); goto abort; }
+		}
+
+		/* we are done. Wait for packet to get sent */
+		dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be empty");
+		wait_event_interruptible(device->fifo_wait_queue,
+					 device->free_in_fifo == FIFO_SIZE ||
+					 kthread_should_stop() );
+		if ( kthread_should_stop() )	printk("ABORT\n");
+
+
+		/* STOP_TRANSMISSION */
+		dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.");
+		SET_CHECKED(rf69_set_mode(spi, standby));
+
+		/* everything sent? */
+		if ( kfifo_is_empty(&device->tx_fifo) )
+		{
+abort:
+			if (rx_interrupted)
+			{
+				rx_interrupted = false;
+				pi433_start_rx(device);
+			}
+			device->tx_active = false;
+			wake_up_interruptible(&device->rx_wait_queue);
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t
+pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	unsigned int		bytes_received;
+	ssize_t			retval;
+
+	/* check, whether internal buffer is big enough for requested size */
+	if (size > MAX_MSG_SIZE)
+		return -EMSGSIZE;
+
+	instance = filp->private_data;
+	device = instance->device;
+
+	/* just one read request at a time */
+	mutex_lock(&device->rx_lock);
+	if (device->rx_active)
+	{
+		mutex_unlock(&device->rx_lock);
+		return -EAGAIN;
+	}
+	else
+	{
+		device->rx_active = true;
+		mutex_unlock(&device->rx_lock);
+	}
+
+	/* start receiving */
+	/* will block until something was received*/
+	device->rx_buffer_size = size;
+	bytes_received = pi433_receive(device);
+
+	/* release rx */
+	mutex_lock(&device->rx_lock);
+	device->rx_active = false;
+	mutex_unlock(&device->rx_lock);
+
+	/* if read was successful copy to user space*/
+	if (bytes_received >= 0)
+	{
+		retval = copy_to_user(buf, device->rx_buffer, bytes_received);
+		if (retval)
+			return retval;
+	}
+
+	return bytes_received;
+}
+
+
+static ssize_t
+pi433_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	int                     copied, retval;
+
+	instance = filp->private_data;
+	device = instance->device;
+
+	/* check, whether internal buffer (tx thread) is big enough for requested size */
+	if (count > MAX_MSG_SIZE)
+		return -EMSGSIZE;
+
+	/* write the following sequence into fifo:
+	   - tx_cfg
+	   - size of message
+	   - message */
+	mutex_lock(&device->tx_fifo_lock);
+	retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg));
+	if ( retval != sizeof(instance->tx_cfg) )
+		goto abort;
+
+	retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t));
+	if ( retval != sizeof(size_t) )
+		goto abort;
+
+	retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied);
+	if (retval || copied != count)
+		goto abort;
+
+	mutex_unlock(&device->tx_fifo_lock);
+
+	/* start transfer */
+	wake_up_interruptible(&device->tx_wait_queue);
+	dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied);
+
+	return 0;
+
+abort:
+	dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
+	kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to discard already stored, valid entries
+	mutex_unlock(&device->tx_fifo_lock);
+	return -EAGAIN;
+}
+
+
+static long
+pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int			err = 0;
+	int			retval = 0;
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	u32			tmp;
+
+	/* Check type and command number */
+	if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
+		return -ENOTTY;
+
+	/* Check access direction once here; don't repeat below.
+	 * IOC_DIR is from the user perspective, while access_ok is
+	 * from the kernel perspective; so they look reversed.
+	 */
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok(VERIFY_WRITE,
+				 (void __user *)arg,
+				 _IOC_SIZE(cmd));
+
+	if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok(VERIFY_READ,
+				 (void __user *)arg,
+				 _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	/* TODO? guard against device removal before, or while,
+	 * we issue this ioctl. --> device_get()
+	 */
+	instance = filp->private_data;
+	device = instance->device;
+
+	if (device == NULL)
+		return -ESHUTDOWN;
+
+	switch (cmd) {
+	case PI433_IOC_RD_TX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+		{
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_to_user((void __user *)arg,
+				    &instance->tx_cfg,
+				    tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+	case PI433_IOC_WR_TX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+		{
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_from_user(&instance->tx_cfg,
+				     (void __user *)arg,
+				     tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+
+	case PI433_IOC_RD_RX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_to_user((void __user *)arg,
+				   &device->rx_cfg,
+				   tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+	case PI433_IOC_WR_RX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		mutex_lock(&device->rx_lock);
+
+		/* during pendig read request, change of config not allowed */
+		if (device->rx_active) {
+			retval = -EAGAIN;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+			retval = -EINVAL;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		if (__copy_from_user(&device->rx_cfg,
+				     (void __user *)arg,
+				     tmp))
+		{
+			retval = -EFAULT;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		mutex_unlock(&device->rx_lock);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define pi433_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_open(struct inode *inode, struct file *filp)
+{
+	struct pi433_device	*device;
+	struct pi433_instance	*instance;
+
+	mutex_lock(&minor_lock);
+	device = idr_find(&pi433_idr, iminor(inode));
+
+	mutex_unlock(&minor_lock);
+	if (!device) {
+		dev_dbg(device->dev, "device: minor %d unknown.\n", iminor(inode));
+		return -ENODEV;
+	}
+
+	if (!device->rx_buffer) {
+		device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL);
+		if (!device->rx_buffer)
+		{
+			dev_dbg(device->dev, "open/ENOMEM\n");
+			return -ENOMEM;
+		}
+	}
+
+	device->users++;
+	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+	if (!instance)
+	{
+		kfree(device->rx_buffer);
+		device->rx_buffer = NULL;
+		return -ENOMEM;
+	}
+
+	/* setup instance data*/
+	instance->device = device;
+	instance->tx_cfg.bit_rate = 4711;
+	// TODO: fill instance->tx_cfg;
+
+	/* instance data as context */
+	filp->private_data = instance;
+	nonseekable_open(inode, filp);
+
+	return 0;
+}
+
+static int pi433_release(struct inode *inode, struct file *filp)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+
+	instance = filp->private_data;
+	device = instance->device;
+	kfree(instance);
+	filp->private_data = NULL;
+
+	/* last close? */
+	device->users--;
+
+	if (!device->users) {
+		kfree(device->rx_buffer);
+		device->rx_buffer = NULL;
+		if (device->spi == NULL)
+			kfree(device);
+	}
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int setup_GPIOs(struct pi433_device *device)
+{
+	char 	name[5];
+	int	retval;
+	int	i;
+
+	for (i=0; i<NUM_DIO; i++)
+	{
+		/* "construct" name and get the gpio descriptor */
+		snprintf(name, sizeof(name), "DIO%d", i);
+		device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+
+		if (device->gpiod[i] == ERR_PTR(-ENOENT))
+		{
+			dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name);
+			continue;
+		}
+
+		if (device->gpiod[i] == ERR_PTR(-EBUSY))
+			dev_dbg(&device->spi->dev, "%s is busy.", name);
+
+		if ( IS_ERR(device->gpiod[i]) )
+		{
+			retval = PTR_ERR(device->gpiod[i]);
+			/* release already allocated gpios */
+			for (i--; i>=0; i--)
+			{
+				free_irq(device->irq_num[i], device);
+				gpiod_put(device->gpiod[i]);
+			}
+			return retval;
+		}
+
+
+		/* configure the pin */
+		gpiod_unexport(device->gpiod[i]);
+		retval = gpiod_direction_input(device->gpiod[i]);
+		if (retval) return retval;
+
+
+		/* configure irq */
+		device->irq_num[i] = gpiod_to_irq(device->gpiod[i]);
+		if (device->irq_num[i] < 0)
+		{
+			device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc *)device->irq_num[i];
+			return device->irq_num[i];
+		}
+		retval = request_irq(device->irq_num[i],
+				     DIO_irq_handler[i],
+				     0, /* flags */
+				     name,
+				     device);
+
+		if (retval)
+			return retval;
+
+		dev_dbg(&device->spi->dev, "%s succesfully configured", name);
+	}
+
+	return 0;
+}
+
+static void free_GPIOs(struct pi433_device *device)
+{
+	int i;
+
+	for (i=0; i<NUM_DIO; i++)
+	{
+		/* check if gpiod is valid */
+		if ( IS_ERR(device->gpiod[i]) )
+			continue;
+
+		free_irq(device->irq_num[i], device);
+		gpiod_put(device->gpiod[i]);
+	}
+	return;
+}
+
+static int pi433_get_minor(struct pi433_device *device)
+{
+	int retval = -ENOMEM;
+
+	mutex_lock(&minor_lock);
+	retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL);
+	if (retval >= 0) {
+		device->minor = retval;
+		retval = 0;
+	} else if (retval == -ENOSPC) {
+		dev_err(device->dev, "too many pi433 devices\n");
+		retval = -EINVAL;
+	}
+	mutex_unlock(&minor_lock);
+	return retval;
+}
+
+static void pi433_free_minor(struct pi433_device *dev)
+{
+	mutex_lock(&minor_lock);
+	idr_remove(&pi433_idr, dev->minor);
+	mutex_unlock(&minor_lock);
+}
+/*-------------------------------------------------------------------------*/
+
+static const struct file_operations pi433_fops = {
+	.owner =	THIS_MODULE,
+	/* REVISIT switch to aio primitives, so that userspace
+	 * gets more complete API coverage.  It'll simplify things
+	 * too, except for the locking.
+	 */
+	.write =	pi433_write,
+	.read =		pi433_read,
+	.unlocked_ioctl = pi433_ioctl,
+	.compat_ioctl = pi433_compat_ioctl,
+	.open =		pi433_open,
+	.release =	pi433_release,
+	.llseek =	no_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_probe(struct spi_device *spi)
+{
+	struct pi433_device	*device;
+	int			retval;
+
+	/* setup spi parameters */
+	spi->mode = 0x00;
+	spi->bits_per_word = 8;
+	/* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay */
+
+	retval = spi_setup(spi);
+	if (retval)
+	{
+		dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
+		return retval;
+	}
+	else
+	{
+		dev_dbg(&spi->dev,
+			"spi interface setup: mode 0x%2x, %d bits per word, %dhz max speed",
+			spi->mode, spi->bits_per_word, spi->max_speed_hz);
+	}
+
+	/* Ping the chip by reading the version register */
+	retval = spi_w8r8(spi, 0x10);
+	if (retval < 0)
+		return retval;
+
+	switch(retval)
+	{
+		case 0x24:
+			dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
+			break;
+		default:
+			dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
+			return -ENODEV;
+	}
+
+	/* Allocate driver data */
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	/* Initialize the driver data */
+	device->spi = spi;
+	device->rx_active = false;
+	device->tx_active = false;
+	device->interrupt_rx_allowed = false;
+
+	/* init wait queues */
+	init_waitqueue_head(&device->tx_wait_queue);
+	init_waitqueue_head(&device->rx_wait_queue);
+	init_waitqueue_head(&device->fifo_wait_queue);
+
+	/* init fifo */
+	INIT_KFIFO(device->tx_fifo);
+
+	/* init mutexes and locks */
+	mutex_init(&device->tx_fifo_lock);
+	mutex_init(&device->rx_lock);
+
+	/* setup GPIO (including irq_handler) for the different DIOs */
+	retval = setup_GPIOs(device);
+	if (retval)
+	{
+		dev_dbg(&spi->dev, "setup of GPIOs failed");
+		goto GPIO_failed;
+	}
+
+	/* setup the radio module */
+	SET_CHECKED(rf69_set_mode		(spi, standby));
+	SET_CHECKED(rf69_set_data_mode		(spi, packet));
+	SET_CHECKED(rf69_set_amplifier_0	(spi, optionOn));
+	SET_CHECKED(rf69_set_amplifier_1	(spi, optionOff));
+	SET_CHECKED(rf69_set_amplifier_2	(spi, optionOff));
+	SET_CHECKED(rf69_set_output_power_level	(spi, 13));
+	SET_CHECKED(rf69_set_antenna_impedance	(spi, fiftyOhm));
+
+	/* start tx thread */
+	device->tx_task_struct = kthread_run(pi433_tx_thread,
+					     device,
+					     "pi433_tx_task");
+	if (device->tx_task_struct < 0)
+	{
+		dev_dbg(device->dev, "start of send thread failed");
+		goto send_thread_failed;
+	}
+
+	/* determ minor number */
+	retval = pi433_get_minor(device);
+	if (retval)
+	{
+		dev_dbg(device->dev, "get of minor number failed");
+		goto minor_failed;
+	}
+
+	/* create device */
+	device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
+	device->dev = device_create(pi433_class,
+				    &spi->dev,
+				    device->devt,
+				    device,
+				    "pi433");
+	if (IS_ERR(device->dev)) {
+		pr_err("pi433: device register failed\n");
+		retval = PTR_ERR(device->dev);
+		goto device_create_failed;
+	}
+	else {
+		dev_dbg(device->dev,
+			"created device for major %d, minor %d\n",
+			MAJOR(pi433_dev),
+			device->minor);
+	}
+
+	/* create cdev */
+	device->cdev = cdev_alloc();
+	device->cdev->owner = THIS_MODULE;
+	cdev_init(device->cdev, &pi433_fops);
+	retval = cdev_add(device->cdev, device->devt, 1);
+	if (retval)
+	{
+		dev_dbg(device->dev, "register of cdev failed");
+		goto cdev_failed;
+	}
+
+	/* spi setup */
+	spi_set_drvdata(spi, device);
+
+	return 0;
+
+cdev_failed:
+	device_destroy(pi433_class, device->devt);
+device_create_failed:
+	pi433_free_minor(device);
+minor_failed:
+	kthread_stop(device->tx_task_struct);
+send_thread_failed:
+	free_GPIOs(device);
+GPIO_failed:
+	kfree(device);
+
+	return retval;
+}
+
+static int pi433_remove(struct spi_device *spi)
+{
+	struct pi433_device	*device = spi_get_drvdata(spi);
+
+	/* free GPIOs */
+	free_GPIOs(device);
+
+	/* make sure ops on existing fds can abort cleanly */
+	device->spi = NULL;
+
+	kthread_stop(device->tx_task_struct);
+
+	device_destroy(pi433_class, device->devt);
+
+	cdev_del(device->cdev);
+
+	pi433_free_minor(device);
+
+	if (device->users == 0)
+		kfree(device);
+
+	return 0;
+}
+
+static const struct of_device_id pi433_dt_ids[] = {
+	{ .compatible = "Smarthome-Wolf,pi433" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, pi433_dt_ids);
+
+static struct spi_driver pi433_spi_driver = {
+	.driver = {
+		.name =		"pi433",
+		.owner =	THIS_MODULE,
+		.of_match_table = of_match_ptr(pi433_dt_ids),
+	},
+	.probe =	pi433_probe,
+	.remove =	pi433_remove,
+
+	/* NOTE:  suspend/resume methods are not necessary here.
+	 * We don't do anything except pass the requests to/from
+	 * the underlying controller.  The refrigerator handles
+	 * most issues; the controller driver handles the rest.
+	 */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init pi433_init(void)
+{
+	int status;
+
+	/* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't
+           work stable - risk of buffer overflow */
+	if (MAX_MSG_SIZE < FIFO_SIZE)
+		return -EINVAL;
+
+	/* Claim device numbers.  Then register a class
+	 * that will key udev/mdev to add/remove /dev nodes.  Last, register
+	 * Last, register the driver which manages those device numbers.
+	 */
+	status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/);
+	if (status < 0)
+		return status;
+
+	pi433_class = class_create(THIS_MODULE, "pi433");
+	if (IS_ERR(pi433_class))
+	{
+		unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+		return PTR_ERR(pi433_class);
+	}
+
+	status = spi_register_driver(&pi433_spi_driver);
+	if (status < 0)
+	{
+		class_destroy(pi433_class);
+		unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+	}
+
+	return status;
+}
+
+module_init(pi433_init);
+
+static void __exit pi433_exit(void)
+{
+	spi_unregister_driver(&pi433_spi_driver);
+	class_destroy(pi433_class);
+	unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+}
+module_exit(pi433_exit);
+
+MODULE_AUTHOR("Marcus Wolf, <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>");
+MODULE_DESCRIPTION("Driver for Pi433");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:pi433");
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
new file mode 100644
index 0000000..e6ed3cd
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.h
@@ -0,0 +1,152 @@
+/*
+ * include/linux/TODO
+ *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR 	0
+struct pi433_tx_cfg
+{
+	__u32			frequency;
+	__u16			bit_rate;
+	__u32			dev_frequency;
+	enum modulation		modulation;
+	enum modShaping		modShaping;
+
+	enum paRamp		pa_ramp;
+
+	enum txStartCondition	tx_start_condition;
+
+	__u16			repetitions;
+
+
+	/* packet format */
+	enum optionOnOff	enable_preamble;
+	enum optionOnOff	enable_sync;
+	enum optionOnOff	enable_length_byte;
+	enum optionOnOff	enable_address_byte;
+	enum optionOnOff	enable_crc;
+
+	__u16			preamble_length;
+	__u8			sync_length;
+	__u8			fixed_message_length;
+
+	__u8			sync_pattern[8];
+	__u8			address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR 	1
+struct pi433_rx_cfg {
+	__u32			frequency;
+	__u16			bit_rate;
+	__u32			dev_frequency;
+
+	enum modulation		modulation;
+
+	__u8			rssi_threshold;
+	enum thresholdDecrement	thresholdDecrement;
+	enum antennaImpedance	antenna_impedance;
+	enum lnaGain		lna_gain;
+	enum mantisse		bw_mantisse;	/* normal: 0x50 */
+	__u8			bw_exponent;	/* during AFC: 0x8b */
+	enum dagc		dagc;
+
+
+
+	/* packet format */
+	enum optionOnOff	enable_sync;
+	enum optionOnOff	enable_length_byte;	  /* should be used in combination with sync, only */
+	enum addressFiltering	enable_address_filtering; /* operational with sync, only */
+	enum optionOnOff	enable_crc;		  /* only operational, if sync on and fixed length or length byte is used */
+
+	__u8			sync_length;
+	__u8			fixed_message_length;
+	__u32			bytes_to_drop;
+
+	__u8			sync_pattern[8];
+	__u8			node_address;
+	__u8			broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC			'r'
+
+#define PI433_IOC_RD_TX_CFG	_IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG	_IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG	_IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG	_IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
new file mode 100644
index 0000000..b6bc45b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.c
@@ -0,0 +1,982 @@
+/*
+ * abstraction of the spi interface of HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* enable prosa debug info */
+#undef DEBUG
+/* enable print of values on reg access */
+#undef DEBUG_VALUES
+/* enable print of values on fifo access */
+#undef DEBUG_FIFO_ACCESS
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include "rf69.h"
+#include "rf69_registers.h"
+
+#define F_OSC	  32000000 /* in Hz */
+#define FIFO_SIZE 66 	   /* in byte */
+
+/*-------------------------------------------------------------------------*/
+
+#define READ_REG(x)	rf69_read_reg (spi, x)
+#define WRITE_REG(x,y)	rf69_write_reg(spi, x, y)
+#define INVALID_PARAM \
+	{ \
+		dev_dbg(&spi->dev, "set: illegal input param"); \
+		return -EINVAL; \
+	}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: mode");
+	#endif
+
+	switch (mode){
+	case transmit:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT);
+	case receive:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE);
+	case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER);
+	case standby:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY);
+	case mode_sleep:  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP);
+	default:	  INVALID_PARAM;
+	}
+
+	// we are using packet mode, so this check is not really needed
+	// but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode
+	//while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
+
+}
+
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: data mode");
+	#endif
+
+	switch (dataMode) {
+	case packet:		return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET);
+	case continuous:	return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS);
+	case continuousNoSync:  return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS_NOSYNC);
+	default:		INVALID_PARAM;
+	}
+}
+
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: modulation");
+	#endif
+
+	switch (modulation) {
+	case OOK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK);
+	case FSK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK);
+	default:    INVALID_PARAM;
+	}
+}
+
+enum modulation rf69_get_modulation(struct spi_device *spi)
+{
+	u8 currentValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: mode");
+	#endif
+
+	currentValue = READ_REG(REG_DATAMODUL);
+
+	switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3)  // TODO improvement: change 3 to define
+	{
+	case DATAMODUL_MODULATION_TYPE_OOK: return OOK;
+	case DATAMODUL_MODULATION_TYPE_FSK: return FSK;
+	default:			    return undefined;
+	}
+}
+
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: mod shaping");
+	#endif
+
+	if (rf69_get_modulation(spi) == FSK)
+	{
+		switch (modShaping) {
+		case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE);
+		case shaping1_0: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_1_0);
+		case shaping0_5: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_3);
+		case shaping0_3: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_5);
+		default:	 INVALID_PARAM;
+		}
+	}
+	else
+	{
+		switch (modShaping) {
+		case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE);
+		case shapingBR:	 return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_BR);
+		case shaping2BR: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_2BR);
+		default:	 INVALID_PARAM;
+		}
+	}
+}
+
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+{
+	int retval;
+	u32 bitRate_min;
+	u32 bitRate_reg;
+	u8 msb;
+	u8 lsb;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: bit rate");
+	#endif
+
+	// check input value
+	bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
+	if (bitRate < bitRate_min)
+	{
+		dev_dbg(&spi->dev, "setBitRate: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculate reg settings
+	bitRate_reg = (F_OSC / bitRate);
+
+	msb = (bitRate_reg&0xff00)   >>  8;
+	lsb = (bitRate_reg&0xff);
+
+	// transmit to RF 69
+	retval = WRITE_REG(REG_BITRATE_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_BITRATE_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_deviation(struct spi_device *spi, u32 deviation)
+{
+	int retval;
+//	u32 f_max; TODO: Abhängigkeit von Bitrate beachten!!
+	u64 f_reg;
+	u64 f_step;
+	u8 msb;
+	u8 lsb;
+	u64 factor = 1000000; // to improve precision of calculation
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: deviation");
+	#endif
+
+	if (deviation < 600 || deviation > 500000) //TODO: Abhängigkeit von Bitrate beachten!!
+	{
+		dev_dbg(&spi->dev, "set_deviation: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculat f step
+	f_step = F_OSC * factor;
+	do_div(f_step, 524288); //  524288 = 2^19
+
+	// calculate register settings
+	f_reg = deviation * factor;
+	do_div(f_reg  , f_step);
+
+	msb = (f_reg&0xff00)   >>  8;
+	lsb = (f_reg&0xff);
+
+	// check msb
+	if (msb & !FDEVMASB_MASK)
+	{
+		dev_dbg(&spi->dev, "set_deviation: err in calc of msb");
+		INVALID_PARAM;
+	}
+
+	// write to chip
+	retval = WRITE_REG(REG_FDEV_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FDEV_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_frequency(struct spi_device *spi, u32 frequency)
+{
+	int retval;
+	u32 f_max;
+	u64 f_reg;
+	u64 f_step;
+	u8 msb;
+	u8 mid;
+	u8 lsb;
+	u64 factor = 1000000; // to improve precision of calculation
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: frequency");
+	#endif
+
+	// calculat f step
+	f_step = F_OSC * factor;
+	do_div(f_step, 524288); //  524288 = 2^19
+
+	// check input value
+	f_max = f_step * 8388608 / factor;
+	if (frequency > f_max)
+	{
+		dev_dbg(&spi->dev, "setFrequency: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculate reg settings
+	f_reg = frequency * factor;
+	do_div(f_reg  , f_step);
+
+	msb = (f_reg&0xff0000) >> 16;
+	mid = (f_reg&0xff00)   >>  8;
+	lsb = (f_reg&0xff);
+
+	// write to chip
+	retval = WRITE_REG(REG_FRF_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FRF_MID, mid);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FRF_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #0");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA0) );
+	case optionOff:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA0) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #1");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA1) );
+	case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA1) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #2");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA2) );
+	case optionOff:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA2) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: power level");
+	#endif
+
+	powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting
+
+	// check input value
+	if (powerLevel > 0x1f)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_OUTPUT_POWER) | powerLevel);
+}
+
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: pa ramp");
+	#endif
+
+	switch(paRamp) {
+	case ramp3400:	return WRITE_REG(REG_PARAMP, PARAMP_3400);
+	case ramp2000:	return WRITE_REG(REG_PARAMP, PARAMP_2000);
+	case ramp1000:	return WRITE_REG(REG_PARAMP, PARAMP_1000);
+	case ramp500:	return WRITE_REG(REG_PARAMP, PARAMP_500);
+	case ramp250:	return WRITE_REG(REG_PARAMP, PARAMP_250);
+	case ramp125:	return WRITE_REG(REG_PARAMP, PARAMP_125);
+	case ramp100:	return WRITE_REG(REG_PARAMP, PARAMP_100);
+	case ramp62:	return WRITE_REG(REG_PARAMP, PARAMP_62);
+	case ramp50:	return WRITE_REG(REG_PARAMP, PARAMP_50);
+	case ramp40:	return WRITE_REG(REG_PARAMP, PARAMP_40);
+	case ramp31:	return WRITE_REG(REG_PARAMP, PARAMP_31);
+	case ramp25:	return WRITE_REG(REG_PARAMP, PARAMP_25);
+	case ramp20:	return WRITE_REG(REG_PARAMP, PARAMP_20);
+	case ramp15:	return WRITE_REG(REG_PARAMP, PARAMP_15);
+	case ramp12:	return WRITE_REG(REG_PARAMP, PARAMP_12);
+	case ramp10:	return WRITE_REG(REG_PARAMP, PARAMP_10);
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: antenna impedance");
+	#endif
+
+	switch(antennaImpedance) {
+	case fiftyOhm:	    return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) & ~MASK_LNA_ZIN) );
+	case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) |  MASK_LNA_ZIN) );
+	default:	    INVALID_PARAM;
+	}
+}
+
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: lna gain");
+	#endif
+
+	switch(lnaGain) {
+	case automatic:	 return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_AUTO) );
+	case max:	 return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX) );
+	case maxMinus6:  return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) );
+	case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) );
+	case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) );
+	case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) );
+	case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) );
+	default:	 INVALID_PARAM;
+	}
+}
+
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi)
+{
+	u8 currentValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: lna gain");
+	#endif
+
+	currentValue = READ_REG(REG_LNA);
+
+	switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3)  // improvement: change 3 to define
+	{
+	case LNA_GAIN_AUTO:	    return automatic;
+	case LNA_GAIN_MAX:	    return max;
+	case LNA_GAIN_MAX_MINUS_6:  return maxMinus6;
+	case LNA_GAIN_MAX_MINUS_12: return maxMinus12;
+	case LNA_GAIN_MAX_MINUS_24: return maxMinus24;
+	case LNA_GAIN_MAX_MINUS_36: return maxMinus36;
+	case LNA_GAIN_MAX_MINUS_48: return maxMinus48;
+	default:		    return undefined;
+	}
+}
+
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum dccPercent dccPercent)
+{
+	switch (dccPercent) {
+	case dcc16Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) );
+	case dcc8Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) );
+	case dcc4Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) );
+	case dcc2Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) );
+	case dcc1Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) );
+	case dcc0_5Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) );
+	case dcc0_25Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) );
+	case dcc0_125Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) );
+	default:		INVALID_PARAM;
+	}
+}
+
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: cut off freq");
+	#endif
+
+	return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent);
+}
+
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: cut off freq during afc");
+	#endif
+
+	return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent);
+}
+
+int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse mantisse, u8 exponent)
+{
+	u8 newValue;
+
+	// check value for mantisse and exponent
+	if (exponent > 7)   INVALID_PARAM;
+	if ( (mantisse!=mantisse16) &&
+	     (mantisse!=mantisse20) &&
+             (mantisse!=mantisse24) ) INVALID_PARAM;
+
+	// read old value
+	newValue = READ_REG(reg);
+
+	// "delete" mantisse and exponent = just keep the DCC setting
+	newValue = newValue & MASK_BW_DCC_FREQ;
+
+	// add new mantisse
+	switch(mantisse) {
+	case mantisse16: newValue = newValue | BW_MANT_16;	break;
+	case mantisse20: newValue = newValue | BW_MANT_20;	break;
+	case mantisse24: newValue = newValue | BW_MANT_24;	break;
+	}
+
+	// add new exponent
+	newValue = newValue | exponent;
+
+	// write back
+	return WRITE_REG(reg, newValue);
+}
+
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: band width");
+	#endif
+
+	return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent);
+}
+
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: band width during afc");
+	#endif
+
+	return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
+}
+
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold type");
+	#endif
+
+	switch (thresholdType)
+	{
+	case fixed:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) );
+	case peak:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) );
+	case average:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold step");
+	#endif
+
+	switch (thresholdStep) {
+	case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) );
+	case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) );
+	case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) );
+	case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) );
+	case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) );
+	case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) );
+	case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) );
+	case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) );
+	default:	 INVALID_PARAM;
+	}
+}
+
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold decrement");
+	#endif
+
+	switch (thresholdDecrement) {
+	case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) );
+	case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) );
+	case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) );
+	case dec_once:	   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) );
+	case dec_twice:	   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) );
+	case dec_4times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) );
+	case dec_8times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) );
+	case dec_16times:  return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) );
+	default:	   INVALID_PARAM;
+	}
+}
+
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+{
+	u8 mask;
+	u8 shift;
+	u8 regaddr;
+	u8 regValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: DIO mapping");
+	#endif
+
+	// check DIO number
+	if (DIONumber > 5) INVALID_PARAM;
+
+	switch (DIONumber) {
+	case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break;
+	case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break;
+	case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break;
+	case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break;
+	case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break;
+	case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break;
+	}
+
+	// read reg
+	regValue=READ_REG(regaddr);
+	// delete old value
+	regValue = regValue & ~mask;
+	// add new value
+	regValue = regValue | value << shift;
+	// write back
+	return WRITE_REG(regaddr,regValue);
+}
+
+bool rf69_get_flag(struct spi_device *spi, enum flag flag)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: flag");
+	#endif
+
+	switch(flag) {
+	case modeSwitchCompleted:     return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_MODE_READY);
+	case readyToReceive:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RX_READY);
+	case readyToSend:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TX_READY);
+	case pllLocked:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_PLL_LOCK);
+	case rssiExceededThreshold:   return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI);
+	case timeout:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TIMEOUT);
+	case automode:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_AUTOMODE);
+	case syncAddressMatch:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+	case fifoFull:		      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_FULL);
+/*	case fifoNotEmpty:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */
+	case fifoEmpty:		      return !(READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY);
+	case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_LEVEL);
+	case fifoOverrun:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_OVERRUN);
+	case packetSent:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PACKET_SENT);
+	case payloadReady:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PAYLOAD_READY);
+	case crcOk:		      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_CRC_OK);
+	case batteryLow:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_LOW_BAT);
+	default:		      return false;
+	}
+}
+
+int rf69_reset_flag(struct spi_device *spi, enum flag flag)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "reset: flag");
+	#endif
+
+	switch(flag) {
+	case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_RSSI);
+	case syncAddressMatch:	    return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+	case fifoOverrun:	    return WRITE_REG(REG_IRQFLAGS2, MASK_IRQFLAGS2_FIFO_OVERRUN);
+	default:		    INVALID_PARAM;
+	}
+}
+
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: rssi threshold");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RSSITHRESH, threshold);
+}
+
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: start timeout");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RXTIMEOUT1, timeout);
+}
+
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: rssi timeout");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RXTIMEOUT2, timeout);
+}
+
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+{
+	int retval;
+	u8 msb, lsb;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: preample length");
+	#endif
+
+	/* no value check needed - u16 exactly matches register size */
+
+	/* calculate reg settings */
+	msb = (preambleLength&0xff00)   >>  8;
+	lsb = (preambleLength&0xff);
+
+	/* transmit to chip */
+	retval = WRITE_REG(REG_PREAMBLE_MSB, msb);
+	if (retval) return retval;
+	retval = WRITE_REG(REG_PREAMBLE_LSB, lsb);
+
+	return retval;
+}
+
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync enable");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_SYNC_ON) );
+	case optionOff:	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: fifo fill condition");
+	#endif
+
+	switch(fifoFillCondition) {
+	case always:		 return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+	case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+	default:		 INVALID_PARAM;
+	}
+}
+
+int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync size");
+	#endif
+
+	// check input value
+	if (syncSize > 0x07)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) );
+}
+
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync tolerance");
+	#endif
+
+	// check input value
+	if (syncTolerance > 0x07)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance);
+}
+
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+{
+	int retval = 0;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync values");
+	#endif
+
+	retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]);
+	retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]);
+	retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]);
+	retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]);
+	retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]);
+	retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]);
+	retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]);
+	retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]);
+
+	return retval;
+}
+
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat packetFormat)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: packet format");
+	#endif
+
+	switch(packetFormat) {
+	case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+	case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+	default:	      INVALID_PARAM;
+	}
+}
+
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: crc enable");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_CRC_ON) );
+	case optionOff:	return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: address filtering");
+	#endif
+
+	switch (addressFiltering) {
+	case filteringOff:	     return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_OFF) );
+	case nodeAddress:	     return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODE) );
+	case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) );
+	default:		     INVALID_PARAM;
+	}
+}
+
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: payload length");
+	#endif
+
+	return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength);
+}
+
+u8  rf69_get_payload_length(struct spi_device *spi)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: payload length");
+	#endif
+
+	return (u8) READ_REG(REG_PAYLOAD_LENGTH);
+}
+
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: node address");
+	#endif
+
+	return WRITE_REG(REG_NODEADRS, nodeAddress);
+}
+
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: broadcast address");
+	#endif
+
+	return WRITE_REG(REG_BROADCASTADRS, broadcastAddress);
+}
+
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: start condition");
+	#endif
+
+	switch(txStartCondition) {
+	case fifoLevel:	   return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) );
+	case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) |  MASK_FIFO_THRESH_TXSTART) );
+	default:	   INVALID_PARAM;
+	}
+}
+
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
+{
+	int retval;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: fifo threshold");
+	#endif
+
+	// check input value
+	if (threshold & 0x80)
+		INVALID_PARAM;
+
+	// write value
+	retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_VALUE) | threshold);
+	if (retval)
+		return retval;
+
+	// access the fifo to activate new threshold
+	return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer
+}
+
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: dagc");
+	#endif
+
+	switch(dagc) {
+	case normalMode:		 return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL);
+	case improve:			 return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA0);
+	case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA1);
+	default:			 INVALID_PARAM;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+	#ifdef DEBUG_FIFO_ACCESS
+		int i;
+	#endif
+	struct spi_transfer transfer;
+	u8 local_buffer[FIFO_SIZE + 1];
+	int retval;
+
+	if (size > FIFO_SIZE)
+	{
+		#ifdef DEBUG
+			dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n");
+		#endif
+		return -EMSGSIZE;
+	}
+
+	/* prepare a bidirectional transfer */
+	local_buffer[0] = REG_FIFO;
+	memset(&transfer, 0, sizeof(transfer));
+  	transfer.tx_buf = local_buffer;
+  	transfer.rx_buf = local_buffer;
+	transfer.len	= size+1;
+
+	retval = spi_sync_transfer(spi, &transfer, 1);
+
+	#ifdef DEBUG_FIFO_ACCESS
+		for (i=0; i<size; i++)
+			dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]);
+	#endif
+
+	memcpy(buffer, &local_buffer[1], size);  // TODO: ohne memcopy wäre schöner
+
+	return retval;
+}
+
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+	#ifdef DEBUG_FIFO_ACCESS
+		int i;
+	#endif
+	char spi_address = REG_FIFO | WRITE_BIT;
+	u8 local_buffer[FIFO_SIZE + 1];
+
+	if (size > FIFO_SIZE)
+	{
+		#ifdef DEBUG
+			dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n");
+		#endif
+		return -EMSGSIZE;
+	}
+
+	local_buffer[0] = spi_address;
+	memcpy(&local_buffer[1], buffer, size);  // TODO: ohne memcopy wäre schöner
+
+	#ifdef DEBUG_FIFO_ACCESS
+		for (i=0; i<size; i++)
+			dev_dbg(&spi->dev, "0x%x\n",buffer[i]);
+	#endif
+
+	return spi_write (spi, local_buffer, size + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+u8 rf69_read_reg(struct spi_device *spi, u8 addr)
+{
+	int retval;
+
+	retval = spi_w8r8(spi, addr);
+
+	#ifdef DEBUG_VALUES
+		if (retval < 0)
+			/* should never happen, since we already checked,
+			   that module is connected. Therefore no error
+			   handling, just an optional error message... */
+			dev_dbg(&spi->dev, "read 0x%x FAILED\n",
+				addr);
+		else
+			dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n",
+				retval,
+				addr);
+	#endif
+
+	return retval;
+}
+
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value)
+{
+	int retval;
+	char buffer[2];
+
+	buffer[0] = addr | WRITE_BIT;
+	buffer[1] = value;
+
+	retval = spi_write(spi, &buffer, 2);
+
+	#ifdef DEBUG_VALUES
+		if (retval < 0)
+			/* should never happen, since we already checked,
+			   that module is connected. Therefore no error
+			   handling, just an optional error message... */
+			dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n",
+				value,
+				addr);
+		else
+			dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n",
+				value,
+				addr);
+	#endif
+
+	return retval;
+}
+
+
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
new file mode 100644
index 0000000..6a6841b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.h
@@ -0,0 +1,82 @@
+/*
+ * hardware abstraction/register access for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef RF69_H
+#define RF69_H
+
+#include "rf69_enum.h"
+#include "rf69_registers.h"
+
+#define F_OSC 		32000000  /* in Hz */
+#define FREQUENCY	433920000 /* in Hz, modifying this value impacts CE certification */
+#define FIFO_SIZE 	66        /* in byte */
+#define FIFO_THRESHOLD	15 	  /* in byte */
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode);
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode);
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
+enum modulation rf69_get_modulation(struct spi_device *spi);
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_deviation(struct spi_device *spi, u32 deviation);
+int rf69_set_frequency(struct spi_device *spi, u32 frequency);
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi);
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent);
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType);
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+bool rf69_get_flag(struct spi_device *spi, enum flag flag);
+int rf69_reset_flag(struct spi_device *spi, enum flag flag);
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition);
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance);
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat packetFormat);
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering);
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength);
+u8  rf69_get_payload_length(struct spi_device *spi);
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition);
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size);
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size);
+
+u8  rf69_read_reg (struct spi_device *spi, u8 addr);
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value);
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_enum.h b/drivers/staging/pi433/rf69_enum.h
new file mode 100644
index 0000000..fbfb59b
--- /dev/null
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -0,0 +1,201 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_registers.h b/drivers/staging/pi433/rf69_registers.h
new file mode 100644
index 0000000..d0c4992
--- /dev/null
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -0,0 +1,489 @@
+/*
+ * register description for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*******************************************/
+/* RF69 register addresses		   */
+/*******************************************/
+#define  REG_FIFO			0x00
+#define  REG_OPMODE			0x01
+#define  REG_DATAMODUL			0x02
+#define  REG_BITRATE_MSB		0x03
+#define  REG_BITRATE_LSB		0x04
+#define  REG_FDEV_MSB			0x05
+#define  REG_FDEV_LSB			0x06
+#define  REG_FRF_MSB			0x07
+#define  REG_FRF_MID			0x08
+#define  REG_FRF_LSB			0x09
+#define  REG_OSC1			0x0A
+#define  REG_AFCCTRL			0x0B
+#define  REG_LOWBAT			0x0C
+#define  REG_LISTEN1			0x0D
+#define  REG_LISTEN2			0x0E
+#define  REG_LISTEN3			0x0F
+#define  REG_VERSION			0x10
+#define  REG_PALEVEL			0x11
+#define  REG_PARAMP			0x12
+#define  REG_OCP			0x13
+#define  REG_AGCREF			0x14 /* not available on RF69 */
+#define  REG_AGCTHRESH1			0x15 /* not available on RF69 */
+#define  REG_AGCTHRESH2			0x16 /* not available on RF69 */
+#define  REG_AGCTHRESH3			0x17 /* not available on RF69 */
+#define  REG_LNA			0x18
+#define  REG_RXBW			0x19
+#define  REG_AFCBW			0x1A
+#define  REG_OOKPEAK			0x1B
+#define  REG_OOKAVG			0x1C
+#define  REG_OOKFIX			0x1D
+#define  REG_AFCFEI			0x1E
+#define  REG_AFCMSB			0x1F
+#define  REG_AFCLSB			0x20
+#define  REG_FEIMSB			0x21
+#define  REG_FEILSB			0x22
+#define  REG_RSSICONFIG			0x23
+#define  REG_RSSIVALUE			0x24
+#define  REG_DIOMAPPING1		0x25
+#define  REG_DIOMAPPING2		0x26
+#define  REG_IRQFLAGS1			0x27
+#define  REG_IRQFLAGS2			0x28
+#define  REG_RSSITHRESH			0x29
+#define  REG_RXTIMEOUT1			0x2A
+#define  REG_RXTIMEOUT2			0x2B
+#define  REG_PREAMBLE_MSB		0x2C
+#define  REG_PREAMBLE_LSB		0x2D
+#define  REG_SYNC_CONFIG		0x2E
+#define  REG_SYNCVALUE1			0x2F
+#define  REG_SYNCVALUE2			0x30
+#define  REG_SYNCVALUE3			0x31
+#define  REG_SYNCVALUE4			0x32
+#define  REG_SYNCVALUE5			0x33
+#define  REG_SYNCVALUE6			0x34
+#define  REG_SYNCVALUE7			0x35
+#define  REG_SYNCVALUE8			0x36
+#define  REG_PACKETCONFIG1		0x37
+#define  REG_PAYLOAD_LENGTH		0x38
+#define  REG_NODEADRS			0x39
+#define  REG_BROADCASTADRS		0x3A
+#define  REG_AUTOMODES			0x3B
+#define  REG_FIFO_THRESH		0x3C
+#define  REG_PACKETCONFIG2		0x3D
+#define  REG_AESKEY1			0x3E
+#define  REG_AESKEY2			0x3F
+#define  REG_AESKEY3			0x40
+#define  REG_AESKEY4			0x41
+#define  REG_AESKEY5			0x42
+#define  REG_AESKEY6			0x43
+#define  REG_AESKEY7			0x44
+#define  REG_AESKEY8			0x45
+#define  REG_AESKEY9			0x46
+#define  REG_AESKEY10			0x47
+#define  REG_AESKEY11			0x48
+#define  REG_AESKEY12			0x49
+#define  REG_AESKEY13			0x4A
+#define  REG_AESKEY14			0x4B
+#define  REG_AESKEY15			0x4C
+#define  REG_AESKEY16			0x4D
+#define  REG_TEMP1			0x4E
+#define  REG_TEMP2			0x4F
+#define  REG_TESTPA1			0x5A /* only present on RFM69HW */
+#define  REG_TESTPA2			0x5C /* only present on RFM69HW */
+#define  REG_TESTDAGC			0x6F
+
+/******************************************************/
+/* RF69/SX1231 bit definition				*/
+/******************************************************/
+/* write bit */
+#define WRITE_BIT				0x80
+
+/* RegOpMode */
+#define  MASK_OPMODE_SEQUENCER_OFF		0x80
+#define  MASK_OPMODE_LISTEN_ON			0x40
+#define  MASK_OPMODE_LISTEN_ABORT		0x20
+#define  MASK_OPMODE_MODE			0x1C
+
+#define  OPMODE_MODE_SLEEP			0x00
+#define  OPMODE_MODE_STANDBY			0x04 /* default */
+#define  OPMODE_MODE_SYNTHESIZER		0x08
+#define  OPMODE_MODE_TRANSMIT			0x0C
+#define  OPMODE_MODE_RECEIVE			0x10
+
+/* RegDataModul */
+#define  MASK_DATAMODUL_MODE			0x06
+#define  MASK_DATAMODUL_MODULATION_TYPE		0x18
+#define  MASK_DATAMODUL_MODULATION_SHAPE	0x03
+
+#define  DATAMODUL_MODE_PACKET			0x00 /* default */
+#define  DATAMODUL_MODE_CONTINUOUS		0x40
+#define  DATAMODUL_MODE_CONTINUOUS_NOSYNC	0x60
+
+#define  DATAMODUL_MODULATION_TYPE_FSK		0x00 /* default */
+#define  DATAMODUL_MODULATION_TYPE_OOK		0x08
+
+#define  DATAMODUL_MODULATION_SHAPE_NONE	0x00 /* default */
+#define  DATAMODUL_MODULATION_SHAPE_1_0		0x01
+#define  DATAMODUL_MODULATION_SHAPE_0_5		0x02
+#define  DATAMODUL_MODULATION_SHAPE_0_3		0x03
+#define  DATAMODUL_MODULATION_SHAPE_BR		0x01
+#define  DATAMODUL_MODULATION_SHAPE_2BR		0x02
+
+/* RegFDevMsb (0x05)*/
+#define FDEVMASB_MASK				0x3f
+
+/*
+// RegOsc1
+#define  OSC1_RCCAL_START			0x80
+#define  OSC1_RCCAL_DONE			0x40
+
+// RegLowBat
+#define  LOWBAT_MONITOR				0x10
+#define  LOWBAT_ON				0x08
+#define  LOWBAT_OFF				0x00  // Default
+
+#define  LOWBAT_TRIM_1695			0x00
+#define  LOWBAT_TRIM_1764			0x01
+#define  LOWBAT_TRIM_1835			0x02  // Default
+#define  LOWBAT_TRIM_1905			0x03
+#define  LOWBAT_TRIM_1976			0x04
+#define  LOWBAT_TRIM_2045			0x05
+#define  LOWBAT_TRIM_2116			0x06
+#define  LOWBAT_TRIM_2185			0x07
+
+
+// RegListen1
+#define  LISTEN1_RESOL_64			0x50
+#define  LISTEN1_RESOL_4100			0xA0  // Default
+#define  LISTEN1_RESOL_262000			0xF0
+
+#define  LISTEN1_CRITERIA_RSSI			0x00  // Default
+#define  LISTEN1_CRITERIA_RSSIANDSYNC		0x08
+
+#define  LISTEN1_END_00				0x00
+#define  LISTEN1_END_01				0x02  // Default
+#define  LISTEN1_END_10				0x04
+
+
+// RegListen2
+#define  LISTEN2_COEFIDLE_VALUE			0xF5 // Default
+
+// RegListen3
+#define  LISTEN3_COEFRX_VALUE			0x20 // Default
+*/
+
+// RegPaLevel
+#define  MASK_PALEVEL_PA0			0x80
+#define  MASK_PALEVEL_PA1			0x40
+#define  MASK_PALEVEL_PA2			0x20
+#define  MASK_PALEVEL_OUTPUT_POWER		0x1F
+
+
+
+// RegPaRamp
+#define  PARAMP_3400				0x00
+#define  PARAMP_2000				0x01
+#define  PARAMP_1000				0x02
+#define  PARAMP_500				0x03
+#define  PARAMP_250				0x04
+#define  PARAMP_125				0x05
+#define  PARAMP_100				0x06
+#define  PARAMP_62				0x07
+#define  PARAMP_50				0x08
+#define  PARAMP_40				0x09 /* default */
+#define  PARAMP_31				0x0A
+#define  PARAMP_25				0x0B
+#define  PARAMP_20				0x0C
+#define  PARAMP_15				0x0D
+#define  PARAMP_12				0x0E
+#define  PARAMP_10				0x0F
+
+#define  MASK_PARAMP				0x0F
+
+/*
+// RegOcp
+#define  OCP_OFF				0x0F
+#define  OCP_ON					0x1A  // Default
+
+#define  OCP_TRIM_45				0x00
+#define  OCP_TRIM_50				0x01
+#define  OCP_TRIM_55				0x02
+#define  OCP_TRIM_60				0x03
+#define  OCP_TRIM_65				0x04
+#define  OCP_TRIM_70				0x05
+#define  OCP_TRIM_75				0x06
+#define  OCP_TRIM_80				0x07
+#define  OCP_TRIM_85				0x08
+#define  OCP_TRIM_90				0x09
+#define  OCP_TRIM_95				0x0A
+#define  OCP_TRIM_100				0x0B  // Default
+#define  OCP_TRIM_105				0x0C
+#define  OCP_TRIM_110				0x0D
+#define  OCP_TRIM_115				0x0E
+#define  OCP_TRIM_120				0x0F
+*/
+
+/* RegLna (0x18) */
+#define  MASK_LNA_ZIN				0x80
+#define  MASK_LNA_CURRENT_GAIN			0x38
+#define  MASK_LNA_GAIN				0x07
+
+#define  LNA_GAIN_AUTO				0x00 /* default */
+#define  LNA_GAIN_MAX				0x01
+#define  LNA_GAIN_MAX_MINUS_6			0x02
+#define  LNA_GAIN_MAX_MINUS_12			0x03
+#define  LNA_GAIN_MAX_MINUS_24			0x04
+#define  LNA_GAIN_MAX_MINUS_36			0x05
+#define  LNA_GAIN_MAX_MINUS_48			0x06
+
+
+/* RegRxBw (0x19) and RegAfcBw (0x1A) */
+#define  MASK_BW_DCC_FREQ			0xE0
+#define  MASK_BW_MANTISSE			0x18
+#define  MASK_BW_EXPONENT			0x07
+
+#define  BW_DCC_16_PERCENT			0x00
+#define  BW_DCC_8_PERCENT			0x20
+#define  BW_DCC_4_PERCENT			0x40 /* default */
+#define  BW_DCC_2_PERCENT			0x60
+#define  BW_DCC_1_PERCENT			0x80
+#define  BW_DCC_0_5_PERCENT			0xA0
+#define  BW_DCC_0_25_PERCENT			0xC0
+#define  BW_DCC_0_125_PERCENT			0xE0
+
+#define  BW_MANT_16				0x00
+#define  BW_MANT_20				0x08
+#define  BW_MANT_24				0x10 /* default */
+
+
+/* RegOokPeak (0x1B) */
+#define  MASK_OOKPEAK_THRESTYPE			0xc0
+#define  MASK_OOKPEAK_THRESSTEP			0x38
+#define  MASK_OOKPEAK_THRESDEC			0x07
+
+#define  OOKPEAK_THRESHTYPE_FIXED		0x00
+#define  OOKPEAK_THRESHTYPE_PEAK		0x40 /* default */
+#define  OOKPEAK_THRESHTYPE_AVERAGE		0x80
+
+#define  OOKPEAK_THRESHSTEP_0_5_DB		0x00 /* default */
+#define  OOKPEAK_THRESHSTEP_1_0_DB		0x08
+#define  OOKPEAK_THRESHSTEP_1_5_DB		0x10
+#define  OOKPEAK_THRESHSTEP_2_0_DB		0x18
+#define  OOKPEAK_THRESHSTEP_3_0_DB		0x20
+#define  OOKPEAK_THRESHSTEP_4_0_DB		0x28
+#define  OOKPEAK_THRESHSTEP_5_0_DB		0x30
+#define  OOKPEAK_THRESHSTEP_6_0_DB		0x38
+
+#define  OOKPEAK_THRESHDEC_ONCE			0x00 /* default */
+#define  OOKPEAK_THRESHDEC_EVERY_2ND		0x01
+#define  OOKPEAK_THRESHDEC_EVERY_4TH		0x02
+#define  OOKPEAK_THRESHDEC_EVERY_8TH		0x03
+#define  OOKPEAK_THRESHDEC_TWICE		0x04
+#define  OOKPEAK_THRESHDEC_4_TIMES		0x05
+#define  OOKPEAK_THRESHDEC_8_TIMES		0x06
+#define  OOKPEAK_THRESHDEC_16_TIMES		0x07
+
+/*
+// RegOokAvg
+#define  OOKAVG_AVERAGETHRESHFILT_00		0x00
+#define  OOKAVG_AVERAGETHRESHFILT_01		0x40
+#define  OOKAVG_AVERAGETHRESHFILT_10		0x80  // Default
+#define  OOKAVG_AVERAGETHRESHFILT_11		0xC0
+
+
+// RegAfcFei
+#define  AFCFEI_FEI_DONE			0x40
+#define  AFCFEI_FEI_START			0x20
+#define  AFCFEI_AFC_DONE			0x10
+#define  AFCFEI_AFCAUTOCLEAR_ON			0x08
+#define  AFCFEI_AFCAUTOCLEAR_OFF		0x00  // Default
+
+#define  AFCFEI_AFCAUTO_ON			0x04
+#define  AFCFEI_AFCAUTO_OFF			0x00  // Default
+
+#define  AFCFEI_AFC_CLEAR			0x02
+#define  AFCFEI_AFC_START			0x01
+
+// RegRssiConfig
+#define  RSSI_FASTRX_ON				0x08
+#define  RSSI_FASTRX_OFF			0x00  // Default
+#define  RSSI_DONE				0x02
+#define  RSSI_START				0x01
+*/
+
+/* RegDioMapping1 */
+#define  MASK_DIO0				0xC0
+#define  MASK_DIO1				0x30
+#define  MASK_DIO2				0x0C
+#define  MASK_DIO3				0x03
+#define  SHIFT_DIO0				6
+#define  SHIFT_DIO1				4
+#define  SHIFT_DIO2				2
+#define  SHIFT_DIO3				0
+
+/* RegDioMapping2 */
+#define  MASK_DIO4				0xC0
+#define  MASK_DIO5				0x30
+#define  SHIFT_DIO4				6
+#define  SHIFT_DIO5				4
+
+/* DIO numbers */
+#define  DIO0					0
+#define  DIO1					1
+#define  DIO2					2
+#define  DIO3					3
+#define  DIO4					4
+#define  DIO5					5
+
+/* DIO Mapping values (packet mode) */
+#define  DIO_ModeReady_DIO4			0x00
+#define  DIO_ModeReady_DIO5			0x03
+#define  DIO_ClkOut				0x00
+#define  DIO_Data				0x01
+#define  DIO_TimeOut_DIO1			0x03
+#define  DIO_TimeOut_DIO4			0x00
+#define  DIO_Rssi_DIO0				0x03
+#define  DIO_Rssi_DIO3_4			0x01
+#define  DIO_RxReady				0x02
+#define  DIO_PLLLock				0x03
+#define  DIO_TxReady				0x01
+#define  DIO_FifoFull_DIO1			0x01
+#define  DIO_FifoFull_DIO3			0x00
+#define  DIO_SyncAddress			0x02
+#define  DIO_FifoNotEmpty_DIO1			0x02
+#define  DIO_FifoNotEmpty_FIO2			0x00
+#define  DIO_Automode				0x04
+#define  DIO_FifoLevel				0x00
+#define  DIO_CrcOk				0x00
+#define  DIO_PayloadReady			0x01
+#define  DIO_PacketSent				0x00
+#define  DIO_Dclk				0x00
+
+/* RegDioMapping2 CLK_OUT part */
+#define  MASK_DIOMAPPING2_CLK_OUT		0x07
+
+#define  DIOMAPPING2_CLK_OUT_NO_DIV		0x00
+#define  DIOMAPPING2_CLK_OUT_DIV_2		0x01
+#define  DIOMAPPING2_CLK_OUT_DIV_4		0x02
+#define  DIOMAPPING2_CLK_OUT_DIV_8		0x03
+#define  DIOMAPPING2_CLK_OUT_DIV_16		0x04
+#define  DIOMAPPING2_CLK_OUT_DIV_32		0x05
+#define  DIOMAPPING2_CLK_OUT_RC			0x06
+#define  DIOMAPPING2_CLK_OUT_OFF		0x07 /* default */
+
+/* RegIrqFlags1 */
+#define  MASK_IRQFLAGS1_MODE_READY		0x80
+#define  MASK_IRQFLAGS1_RX_READY		0x40
+#define  MASK_IRQFLAGS1_TX_READY		0x20
+#define  MASK_IRQFLAGS1_PLL_LOCK		0x10
+#define  MASK_IRQFLAGS1_RSSI			0x08
+#define  MASK_IRQFLAGS1_TIMEOUT			0x04
+#define  MASK_IRQFLAGS1_AUTOMODE		0x02
+#define  MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH	0x01
+
+/* RegIrqFlags2 */
+#define  MASK_IRQFLAGS2_FIFO_FULL		0x80
+#define  MASK_IRQFLAGS2_FIFO_NOT_EMPTY		0x40
+#define  MASK_IRQFLAGS2_FIFO_LEVEL		0x20
+#define  MASK_IRQFLAGS2_FIFO_OVERRUN		0x10
+#define  MASK_IRQFLAGS2_PACKET_SENT		0x08
+#define  MASK_IRQFLAGS2_PAYLOAD_READY		0x04
+#define  MASK_IRQFLAGS2_CRC_OK			0x02
+#define  MASK_IRQFLAGS2_LOW_BAT			0x01
+
+/* RegSyncConfig */
+#define  MASK_SYNC_CONFIG_SYNC_ON		0x80 /* default */
+#define  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION	0x40
+#define  MASK_SYNC_CONFIG_SYNC_SIZE		0x38
+#define  MASK_SYNC_CONFIG_SYNC_TOLERANCE	0x07
+
+/* RegPacketConfig1 */
+#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE	0x80
+#define  MASK_PACKETCONFIG1_DCFREE			0x60
+#define  MASK_PACKETCONFIG1_CRC_ON			0x10 /* default */
+#define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF		0x08
+#define  MASK_PACKETCONFIG1_ADDRESSFILTERING		0x06
+
+#define  PACKETCONFIG1_DCFREE_OFF			0x00 /* default */
+#define  PACKETCONFIG1_DCFREE_MANCHESTER		0x20
+#define  PACKETCONFIG1_DCFREE_WHITENING			0x40
+#define  PACKETCONFIG1_ADDRESSFILTERING_OFF		0x00 /* default */
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODE		0x02
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST	0x04
+
+/*
+// RegAutoModes
+#define  AUTOMODES_ENTER_OFF			0x00  // Default
+#define  AUTOMODES_ENTER_FIFONOTEMPTY		0x20
+#define  AUTOMODES_ENTER_FIFOLEVEL		0x40
+#define  AUTOMODES_ENTER_CRCOK			0x60
+#define  AUTOMODES_ENTER_PAYLOADREADY		0x80
+#define  AUTOMODES_ENTER_SYNCADRSMATCH		0xA0
+#define  AUTOMODES_ENTER_PACKETSENT		0xC0
+#define  AUTOMODES_ENTER_FIFOEMPTY		0xE0
+
+#define  AUTOMODES_EXIT_OFF			0x00  // Default
+#define  AUTOMODES_EXIT_FIFOEMPTY		0x04
+#define  AUTOMODES_EXIT_FIFOLEVEL		0x08
+#define  AUTOMODES_EXIT_CRCOK			0x0C
+#define  AUTOMODES_EXIT_PAYLOADREADY		0x10
+#define  AUTOMODES_EXIT_SYNCADRSMATCH		0x14
+#define  AUTOMODES_EXIT_PACKETSENT		0x18
+#define  AUTOMODES_EXIT_RXTIMEOUT		0x1C
+
+#define  AUTOMODES_INTERMEDIATE_SLEEP		0x00  // Default
+#define  AUTOMODES_INTERMEDIATE_STANDBY		0x01
+#define  AUTOMODES_INTERMEDIATE_RECEIVER	0x02
+#define  AUTOMODES_INTERMEDIATE_TRANSMITTER	0x03
+
+*/
+/* RegFifoThresh (0x3c) */
+#define  MASK_FIFO_THRESH_TXSTART		0x80
+#define  MASK_FIFO_THRESH_VALUE			0x7F
+
+/*
+
+// RegPacketConfig2
+#define  PACKET2_RXRESTARTDELAY_1BIT		0x00  // Default
+#define  PACKET2_RXRESTARTDELAY_2BITS		0x10
+#define  PACKET2_RXRESTARTDELAY_4BITS		0x20
+#define  PACKET2_RXRESTARTDELAY_8BITS		0x30
+#define  PACKET2_RXRESTARTDELAY_16BITS		0x40
+#define  PACKET2_RXRESTARTDELAY_32BITS		0x50
+#define  PACKET2_RXRESTARTDELAY_64BITS		0x60
+#define  PACKET2_RXRESTARTDELAY_128BITS		0x70
+#define  PACKET2_RXRESTARTDELAY_256BITS		0x80
+#define  PACKET2_RXRESTARTDELAY_512BITS		0x90
+#define  PACKET2_RXRESTARTDELAY_1024BITS	0xA0
+#define  PACKET2_RXRESTARTDELAY_2048BITS	0xB0
+#define  PACKET2_RXRESTARTDELAY_NONE		0xC0
+#define  PACKET2_RXRESTART			0x04
+
+#define  PACKET2_AUTORXRESTART_ON		0x02  // Default
+#define  PACKET2_AUTORXRESTART_OFF		0x00
+
+#define  PACKET2_AES_ON				0x01
+#define  PACKET2_AES_OFF			0x00  // Default
+
+
+// RegTemp1
+#define  TEMP1_MEAS_START			0x08
+#define  TEMP1_MEAS_RUNNING			0x04
+#define  TEMP1_ADCLOWPOWER_ON			0x01  // Default
+#define  TEMP1_ADCLOWPOWER_OFF			0x00
+*/
+
+// RegTestDagc (0x6F)
+#define  DAGC_NORMAL				0x00 /* Reset value */
+#define  DAGC_IMPROVED_LOWBETA1			0x20
+#define  DAGC_IMPROVED_LOWBETA0			0x30 /* Recommended val */
>> I absolutly agree. My patch should meet the needs of an official patch.
>
> Again, don't use html email :)
>
>> But I don't know about the exact needs. Can you please help me? What is needed
>> / missing in my patch and how do I produce it?
>> Maybe you can pass me a link, where I can read, what to do?
>
> The link I sent you, Documentation/SubmittingPatches in the kernel
> source tree, should contain everything you need to know.  As a minimum
> you need a good subject, a good changelog body text, and a
> signed-off-by: line.  The file should tell you all about how to create
> this.
>
> If you have specific questions after reading that about these things,
> please let us know.
>
> thanks,
>
> greg k-h
>
>

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: Submit of a driver for Pi433 - a radio module for Raspberry Pi
  2017-07-15 17:05                     ` Wolf Entwicklungen
  (?)
@ 2017-07-16  6:45                     ` Greg KH
  2017-07-16  9:52                         ` Wolf Entwicklungen
  -1 siblings, 1 reply; 49+ messages in thread
From: Greg KH @ 2017-07-16  6:45 UTC (permalink / raw)
  To: Wolf Entwicklungen; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

On Sat, Jul 15, 2017 at 07:05:04PM +0200, Wolf Entwicklungen wrote:
> Am Sa, 15.07.2017, 15:47 schrieb Greg KH:
> > On Sat, Jul 15, 2017 at 03:40:30PM +0200, Marcus Wolf wrote:
> >> Hi Greg,
> >>
> 
> Hi Greg,
> 
> now I added a TODO file and did a manual patchwork with lines of the old patch
> (git format-patch master --stdout -p > pi433_patch) and the newer patch (git
> diff master > pi433_patch). Stil don't know how to retreive multiple commits
> in one single patch directly from git :-/
> I did my best to meet a lot of rules of the link, you send me.If
> there is stil something essential wrong or missing, please excuse and let me know.
> 
> Especially I was in doubt about the verbosity of the change log. If you'd like
> to see the list of features of the driver over there (please see my first mail),
> let me know and I'll add.


Can you resend it without all of this stuff here, a patch email should just
contain the patch itself, look at all of the examples on the mailing
lists for how they look.

> From: Marcus Wolf <linux@Wolf-Entwicklungen.de>
> Date: Tue,15 Jul 2017 17:52:06 +0100
> Subject: [PATCH 1/1] drivers/staging/pi433: New driver
> 
> Added a driver for the pi433 radio module
> (see https://www.pi433.de/en.html for details).
> Signed-off-by: Marcus Wolf <linux@Wolf-Entwicklungen.de>

Need a blank line before signed-off-by.

> Tested-by: Marcus Wolf <linux@Wolf-Entwicklungen.de> on Raspbian, running Kernel v4.12

No need for a tested-by from something that wrote, that is implied :)

Almost there...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-16  9:52                         ` Wolf Entwicklungen
  0 siblings, 0 replies; 49+ messages in thread
From: Wolf Entwicklungen @ 2017-07-16  9:52 UTC (permalink / raw)
  To: Greg KH; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

From: Marcus Wolf <linux@Wolf-Entwicklungen.de>
Date: Tue,16 Jul 2017 11:52:06 +0100
Subject: [PATCH 1/1] drivers/staging/pi433: New driver

Added a driver for the pi433 radio module
(see https://www.pi433.de/en.html for details).

Signed-off-by: Marcus Wolf <linux@Wolf-Entwicklungen.de>
---
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 268d4e6..fdf060c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"

 source "drivers/staging/typec/Kconfig"

+source "drivers/staging/pi433/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b93e6f5..998f644 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)		+= ks7010/
 obj-$(CONFIG_GREYBUS)		+= greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)	+= vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)	+= ccree/
+obj-$(CONFIG_PI433)		+= pi433/
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
new file mode 100644
index 0000000..004b502
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
@@ -0,0 +1,53 @@
+// Definitions for Pi433
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			pi433_pins: pi433_pins {
+				brcm,pins = <7 25 24>;
+				brcm,function = <0 0 0>; // in in in
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pi433: pi433@0 {
+				compatible = "Smarthome-Wolf,pi433";
+				reg = <0>;
+				spi-max-frequency = <10000000>;
+				status = "okay";
+
+				pinctrl-0 = <&pi433_pins>;
+				DIO0-gpio = <&gpio 24 0>;
+				DIO1-gpio = <&gpio 25 0>;
+				DIO2-gpio = <&gpio  7 0>;
+			};
+		};
+	};
+};
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
new file mode 100644
index 0000000..14197c6
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
@@ -0,0 +1,62 @@
+* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see www.pi433.de)
+
+Required properties:
+- compatible: must be "Smarthome-Wolf,pi433"
+- reg: chip select of SPI Interface
+- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69 module
+
+
+Example:
+
+With the following lines in gpio-section, the gpio pins, connected with pi433 are
+reserved/declared.
+
+&gpio{
+	[...]
+
+	pi433_pins: pi433_pins {
+		brcm,pins = <7 25 24>;
+		brcm,function = <0 0 0>; // in in in
+	};
+
+	[...]
+}
+
+With the following lines in spi section, the device pi433 is declared.
+It consists of the three gpio pins and an spi interface (here chip select 0)
+
+&spi0{
+	[...]
+
+	pi433: pi433@0 {
+		compatible = "Smarthome-Wolf,pi433";
+		reg = <0>; /* CE 0 */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-max-frequency = <10000000>;
+
+		pinctrl-0 = <&pi433_pins>;
+		DIO0-gpio = <&gpio 24 0>;
+		DIO1-gpio = <&gpio 25 0>;
+		DIO2-gpio = <&gpio  7 0>;
+	};
+}
+
+
+
+For Raspbian users only
+=======================
+Since Raspbian supports device tree overlays, you may use and overlay, instead
+of editing your boards device tree.
+For using the overlay, you need to compile the file pi433-overlay.dts you can
+find aside to this documentation.
+The file needs to be compiled - either manually or by integration in your kernel
+source tree. For a manual compile, you may use a command line like the following:
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+arch/arm/boot/dts/overlays and you need to add the file to the list of files
+in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
+kernel make files compile the device tree overlay for you.
+
+
diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt
new file mode 100644
index 0000000..860dd0f
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -0,0 +1,274 @@
+=====
+Pi433
+=====
+
+
+Introduction
+============
+This driver is for controlling pi433, a radio module for the Raspberry Pi
+(www.pi433.de). It supports transmission and reception. It can be opened
+by multiple applications for transmission and reception. While transmit
+jobs were queued and process automatically in the background, the first
+application asking for reception will block out all other applications
+until something gets received terminates the read request.
+The driver supports on the fly reloading of the hardware fifo of the rf
+chip, thus enabling for much longer telegrams then hardware fifo size.
+
+Discription of driver operation
+===============================
+
+a) transmission
+
+Each transmission can take place with a different configuration of the rf
+module. Therfore each application can set its own set of parameters. The driver
+takes care, that each transmission takes place with the parameterset of the
+application, that requests the transmission. To allow the transmission to take
+place in the background, a tx thread is introduced.
+The transfer of data from the main thread to the tx thread is realised by a
+kfifo. With each write request of an application, the passed in data and the
+corresponding parameter set gets written to the kfifo.
+On the other "side" of the kfifo, the tx thread continuously checks, whether the
+kfifo is empty. If not, it gets one set of config and data from the kfifo. If
+there is no receive request or the receiver is still waiting for something in
+the air, the rf module is set to standby, the parameters for transmission gets
+set, the hardware fifo of the rf chip gets preloaded and the transmission gets
+started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling
+much longer telegrams then hardware fifo size. If the telegram is send and there
+is more data available in the kfifo, the procedure is repeated. If not the
+transmission cycle ends.
+
+b) reception
+
+Since there is only one application allowed to receive data at a time, for
+reception there is only one configuration set.
+As soon as an application sets an request for receiving a telegram, the reception
+configuration set is written to the rf module and it gets set into receiving mode.
+Now the driver is waiting, that a predefined RSSI level (signal strength at the
+receiver) is reached. Until this hasn't happened, the reception can be
+interrupted by the transmission thread at any time to insert a transmission cycle.
+As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar
+as described for the transmission cycle the read out of the hardware fifo is done
+dynamically. Upon each hardware fifo threshold interrupt, a portion of data gets
+read. So also for reception it is possible to receive more data then the hardware
+fifo can hold.
+
+
+Driver API
+==========
+
+The driver is currently implemented as a character device. Therefore it supports
+the calls open, ioctl, read, write and close.
+
+
+params for ioctl
+----------------
+
+There are four options:
+PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver
+PI433_IOC_WR_TX_CFG - set the transmission parameters
+PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver
+PI433_IOC_WR_RX_CFG - set the receiving parameters
+
+The tx configuration is transfered via struct pi433_tx_cfg, the parameterset for transmission.
+It is devided into two sections: rf parameters and packet format.
+
+rf params:
+	frequency
+		frequency used for transmission.
+		Allowed values: 433050000...434790000
+	bit_rate
+		bit rate used for transmission.
+		Allowed values: #####
+	dev_frequency
+		frequency deviation in case of FSK.
+		Allowed values: 600...500000
+	modulation
+		FSK - frequency shift key
+		OOK - On-Off-key
+	modShaping
+		shapingOff	- no shaping
+		shaping1_0	- gauss filter with BT 1 (FSK only)
+		shaping0_5	- gauss filter with BT 0.5 (FSK only)
+		shaping0_3	- gauss filter with BT 0.3 (FSK only)
+		shapingBR	- filter cut off at BR (OOK only)
+		shaping2BR	- filter cut off at 2*BR (OOK only)
+	paRamp (FSK only)
+		ramp3400	- amp ramps up in 3.4ms
+		ramp2000	- amp ramps up in 2.0ms
+		ramp1000	- amp ramps up in 1ms
+		ramp500		- amp ramps up in 500us
+		ramp250		- amp ramps up in 250us
+		ramp125		- amp ramps up in 125us
+		ramp100		- amp ramps up in 100us
+		ramp62		- amp ramps up in 62us
+		ramp50		- amp ramps up in 50us
+		ramp40		- amp ramps up in 40us
+		ramp31		- amp ramps up in 31us
+		ramp25		- amp ramps up in 25us
+		ramp20		- amp ramps up in 20us
+		ramp15		- amp ramps up in 15us
+		ramp12		- amp ramps up in 12us
+		ramp10		- amp ramps up in 10us
+	tx_start_condition
+		fifoLevel	- transmission starts, if fifo is filled to
+				  threshold level
+		fifoNotEmpty	- transmission starts, as soon as there is one
+				  byte in internal fifo
+	repetitions
+		This gives the option, to send a telegram multiple times. Default: 1
+
+packet format:
+	enable_preamble
+		optionOn	- a preamble will be automatically generated
+		optionOff	- no preamble will be generated
+	enable_sync
+		optionOn	- a sync word will be automatically added to
+				  the telegram after preamble
+		optionOff	- no sync word will be added
+		Attention: While possible to generate sync without preamble, the
+		receiver won't be able to detect the sync without preamble.
+	enable_length_byte
+		optionOn	- the length of the telegram will be automatically
+				  added to the telegram. It's part of the payload
+		optionOff	- no length information will be automatically added
+				  to the telegram.
+		Attention: For telegram length over 255 bytes, this option can't be used
+		Attention: should be used in combination with sync, only
+	enable_address_byte
+		optionOn	- the address byte will be automatically added to the
+				  telgram. It's part of the payload
+		optionOff	- the address byte will not be added to the telegram.
+		The address byte can be used for address filtering, so the receiver
+		will only receive telegrams with a given address byte.
+		Attention: should be used in combination with sync, only
+	enable_crc
+		optionOn	- an crc will be automatically calculated over the
+				  payload of the telegram and added to the telegram
+				  after payload.
+		optionOff	- no crc will be calculated
+	preamble_length
+		length of the preamble. Allowed values: 0...65536
+	sync_length
+		length of the sync word. Allowed values: 0...8
+	fixed_message_length
+		length of the payload of the telegram. Will override the length
+		given by the buffer, passed in with the write command. Will be
+		ignored if set to zero.
+	sync_pattern[8]
+		contains up to eight values, that are used as the sync pattern
+		on sync option
+	address_byte
+		one byte, used as address byte on address byte option.
+
+
+The rx configuration is transfered via struct pi433_rx_cfg, the parameterset for receiving. It is devided into two sections: rf parameters and packet format.
+
+rf params:
+	frequency
+		frequency used for transmission.
+		Allowed values: 433050000...434790000
+	bit_rate
+		bit rate used for transmission.
+		Allowed values: #####
+	dev_frequency
+		frequency deviation in case of FSK.
+		Allowed values: 600...500000
+	modulation
+		FSK - frequency shift key
+		OOK - on off key
+	rssi_threshold
+		threshold value for the signal strength on the receiver input.
+		If this value is exeeded, a reception cycle starts
+		Allowed values: 0...255
+	thresholdDecrement
+		in order to adapt to different levels of singnal strength, over
+		time the receiver gets more and more sensitive. This value
+		determs, how fast the sensitivity increases.
+		step_0_5db	- increase in 0,5dB steps
+		step_1_0db	- increase in 1 db steps
+		step_1_5db	- increase in 1,5dB steps
+		step_2_0db	- increase in 2 db steps
+		step_3_0db	- increase in 3 db steps
+		step_4_0db	- increase in 4 db steps
+		step_5_0db	- increase in 5 db steps
+		step_6_0db	- increase in 6 db steps
+	antennaImpedance
+		sets the electrical adoption of the antenna
+		fiftyOhm	- for antennas with an impedance of 50Ohm
+		twohundretOhm	- for antennas with an impedance of 200Ohm
+	lnaGain
+		sets the gain of the low noise amp
+		automatic	- lna gain is determed by an agc
+		max		- lna gain is set to maximum
+		maxMinus6	- lna gain is set to  6db below max
+		maxMinus12	- lna gain is set to 12db below max
+		maxMinus24	- lna gain is set to 24db below max
+		maxMinus36	- lna gain is set to 36db below max
+		maxMinus48	- lna gain is set to 48db below max
+	bw_mantisse
+		sets the bandwidth of the channel filter - part one: mantisse.
+		mantisse16	- mantisse is set to 16
+		mantisse20	- mantisse is set to 20
+		mantisse24	- mantisse is set to 24
+	bw_exponent
+		sets the bandwidth of the channel filter - part two: exponent.
+		Allowd values: 0...7
+	dagc;
+		operation mode of the digital automatic gain control
+		normalMode
+		improve
+		improve4LowModulationIndex
+
+ packet format:
+	enable_sync
+		optionOn  - sync detection is enabled. If configured sync pattern
+			    isn't found, telegram will be internally discarded
+		optionOff - sync detection is disabled.
+	enable_length_byte
+		optionOn   - First byte of payload will be used as length byte,
+			     regardless of the amount of bytes that were requested
+			     by the read request.
+		optionOff  - Number of bytes to be read will be set according to
+			     amount of bytes that were requested by the read request.
+		Attention: should be used in combination with sync, only
+	enable_address_filtering;
+		filteringOff		- no adress filtering will take place
+		nodeAddress		- all telegrams, not matching the node
+					  address will be internally discarded
+		nodeOrBroadcastAddress	- all telegrams, neither matching the
+					  node, nor the broadcast address will
+					  be internally discarded
+		Attention: Sync option must be enabled in order to use this feature
+	enable_crc
+		optionOn	- a crc will be calculated over the payload of
+				  the telegram, that was received. If the
+				  calculated crc doesn't match to two bytes,
+				  that follow the payload, the telegram will be
+				  internally discarded.
+		Attention: This option is only operational, if sync on and fixed length
+		or length byte is used
+	sync_length
+		Gives the length of the payload.
+		Attention: This setting must meet the setting of the transmitter,
+		if sync option is used.
+	fixed_message_length
+		Overrides the telegram length either given by the first byte of
+		payload or by the read request.
+	bytes_to_drop
+		gives the number of bytes, that will be dropped before transfering
+		data to the read buffer
+		This option is only usefull, if all packet helper are switched
+		off and the rf chip is used in raw receiving mode. This may be
+		needed, if a telegram of a third party device should be received,
+		using a protocol not compatible with the packet engine of the rf69 chip.
+	sync_pattern[8]
+		contains up to eight values, that are used as the sync pattern
+		on sync option.
+		This setting must meet the configuration of the transmitting device,
+		if sync option is enabled.
+	node_address
+		one byte, used as node address byte on address byte option.
+	broadcast_address
+		one byte, used as broadcast address byte on address byte option.
+
+
diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
new file mode 100644
index 0000000..61b4b4e
--- /dev/null
+++ b/drivers/staging/pi433/Kconfig
@@ -0,0 +1,16 @@
+config PI433
+        tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
+        default n
+        ---help---
+          This option allows you to enable support for the radio module Pi433.
+
+          Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi
+          or compatible. It extends the Raspberry Pi with the option, to
+          send and receive data in the 433MHz ISM band - for example to
+          communicate between two systems without using ethernet or bluetooth
+          or for control or read sockets, actors, sensors, widely available
+          for low price.
+
+          For details or the option to buy, please visit https://pi433.de/en.html
+
+          If in doubt, say N here, but saying yes most probably won't hurt
diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile
new file mode 100644
index 0000000..417f3e4
--- /dev/null
+++ b/drivers/staging/pi433/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PI433) += pi433.o
+
+pi433-objs := pi433_if.o rf69.o
diff --git a/drivers/staging/pi433/TODO b/drivers/staging/pi433/TODO
new file mode 100644
index 0000000..63a40bf
--- /dev/null
+++ b/drivers/staging/pi433/TODO
@@ -0,0 +1,5 @@
+* coding style does not fully comply with the kernel style guide.
+* still TODOs, annotated in the code
+* currently the code introduces new IOCTLs. I'm afraid this is a bad idea.
+  -> Replace this with another interface, hints are welcome!
+* Some missing data (marked with ###) needs to be added in the documentation
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
new file mode 100644
index 0000000..541ca78
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.c
@@ -0,0 +1,1314 @@
+/*
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+#endif
+
+#include "pi433_if.h"
+#include "rf69.h"
+
+
+#define N_PI433_MINORS			(1U << MINORBITS) /*32*/	/* ... up to 256 */
+#define MAX_MSG_SIZE			900	/* min: FIFO_SIZE! */
+#define MSG_FIFO_SIZE			65536   /* 65536 = 2^16  */
+#define NUM_DIO				2
+
+static dev_t pi433_dev;
+static DEFINE_IDR(pi433_idr);
+static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+
+static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
+
+/* tx config is instance specific
+	so with each open a new tx config struct is needed */
+/* rx config is device specific
+	so we have just one rx config, ebedded in device struct */
+struct pi433_device {
+	/* device handling related values */
+	dev_t			devt;
+	int			minor;
+	struct device		*dev;
+	struct cdev		*cdev;
+	struct spi_device	*spi;
+	unsigned		users;
+
+	/* irq related values */
+	struct gpio_desc	*gpiod[NUM_DIO];
+	int			irq_num[NUM_DIO];
+	u8			irq_state[NUM_DIO];
+
+	/* tx related values */
+	STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
+	struct mutex		tx_fifo_lock; // TODO: check, whether necessary or obsolete
+	struct task_struct	*tx_task_struct;
+	wait_queue_head_t	tx_wait_queue;
+	u8			free_in_fifo;
+
+	/* rx related values */
+	struct pi433_rx_cfg	rx_cfg;
+	u8			*rx_buffer;
+	unsigned int		rx_buffer_size;
+	u32			rx_bytes_to_drop;
+	u32			rx_bytes_dropped;
+	unsigned int		rx_position;
+	struct mutex		rx_lock;
+	wait_queue_head_t	rx_wait_queue;
+
+	/* fifo wait queue */
+	struct task_struct	*fifo_task_struct;
+	wait_queue_head_t	fifo_wait_queue;
+
+	/* flags */
+	bool			rx_active;
+	bool			tx_active;
+	bool			interrupt_rx_allowed;
+};
+
+struct pi433_instance {
+	struct pi433_device	*device;
+	struct pi433_tx_cfg	tx_cfg;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* macro for checked access of registers of radio module */
+#define SET_CHECKED(retval) \
+	if (retval < 0) \
+		return retval;
+
+/*-------------------------------------------------------------------------*/
+
+/* GPIO interrupt handlers */
+static irq_handler_t
+DIO0_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pi433_device *device = dev_id;
+
+	if      (device->irq_state[DIO0] == DIO_PacketSent)
+	{
+		device->free_in_fifo = FIFO_SIZE;
+		printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include KERN_ facility level
+		wake_up_interruptible(&device->fifo_wait_queue);
+	}
+	else if (device->irq_state[DIO0] == DIO_Rssi_DIO0)
+	{
+		printk("DIO0 irq: RSSI level over threshold\n");
+		wake_up_interruptible(&device->rx_wait_queue);
+	}
+	else if (device->irq_state[DIO0] == DIO_PayloadReady)
+	{
+		printk("DIO0 irq: PayloadReady\n");
+		device->free_in_fifo = 0;
+		wake_up_interruptible(&device->fifo_wait_queue);
+	}
+
+	return (irq_handler_t) IRQ_HANDLED;
+}
+
+static irq_handler_t
+DIO1_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pi433_device *device = dev_id;
+
+	if      (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1)
+	{
+		device->free_in_fifo = FIFO_SIZE;
+	}
+	else if (device->irq_state[DIO1] == DIO_FifoLevel)
+	{
+		if (device->rx_active)	device->free_in_fifo = FIFO_THRESHOLD - 1;
+		else			device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1;
+	}
+	printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO: printk() should include KERN_ facility level
+	wake_up_interruptible(&device->fifo_wait_queue);
+
+	return (irq_handler_t) IRQ_HANDLED;
+}
+
+static void *DIO_irq_handler[NUM_DIO] = {
+	DIO0_irq_handler,
+	DIO1_irq_handler
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
+{
+	int payload_length;
+
+	/* receiver config */
+	SET_CHECKED(rf69_set_frequency	(dev->spi, rx_cfg->frequency));
+	SET_CHECKED(rf69_set_bit_rate	(dev->spi, rx_cfg->bit_rate));
+	SET_CHECKED(rf69_set_modulation	(dev->spi, rx_cfg->modulation));
+	SET_CHECKED(rf69_set_antenna_impedance	 (dev->spi, rx_cfg->antenna_impedance));
+	SET_CHECKED(rf69_set_rssi_threshold	 (dev->spi, rx_cfg->rssi_threshold));
+	SET_CHECKED(rf69_set_ook_threshold_dec	 (dev->spi, rx_cfg->thresholdDecrement));
+	SET_CHECKED(rf69_set_bandwidth 		 (dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent));
+	SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent));
+	SET_CHECKED(rf69_set_dagc 		 (dev->spi, rx_cfg->dagc));
+
+	dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop;
+
+	/* packet config */
+	/* enable */
+	SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync));
+	if (rx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always));
+	}
+	SET_CHECKED(rf69_set_packet_format  (dev->spi, rx_cfg->enable_length_byte));
+	SET_CHECKED(rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering));
+	SET_CHECKED(rf69_set_crc_enable	    (dev->spi, rx_cfg->enable_crc));
+
+	/* lengths */
+	SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
+	if (rx_cfg->enable_length_byte == optionOn)
+	{
+		SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff));
+	}
+	else if (rx_cfg->fixed_message_length != 0)
+	{
+		payload_length = rx_cfg->fixed_message_length;
+		if (rx_cfg->enable_length_byte  == optionOn) payload_length++;
+		if (rx_cfg->enable_address_filtering != filteringOff) payload_length++;
+		SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
+	}
+
+	/* values */
+	if (rx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern));
+	}
+	if (rx_cfg->enable_address_filtering != filteringOff)
+	{
+		SET_CHECKED(rf69_set_node_address     (dev->spi, rx_cfg->node_address));
+		SET_CHECKED(rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address));
+	}
+
+	return 0;
+}
+
+static int
+rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
+{
+	SET_CHECKED(rf69_set_frequency	(dev->spi, tx_cfg->frequency));
+	SET_CHECKED(rf69_set_bit_rate	(dev->spi, tx_cfg->bit_rate));
+	SET_CHECKED(rf69_set_modulation	(dev->spi, tx_cfg->modulation));
+	SET_CHECKED(rf69_set_deviation	(dev->spi, tx_cfg->dev_frequency));
+	SET_CHECKED(rf69_set_pa_ramp	(dev->spi, tx_cfg->pa_ramp));
+	SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping));
+	SET_CHECKED(rf69_set_tx_start_condition(dev->spi, tx_cfg->tx_start_condition));
+
+	/* packet format enable */
+	if (tx_cfg->enable_preamble == optionOn)
+	{
+		SET_CHECKED(rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
+	}
+	SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
+	SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
+	SET_CHECKED(rf69_set_crc_enable	  (dev->spi, tx_cfg->enable_crc));
+
+	/* configure sync, if enabled */
+	if (tx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length));
+		SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern));
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pi433_start_rx(struct pi433_device *dev)
+{
+	int retval;
+
+	/* return without action, if no pending read request */
+	if (!dev->rx_active)
+		return 0;
+
+	/* setup for receiving */
+	retval = rf69_set_rx_cfg(dev, &dev->rx_cfg);
+	if (retval) return retval;
+
+	/* setup rssi irq */
+	SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0));
+	dev->irq_state[DIO0] = DIO_Rssi_DIO0;
+	irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+	/* setup fifo level interrupt */
+	SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD));
+	SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel));
+	dev->irq_state[DIO1] = DIO_FifoLevel;
+	irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING);
+
+	/* set module to receiving mode */
+	SET_CHECKED(rf69_set_mode(dev->spi, receive));
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int
+pi433_receive(void *data)
+{
+	struct pi433_device *dev = data;
+	struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */
+	int bytes_to_read, bytes_total;
+	int retval;
+
+	dev->interrupt_rx_allowed = false;
+
+	/* wait for any tx to finish */
+	dev_dbg(dev->dev,"rx: going to wait for any tx to finish");
+	retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
+	if(retval) /* wait was interrupted */
+	{
+		dev->interrupt_rx_allowed = true;
+		wake_up_interruptible(&dev->tx_wait_queue);
+		return retval;
+	}
+
+	/* prepare status vars */
+	dev->free_in_fifo = FIFO_SIZE;
+	dev->rx_position = 0;
+	dev->rx_bytes_dropped = 0;
+
+	/* setup radio module to listen for something "in the air" */
+	retval = pi433_start_rx(dev);
+	if (retval)
+		return retval;
+
+	/* now check RSSI, if low wait for getting high (RSSI interrupt) */
+	while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) )
+	{
+		/* allow tx to interrupt us while waiting for high RSSI */
+		dev->interrupt_rx_allowed = true;
+		wake_up_interruptible(&dev->tx_wait_queue);
+
+		/* wait for RSSI level to become high */
+		dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
+		retval = wait_event_interruptible(dev->rx_wait_queue,
+			                          rf69_get_flag(dev->spi,
+		                                                rssiExceededThreshold));
+		if (retval) goto abort; /* wait was interrupted */
+		dev->interrupt_rx_allowed = false;
+
+		/* cross check for ongoing tx */
+		if (!dev->tx_active) break;
+	}
+
+	/* configure payload ready irq */
+	SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady));
+	dev->irq_state[DIO0] = DIO_PayloadReady;
+	irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+	/* fixed or unlimited length? */
+	if (dev->rx_cfg.fixed_message_length != 0)
+	{
+		if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size)
+		{
+			retval = -1;
+			goto abort;
+		}
+		bytes_total = dev->rx_cfg.fixed_message_length;
+		dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total);
+	}
+	else
+	{
+		bytes_total = dev->rx_buffer_size;
+		dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total);
+	}
+
+	/* length byte enabled? */
+	if (dev->rx_cfg.enable_length_byte == optionOn)
+	{
+		retval = wait_event_interruptible(dev->fifo_wait_queue,
+						  dev->free_in_fifo < FIFO_SIZE);
+		if (retval) goto abort; /* wait was interrupted */
+
+		rf69_read_fifo(spi, (u8 *)&bytes_total, 1);
+		if (bytes_total > dev->rx_buffer_size)
+		{
+			retval = -1;
+			goto abort;
+		}
+		dev->free_in_fifo++;
+		dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total);
+	}
+
+	/* address byte enabled? */
+	if (dev->rx_cfg.enable_address_filtering != filteringOff)
+	{
+		u8 dummy;
+
+		bytes_total--;
+
+		retval = wait_event_interruptible(dev->fifo_wait_queue,
+						  dev->free_in_fifo < FIFO_SIZE);
+		if (retval) goto abort; /* wait was interrupted */
+
+		rf69_read_fifo(spi, &dummy, 1);
+		dev->free_in_fifo++;
+		dev_dbg(dev->dev, "rx: address byte stripped off");
+	}
+
+	/* get payload */
+	while (dev->rx_position < bytes_total)
+	{
+		if ( !rf69_get_flag(dev->spi, payloadReady) )
+		{
+			retval = wait_event_interruptible(dev->fifo_wait_queue,
+							  dev->free_in_fifo < FIFO_SIZE);
+			if (retval) goto abort; /* wait was interrupted */
+		}
+
+		/* need to drop bytes or acquire? */
+		if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+			bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+		else
+			bytes_to_read = bytes_total - dev->rx_position;
+
+
+		/* access the fifo */
+		if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo)
+			bytes_to_read = FIFO_SIZE - dev->free_in_fifo;
+		retval = rf69_read_fifo(spi,
+					&dev->rx_buffer[dev->rx_position],
+					bytes_to_read);
+		if (retval) goto abort; /* read failed */
+		dev->free_in_fifo += bytes_to_read;
+
+		/* adjust status vars */
+		if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+			dev->rx_bytes_dropped += bytes_to_read;
+		else
+			dev->rx_position += bytes_to_read;
+	}
+
+
+	/* rx done, wait was interrupted or error occured */
+abort:
+	dev->interrupt_rx_allowed = true;
+	SET_CHECKED(rf69_set_mode(dev->spi, standby));
+	wake_up_interruptible(&dev->tx_wait_queue);
+
+	if (retval)
+		return retval;
+	else
+		return bytes_total;
+}
+
+int
+pi433_tx_thread(void *data)
+{
+	struct pi433_device *device = data;
+	struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
+	struct pi433_tx_cfg tx_cfg;
+	u8     buffer[MAX_MSG_SIZE];
+	size_t size;
+	bool   rx_interrupted = false;
+	int    position, repetitions;
+	int    retval;
+
+	while (1)
+	{
+		/* wait for fifo to be populated or for request to terminate*/
+		dev_dbg(device->dev, "thread: going to wait for new messages");
+		wait_event_interruptible(device->tx_wait_queue,
+					 ( !kfifo_is_empty(&device->tx_fifo) ||
+					    kthread_should_stop() ));
+		if ( kthread_should_stop() )
+			return 0;
+
+		/* get data from fifo in the following order:
+		   - tx_cfg
+		   - size of message
+		   - message */
+		mutex_lock(&device->tx_fifo_lock);
+
+		retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
+		if (retval != sizeof(tx_cfg))
+		{
+			dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) );
+			mutex_unlock(&device->tx_fifo_lock);
+			continue;
+		}
+
+		retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
+		if (retval != sizeof(size_t))
+		{
+			dev_dbg(device->dev, "reading msg size from fifo failed: got %d, expected %d", retval, (unsigned int)sizeof(size_t) );
+			mutex_unlock(&device->tx_fifo_lock);
+			continue;
+		}
+
+		/* use fixed message length, if requested */
+		if (tx_cfg.fixed_message_length != 0)
+			size = tx_cfg.fixed_message_length;
+
+		/* increase size, if len byte is requested */
+		if (tx_cfg.enable_length_byte == optionOn)
+			size++;
+
+		/* increase size, if adr byte is requested */
+		if (tx_cfg.enable_address_byte == optionOn)
+			size++;
+
+		/* prime buffer */
+		memset(buffer, 0, size);
+		position = 0;
+
+		/* add length byte, if requested */
+		if (tx_cfg.enable_length_byte  == optionOn)
+			buffer[position++] = size-1; /* according to spec length byte itself must be excluded from the length calculation */
+
+		/* add adr byte, if requested */
+		if (tx_cfg.enable_address_byte == optionOn)
+			buffer[position++] = tx_cfg.address_byte;
+
+		/* finally get message data from fifo */
+		retval = kfifo_out(&device->tx_fifo, &buffer[position], sizeof(buffer)-position );
+		dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval);
+		mutex_unlock(&device->tx_fifo_lock);
+
+		/* if rx is active, we need to interrupt the waiting for
+		   incoming telegrams, to be able to send something.
+		   We are only allowed, if currently no reception takes
+		   place otherwise we need to  wait for the incoming telegram
+		   to finish */
+		wait_event_interruptible(device->tx_wait_queue,
+					 !device->rx_active ||
+					  device->interrupt_rx_allowed == true);
+
+		/* prevent race conditions
+		   irq will be reenabled after tx config is set */
+		disable_irq(device->irq_num[DIO0]);
+		device->tx_active = true;
+
+		if (device->rx_active && rx_interrupted == false)
+		{
+			/* rx is currently waiting for a telegram;
+			   we need to set the radio module to standby */
+			SET_CHECKED(rf69_set_mode(device->spi, standby));
+			rx_interrupted = true;
+		}
+
+		/* clear fifo, set fifo threshold, set payload length */
+		SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */
+		SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD));
+		if (tx_cfg.enable_length_byte == optionOn)
+		{
+			SET_CHECKED(rf69_set_payload_length(spi, size * tx_cfg.repetitions));
+		}
+		else
+		{
+			SET_CHECKED(rf69_set_payload_length(spi, 0));
+		}
+
+		/* configure the rf chip */
+		rf69_set_tx_cfg(device, &tx_cfg);
+
+		/* enable fifo level interrupt */
+		SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel));
+		device->irq_state[DIO1] = DIO_FifoLevel;
+		irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING);
+
+		/* enable packet sent interrupt */
+		SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent));
+		device->irq_state[DIO0] = DIO_PacketSent;
+		irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+		enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check */
+
+		/* enable transmission */
+		SET_CHECKED(rf69_set_mode(spi, transmit));
+
+		/* transfer this msg (and repetitions) to chip fifo */
+		device->free_in_fifo = FIFO_SIZE;
+		position = 0;
+		repetitions = tx_cfg.repetitions;
+		while( (repetitions > 0) && (size > position) )
+		{
+			if ( (size - position) > device->free_in_fifo)
+			{	/* msg to big for fifo - take a part */
+				int temp = device->free_in_fifo;
+				device->free_in_fifo = 0;
+				rf69_write_fifo(spi,
+				                &buffer[position],
+				                temp);
+				position +=temp;
+			}
+			else
+			{	/* msg fits into fifo - take all */
+				device->free_in_fifo -= size;
+				repetitions--;
+				rf69_write_fifo(spi,
+						&buffer[position],
+						(size - position) );
+				position = 0; /* reset for next repetition */
+			}
+
+			retval = wait_event_interruptible(device->fifo_wait_queue,
+							  device->free_in_fifo > 0);
+			if (retval) { printk("ABORT\n"); goto abort; }
+		}
+
+		/* we are done. Wait for packet to get sent */
+		dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be empty");
+		wait_event_interruptible(device->fifo_wait_queue,
+					 device->free_in_fifo == FIFO_SIZE ||
+					 kthread_should_stop() );
+		if ( kthread_should_stop() )	printk("ABORT\n");
+
+
+		/* STOP_TRANSMISSION */
+		dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.");
+		SET_CHECKED(rf69_set_mode(spi, standby));
+
+		/* everything sent? */
+		if ( kfifo_is_empty(&device->tx_fifo) )
+		{
+abort:
+			if (rx_interrupted)
+			{
+				rx_interrupted = false;
+				pi433_start_rx(device);
+			}
+			device->tx_active = false;
+			wake_up_interruptible(&device->rx_wait_queue);
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t
+pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	int			bytes_received;
+	ssize_t			retval;
+
+	/* check, whether internal buffer is big enough for requested size */
+	if (size > MAX_MSG_SIZE)
+		return -EMSGSIZE;
+
+	instance = filp->private_data;
+	device = instance->device;
+
+	/* just one read request at a time */
+	mutex_lock(&device->rx_lock);
+	if (device->rx_active)
+	{
+		mutex_unlock(&device->rx_lock);
+		return -EAGAIN;
+	}
+	else
+	{
+		device->rx_active = true;
+		mutex_unlock(&device->rx_lock);
+	}
+
+	/* start receiving */
+	/* will block until something was received*/
+	device->rx_buffer_size = size;
+	bytes_received = pi433_receive(device);
+
+	/* release rx */
+	mutex_lock(&device->rx_lock);
+	device->rx_active = false;
+	mutex_unlock(&device->rx_lock);
+
+	/* if read was successful copy to user space*/
+	if (bytes_received > 0)
+	{
+		retval = copy_to_user(buf, device->rx_buffer, bytes_received);
+		if (retval)
+			return retval;
+	}
+
+	return bytes_received;
+}
+
+
+static ssize_t
+pi433_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	int                     copied, retval;
+
+	instance = filp->private_data;
+	device = instance->device;
+
+	/* check, whether internal buffer (tx thread) is big enough for requested size */
+	if (count > MAX_MSG_SIZE)
+		return -EMSGSIZE;
+
+	/* write the following sequence into fifo:
+	   - tx_cfg
+	   - size of message
+	   - message */
+	mutex_lock(&device->tx_fifo_lock);
+	retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg));
+	if ( retval != sizeof(instance->tx_cfg) )
+		goto abort;
+
+	retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t));
+	if ( retval != sizeof(size_t) )
+		goto abort;
+
+	retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied);
+	if (retval || copied != count)
+		goto abort;
+
+	mutex_unlock(&device->tx_fifo_lock);
+
+	/* start transfer */
+	wake_up_interruptible(&device->tx_wait_queue);
+	dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied);
+
+	return 0;
+
+abort:
+	dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
+	kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to discard already stored, valid entries
+	mutex_unlock(&device->tx_fifo_lock);
+	return -EAGAIN;
+}
+
+
+static long
+pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int			err = 0;
+	int			retval = 0;
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	u32			tmp;
+
+	/* Check type and command number */
+	if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
+		return -ENOTTY;
+
+	/* Check access direction once here; don't repeat below.
+	 * IOC_DIR is from the user perspective, while access_ok is
+	 * from the kernel perspective; so they look reversed.
+	 */
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok(VERIFY_WRITE,
+				 (void __user *)arg,
+				 _IOC_SIZE(cmd));
+
+	if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok(VERIFY_READ,
+				 (void __user *)arg,
+				 _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	/* TODO? guard against device removal before, or while,
+	 * we issue this ioctl. --> device_get()
+	 */
+	instance = filp->private_data;
+	device = instance->device;
+
+	if (device == NULL)
+		return -ESHUTDOWN;
+
+	switch (cmd) {
+	case PI433_IOC_RD_TX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+		{
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_to_user((void __user *)arg,
+				    &instance->tx_cfg,
+				    tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+	case PI433_IOC_WR_TX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+		{
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_from_user(&instance->tx_cfg,
+				     (void __user *)arg,
+				     tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+
+	case PI433_IOC_RD_RX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_to_user((void __user *)arg,
+				   &device->rx_cfg,
+				   tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+	case PI433_IOC_WR_RX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		mutex_lock(&device->rx_lock);
+
+		/* during pendig read request, change of config not allowed */
+		if (device->rx_active) {
+			retval = -EAGAIN;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+			retval = -EINVAL;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		if (__copy_from_user(&device->rx_cfg,
+				     (void __user *)arg,
+				     tmp))
+		{
+			retval = -EFAULT;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		mutex_unlock(&device->rx_lock);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define pi433_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_open(struct inode *inode, struct file *filp)
+{
+	struct pi433_device	*device;
+	struct pi433_instance	*instance;
+
+	mutex_lock(&minor_lock);
+	device = idr_find(&pi433_idr, iminor(inode));
+	mutex_unlock(&minor_lock);
+	if (!device) {
+		pr_debug("device: minor %d unknown.\n", iminor(inode));
+		return -ENODEV;
+	}
+
+	if (!device->rx_buffer) {
+		device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL);
+		if (!device->rx_buffer)
+		{
+			dev_dbg(device->dev, "open/ENOMEM\n");
+			return -ENOMEM;
+		}
+	}
+
+	device->users++;
+	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+	if (!instance)
+	{
+		kfree(device->rx_buffer);
+		device->rx_buffer = NULL;
+		return -ENOMEM;
+	}
+
+	/* setup instance data*/
+	instance->device = device;
+	instance->tx_cfg.bit_rate = 4711;
+	// TODO: fill instance->tx_cfg;
+
+	/* instance data as context */
+	filp->private_data = instance;
+	nonseekable_open(inode, filp);
+
+	return 0;
+}
+
+static int pi433_release(struct inode *inode, struct file *filp)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+
+	instance = filp->private_data;
+	device = instance->device;
+	kfree(instance);
+	filp->private_data = NULL;
+
+	/* last close? */
+	device->users--;
+
+	if (!device->users) {
+		kfree(device->rx_buffer);
+		device->rx_buffer = NULL;
+		if (device->spi == NULL)
+			kfree(device);
+	}
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int setup_GPIOs(struct pi433_device *device)
+{
+	char 	name[5];
+	int	retval;
+	int	i;
+
+	for (i=0; i<NUM_DIO; i++)
+	{
+		/* "construct" name and get the gpio descriptor */
+		snprintf(name, sizeof(name), "DIO%d", i);
+		device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+
+		if (device->gpiod[i] == ERR_PTR(-ENOENT))
+		{
+			dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name);
+			continue;
+		}
+
+		if (device->gpiod[i] == ERR_PTR(-EBUSY))
+			dev_dbg(&device->spi->dev, "%s is busy.", name);
+
+		if ( IS_ERR(device->gpiod[i]) )
+		{
+			retval = PTR_ERR(device->gpiod[i]);
+			/* release already allocated gpios */
+			for (i--; i>=0; i--)
+			{
+				free_irq(device->irq_num[i], device);
+				gpiod_put(device->gpiod[i]);
+			}
+			return retval;
+		}
+
+
+		/* configure the pin */
+		gpiod_unexport(device->gpiod[i]);
+		retval = gpiod_direction_input(device->gpiod[i]);
+		if (retval) return retval;
+
+
+		/* configure irq */
+		device->irq_num[i] = gpiod_to_irq(device->gpiod[i]);
+		if (device->irq_num[i] < 0)
+		{
+			device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc *)device->irq_num[i];
+			return device->irq_num[i];
+		}
+		retval = request_irq(device->irq_num[i],
+				     DIO_irq_handler[i],
+				     0, /* flags */
+				     name,
+				     device);
+
+		if (retval)
+			return retval;
+
+		dev_dbg(&device->spi->dev, "%s succesfully configured", name);
+	}
+
+	return 0;
+}
+
+static void free_GPIOs(struct pi433_device *device)
+{
+	int i;
+
+	for (i=0; i<NUM_DIO; i++)
+	{
+		/* check if gpiod is valid */
+		if ( IS_ERR(device->gpiod[i]) )
+			continue;
+
+		free_irq(device->irq_num[i], device);
+		gpiod_put(device->gpiod[i]);
+	}
+	return;
+}
+
+static int pi433_get_minor(struct pi433_device *device)
+{
+	int retval = -ENOMEM;
+
+	mutex_lock(&minor_lock);
+	retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL);
+	if (retval >= 0) {
+		device->minor = retval;
+		retval = 0;
+	} else if (retval == -ENOSPC) {
+		dev_err(device->dev, "too many pi433 devices\n");
+		retval = -EINVAL;
+	}
+	mutex_unlock(&minor_lock);
+	return retval;
+}
+
+static void pi433_free_minor(struct pi433_device *dev)
+{
+	mutex_lock(&minor_lock);
+	idr_remove(&pi433_idr, dev->minor);
+	mutex_unlock(&minor_lock);
+}
+/*-------------------------------------------------------------------------*/
+
+static const struct file_operations pi433_fops = {
+	.owner =	THIS_MODULE,
+	/* REVISIT switch to aio primitives, so that userspace
+	 * gets more complete API coverage.  It'll simplify things
+	 * too, except for the locking.
+	 */
+	.write =	pi433_write,
+	.read =		pi433_read,
+	.unlocked_ioctl = pi433_ioctl,
+	.compat_ioctl = pi433_compat_ioctl,
+	.open =		pi433_open,
+	.release =	pi433_release,
+	.llseek =	no_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_probe(struct spi_device *spi)
+{
+	struct pi433_device	*device;
+	int			retval;
+
+	/* setup spi parameters */
+	spi->mode = 0x00;
+	spi->bits_per_word = 8;
+	/* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay */
+
+	retval = spi_setup(spi);
+	if (retval)
+	{
+		dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
+		return retval;
+	}
+	else
+	{
+		dev_dbg(&spi->dev,
+			"spi interface setup: mode 0x%2x, %d bits per word, %dhz max speed",
+			spi->mode, spi->bits_per_word, spi->max_speed_hz);
+	}
+
+	/* Ping the chip by reading the version register */
+	retval = spi_w8r8(spi, 0x10);
+	if (retval < 0)
+		return retval;
+
+	switch(retval)
+	{
+		case 0x24:
+			dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
+			break;
+		default:
+			dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
+			return -ENODEV;
+	}
+
+	/* Allocate driver data */
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	/* Initialize the driver data */
+	device->spi = spi;
+	device->rx_active = false;
+	device->tx_active = false;
+	device->interrupt_rx_allowed = false;
+
+	/* init wait queues */
+	init_waitqueue_head(&device->tx_wait_queue);
+	init_waitqueue_head(&device->rx_wait_queue);
+	init_waitqueue_head(&device->fifo_wait_queue);
+
+	/* init fifo */
+	INIT_KFIFO(device->tx_fifo);
+
+	/* init mutexes and locks */
+	mutex_init(&device->tx_fifo_lock);
+	mutex_init(&device->rx_lock);
+
+	/* setup GPIO (including irq_handler) for the different DIOs */
+	retval = setup_GPIOs(device);
+	if (retval)
+	{
+		dev_dbg(&spi->dev, "setup of GPIOs failed");
+		goto GPIO_failed;
+	}
+
+	/* setup the radio module */
+	SET_CHECKED(rf69_set_mode		(spi, standby));
+	SET_CHECKED(rf69_set_data_mode		(spi, packet));
+	SET_CHECKED(rf69_set_amplifier_0	(spi, optionOn));
+	SET_CHECKED(rf69_set_amplifier_1	(spi, optionOff));
+	SET_CHECKED(rf69_set_amplifier_2	(spi, optionOff));
+	SET_CHECKED(rf69_set_output_power_level	(spi, 13));
+	SET_CHECKED(rf69_set_antenna_impedance	(spi, fiftyOhm));
+
+	/* start tx thread */
+	device->tx_task_struct = kthread_run(pi433_tx_thread,
+					     device,
+					     "pi433_tx_task");
+	if (device->tx_task_struct < 0)
+	{
+		dev_dbg(device->dev, "start of send thread failed");
+		goto send_thread_failed;
+	}
+
+	/* determ minor number */
+	retval = pi433_get_minor(device);
+	if (retval)
+	{
+		dev_dbg(device->dev, "get of minor number failed");
+		goto minor_failed;
+	}
+
+	/* create device */
+	device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
+	device->dev = device_create(pi433_class,
+				    &spi->dev,
+				    device->devt,
+				    device,
+				    "pi433");
+	if (IS_ERR(device->dev)) {
+		pr_err("pi433: device register failed\n");
+		retval = PTR_ERR(device->dev);
+		goto device_create_failed;
+	}
+	else {
+		dev_dbg(device->dev,
+			"created device for major %d, minor %d\n",
+			MAJOR(pi433_dev),
+			device->minor);
+	}
+
+	/* create cdev */
+	device->cdev = cdev_alloc();
+	device->cdev->owner = THIS_MODULE;
+	cdev_init(device->cdev, &pi433_fops);
+	retval = cdev_add(device->cdev, device->devt, 1);
+	if (retval)
+	{
+		dev_dbg(device->dev, "register of cdev failed");
+		goto cdev_failed;
+	}
+
+	/* spi setup */
+	spi_set_drvdata(spi, device);
+
+	return 0;
+
+cdev_failed:
+	device_destroy(pi433_class, device->devt);
+device_create_failed:
+	pi433_free_minor(device);
+minor_failed:
+	kthread_stop(device->tx_task_struct);
+send_thread_failed:
+	free_GPIOs(device);
+GPIO_failed:
+	kfree(device);
+
+	return retval;
+}
+
+static int pi433_remove(struct spi_device *spi)
+{
+	struct pi433_device	*device = spi_get_drvdata(spi);
+
+	/* free GPIOs */
+	free_GPIOs(device);
+
+	/* make sure ops on existing fds can abort cleanly */
+	device->spi = NULL;
+
+	kthread_stop(device->tx_task_struct);
+
+	device_destroy(pi433_class, device->devt);
+
+	cdev_del(device->cdev);
+
+	pi433_free_minor(device);
+
+	if (device->users == 0)
+		kfree(device);
+
+	return 0;
+}
+
+static const struct of_device_id pi433_dt_ids[] = {
+	{ .compatible = "Smarthome-Wolf,pi433" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, pi433_dt_ids);
+
+static struct spi_driver pi433_spi_driver = {
+	.driver = {
+		.name =		"pi433",
+		.owner =	THIS_MODULE,
+		.of_match_table = of_match_ptr(pi433_dt_ids),
+	},
+	.probe =	pi433_probe,
+	.remove =	pi433_remove,
+
+	/* NOTE:  suspend/resume methods are not necessary here.
+	 * We don't do anything except pass the requests to/from
+	 * the underlying controller.  The refrigerator handles
+	 * most issues; the controller driver handles the rest.
+	 */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init pi433_init(void)
+{
+	int status;
+
+	/* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't
+           work stable - risk of buffer overflow */
+	if (MAX_MSG_SIZE < FIFO_SIZE)
+		return -EINVAL;
+
+	/* Claim device numbers.  Then register a class
+	 * that will key udev/mdev to add/remove /dev nodes.  Last, register
+	 * Last, register the driver which manages those device numbers.
+	 */
+	status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/);
+	if (status < 0)
+		return status;
+
+	pi433_class = class_create(THIS_MODULE, "pi433");
+	if (IS_ERR(pi433_class))
+	{
+		unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+		return PTR_ERR(pi433_class);
+	}
+
+	status = spi_register_driver(&pi433_spi_driver);
+	if (status < 0)
+	{
+		class_destroy(pi433_class);
+		unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+	}
+
+	return status;
+}
+
+module_init(pi433_init);
+
+static void __exit pi433_exit(void)
+{
+	spi_unregister_driver(&pi433_spi_driver);
+	class_destroy(pi433_class);
+	unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+}
+module_exit(pi433_exit);
+
+MODULE_AUTHOR("Marcus Wolf, <linux@wolf-entwicklungen.de>");
+MODULE_DESCRIPTION("Driver for Pi433");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:pi433");
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
new file mode 100644
index 0000000..e6ed3cd
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.h
@@ -0,0 +1,152 @@
+/*
+ * include/linux/TODO
+ *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR 	0
+struct pi433_tx_cfg
+{
+	__u32			frequency;
+	__u16			bit_rate;
+	__u32			dev_frequency;
+	enum modulation		modulation;
+	enum modShaping		modShaping;
+
+	enum paRamp		pa_ramp;
+
+	enum txStartCondition	tx_start_condition;
+
+	__u16			repetitions;
+
+
+	/* packet format */
+	enum optionOnOff	enable_preamble;
+	enum optionOnOff	enable_sync;
+	enum optionOnOff	enable_length_byte;
+	enum optionOnOff	enable_address_byte;
+	enum optionOnOff	enable_crc;
+
+	__u16			preamble_length;
+	__u8			sync_length;
+	__u8			fixed_message_length;
+
+	__u8			sync_pattern[8];
+	__u8			address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR 	1
+struct pi433_rx_cfg {
+	__u32			frequency;
+	__u16			bit_rate;
+	__u32			dev_frequency;
+
+	enum modulation		modulation;
+
+	__u8			rssi_threshold;
+	enum thresholdDecrement	thresholdDecrement;
+	enum antennaImpedance	antenna_impedance;
+	enum lnaGain		lna_gain;
+	enum mantisse		bw_mantisse;	/* normal: 0x50 */
+	__u8			bw_exponent;	/* during AFC: 0x8b */
+	enum dagc		dagc;
+
+
+
+	/* packet format */
+	enum optionOnOff	enable_sync;
+	enum optionOnOff	enable_length_byte;	  /* should be used in combination with sync, only */
+	enum addressFiltering	enable_address_filtering; /* operational with sync, only */
+	enum optionOnOff	enable_crc;		  /* only operational, if sync on and fixed length or length byte is used */
+
+	__u8			sync_length;
+	__u8			fixed_message_length;
+	__u32			bytes_to_drop;
+
+	__u8			sync_pattern[8];
+	__u8			node_address;
+	__u8			broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC			'r'
+
+#define PI433_IOC_RD_TX_CFG	_IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG	_IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG	_IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG	_IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
new file mode 100644
index 0000000..b6bc45b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.c
@@ -0,0 +1,982 @@
+/*
+ * abstraction of the spi interface of HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* enable prosa debug info */
+#undef DEBUG
+/* enable print of values on reg access */
+#undef DEBUG_VALUES
+/* enable print of values on fifo access */
+#undef DEBUG_FIFO_ACCESS
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include "rf69.h"
+#include "rf69_registers.h"
+
+#define F_OSC	  32000000 /* in Hz */
+#define FIFO_SIZE 66 	   /* in byte */
+
+/*-------------------------------------------------------------------------*/
+
+#define READ_REG(x)	rf69_read_reg (spi, x)
+#define WRITE_REG(x,y)	rf69_write_reg(spi, x, y)
+#define INVALID_PARAM \
+	{ \
+		dev_dbg(&spi->dev, "set: illegal input param"); \
+		return -EINVAL; \
+	}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: mode");
+	#endif
+
+	switch (mode){
+	case transmit:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT);
+	case receive:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE);
+	case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER);
+	case standby:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY);
+	case mode_sleep:  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP);
+	default:	  INVALID_PARAM;
+	}
+
+	// we are using packet mode, so this check is not really needed
+	// but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode
+	//while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
+
+}
+
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: data mode");
+	#endif
+
+	switch (dataMode) {
+	case packet:		return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET);
+	case continuous:	return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS);
+	case continuousNoSync:  return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS_NOSYNC);
+	default:		INVALID_PARAM;
+	}
+}
+
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: modulation");
+	#endif
+
+	switch (modulation) {
+	case OOK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK);
+	case FSK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK);
+	default:    INVALID_PARAM;
+	}
+}
+
+enum modulation rf69_get_modulation(struct spi_device *spi)
+{
+	u8 currentValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: mode");
+	#endif
+
+	currentValue = READ_REG(REG_DATAMODUL);
+
+	switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3)  // TODO improvement: change 3 to define
+	{
+	case DATAMODUL_MODULATION_TYPE_OOK: return OOK;
+	case DATAMODUL_MODULATION_TYPE_FSK: return FSK;
+	default:			    return undefined;
+	}
+}
+
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: mod shaping");
+	#endif
+
+	if (rf69_get_modulation(spi) == FSK)
+	{
+		switch (modShaping) {
+		case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE);
+		case shaping1_0: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_1_0);
+		case shaping0_5: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_3);
+		case shaping0_3: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_5);
+		default:	 INVALID_PARAM;
+		}
+	}
+	else
+	{
+		switch (modShaping) {
+		case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE);
+		case shapingBR:	 return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_BR);
+		case shaping2BR: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_2BR);
+		default:	 INVALID_PARAM;
+		}
+	}
+}
+
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+{
+	int retval;
+	u32 bitRate_min;
+	u32 bitRate_reg;
+	u8 msb;
+	u8 lsb;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: bit rate");
+	#endif
+
+	// check input value
+	bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
+	if (bitRate < bitRate_min)
+	{
+		dev_dbg(&spi->dev, "setBitRate: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculate reg settings
+	bitRate_reg = (F_OSC / bitRate);
+
+	msb = (bitRate_reg&0xff00)   >>  8;
+	lsb = (bitRate_reg&0xff);
+
+	// transmit to RF 69
+	retval = WRITE_REG(REG_BITRATE_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_BITRATE_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_deviation(struct spi_device *spi, u32 deviation)
+{
+	int retval;
+//	u32 f_max; TODO: Abhängigkeit von Bitrate beachten!!
+	u64 f_reg;
+	u64 f_step;
+	u8 msb;
+	u8 lsb;
+	u64 factor = 1000000; // to improve precision of calculation
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: deviation");
+	#endif
+
+	if (deviation < 600 || deviation > 500000) //TODO: Abhängigkeit von Bitrate beachten!!
+	{
+		dev_dbg(&spi->dev, "set_deviation: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculat f step
+	f_step = F_OSC * factor;
+	do_div(f_step, 524288); //  524288 = 2^19
+
+	// calculate register settings
+	f_reg = deviation * factor;
+	do_div(f_reg  , f_step);
+
+	msb = (f_reg&0xff00)   >>  8;
+	lsb = (f_reg&0xff);
+
+	// check msb
+	if (msb & !FDEVMASB_MASK)
+	{
+		dev_dbg(&spi->dev, "set_deviation: err in calc of msb");
+		INVALID_PARAM;
+	}
+
+	// write to chip
+	retval = WRITE_REG(REG_FDEV_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FDEV_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_frequency(struct spi_device *spi, u32 frequency)
+{
+	int retval;
+	u32 f_max;
+	u64 f_reg;
+	u64 f_step;
+	u8 msb;
+	u8 mid;
+	u8 lsb;
+	u64 factor = 1000000; // to improve precision of calculation
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: frequency");
+	#endif
+
+	// calculat f step
+	f_step = F_OSC * factor;
+	do_div(f_step, 524288); //  524288 = 2^19
+
+	// check input value
+	f_max = f_step * 8388608 / factor;
+	if (frequency > f_max)
+	{
+		dev_dbg(&spi->dev, "setFrequency: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculate reg settings
+	f_reg = frequency * factor;
+	do_div(f_reg  , f_step);
+
+	msb = (f_reg&0xff0000) >> 16;
+	mid = (f_reg&0xff00)   >>  8;
+	lsb = (f_reg&0xff);
+
+	// write to chip
+	retval = WRITE_REG(REG_FRF_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FRF_MID, mid);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FRF_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #0");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA0) );
+	case optionOff:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA0) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #1");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA1) );
+	case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA1) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #2");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA2) );
+	case optionOff:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA2) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: power level");
+	#endif
+
+	powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting
+
+	// check input value
+	if (powerLevel > 0x1f)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_OUTPUT_POWER) | powerLevel);
+}
+
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: pa ramp");
+	#endif
+
+	switch(paRamp) {
+	case ramp3400:	return WRITE_REG(REG_PARAMP, PARAMP_3400);
+	case ramp2000:	return WRITE_REG(REG_PARAMP, PARAMP_2000);
+	case ramp1000:	return WRITE_REG(REG_PARAMP, PARAMP_1000);
+	case ramp500:	return WRITE_REG(REG_PARAMP, PARAMP_500);
+	case ramp250:	return WRITE_REG(REG_PARAMP, PARAMP_250);
+	case ramp125:	return WRITE_REG(REG_PARAMP, PARAMP_125);
+	case ramp100:	return WRITE_REG(REG_PARAMP, PARAMP_100);
+	case ramp62:	return WRITE_REG(REG_PARAMP, PARAMP_62);
+	case ramp50:	return WRITE_REG(REG_PARAMP, PARAMP_50);
+	case ramp40:	return WRITE_REG(REG_PARAMP, PARAMP_40);
+	case ramp31:	return WRITE_REG(REG_PARAMP, PARAMP_31);
+	case ramp25:	return WRITE_REG(REG_PARAMP, PARAMP_25);
+	case ramp20:	return WRITE_REG(REG_PARAMP, PARAMP_20);
+	case ramp15:	return WRITE_REG(REG_PARAMP, PARAMP_15);
+	case ramp12:	return WRITE_REG(REG_PARAMP, PARAMP_12);
+	case ramp10:	return WRITE_REG(REG_PARAMP, PARAMP_10);
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: antenna impedance");
+	#endif
+
+	switch(antennaImpedance) {
+	case fiftyOhm:	    return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) & ~MASK_LNA_ZIN) );
+	case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) |  MASK_LNA_ZIN) );
+	default:	    INVALID_PARAM;
+	}
+}
+
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: lna gain");
+	#endif
+
+	switch(lnaGain) {
+	case automatic:	 return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_AUTO) );
+	case max:	 return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX) );
+	case maxMinus6:  return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) );
+	case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) );
+	case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) );
+	case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) );
+	case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) );
+	default:	 INVALID_PARAM;
+	}
+}
+
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi)
+{
+	u8 currentValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: lna gain");
+	#endif
+
+	currentValue = READ_REG(REG_LNA);
+
+	switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3)  // improvement: change 3 to define
+	{
+	case LNA_GAIN_AUTO:	    return automatic;
+	case LNA_GAIN_MAX:	    return max;
+	case LNA_GAIN_MAX_MINUS_6:  return maxMinus6;
+	case LNA_GAIN_MAX_MINUS_12: return maxMinus12;
+	case LNA_GAIN_MAX_MINUS_24: return maxMinus24;
+	case LNA_GAIN_MAX_MINUS_36: return maxMinus36;
+	case LNA_GAIN_MAX_MINUS_48: return maxMinus48;
+	default:		    return undefined;
+	}
+}
+
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum dccPercent dccPercent)
+{
+	switch (dccPercent) {
+	case dcc16Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) );
+	case dcc8Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) );
+	case dcc4Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) );
+	case dcc2Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) );
+	case dcc1Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) );
+	case dcc0_5Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) );
+	case dcc0_25Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) );
+	case dcc0_125Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) );
+	default:		INVALID_PARAM;
+	}
+}
+
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: cut off freq");
+	#endif
+
+	return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent);
+}
+
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: cut off freq during afc");
+	#endif
+
+	return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent);
+}
+
+int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse mantisse, u8 exponent)
+{
+	u8 newValue;
+
+	// check value for mantisse and exponent
+	if (exponent > 7)   INVALID_PARAM;
+	if ( (mantisse!=mantisse16) &&
+	     (mantisse!=mantisse20) &&
+             (mantisse!=mantisse24) ) INVALID_PARAM;
+
+	// read old value
+	newValue = READ_REG(reg);
+
+	// "delete" mantisse and exponent = just keep the DCC setting
+	newValue = newValue & MASK_BW_DCC_FREQ;
+
+	// add new mantisse
+	switch(mantisse) {
+	case mantisse16: newValue = newValue | BW_MANT_16;	break;
+	case mantisse20: newValue = newValue | BW_MANT_20;	break;
+	case mantisse24: newValue = newValue | BW_MANT_24;	break;
+	}
+
+	// add new exponent
+	newValue = newValue | exponent;
+
+	// write back
+	return WRITE_REG(reg, newValue);
+}
+
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: band width");
+	#endif
+
+	return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent);
+}
+
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: band width during afc");
+	#endif
+
+	return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
+}
+
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold type");
+	#endif
+
+	switch (thresholdType)
+	{
+	case fixed:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) );
+	case peak:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) );
+	case average:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold step");
+	#endif
+
+	switch (thresholdStep) {
+	case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) );
+	case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) );
+	case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) );
+	case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) );
+	case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) );
+	case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) );
+	case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) );
+	case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) );
+	default:	 INVALID_PARAM;
+	}
+}
+
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold decrement");
+	#endif
+
+	switch (thresholdDecrement) {
+	case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) );
+	case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) );
+	case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) );
+	case dec_once:	   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) );
+	case dec_twice:	   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) );
+	case dec_4times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) );
+	case dec_8times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) );
+	case dec_16times:  return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) );
+	default:	   INVALID_PARAM;
+	}
+}
+
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+{
+	u8 mask;
+	u8 shift;
+	u8 regaddr;
+	u8 regValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: DIO mapping");
+	#endif
+
+	// check DIO number
+	if (DIONumber > 5) INVALID_PARAM;
+
+	switch (DIONumber) {
+	case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break;
+	case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break;
+	case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break;
+	case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break;
+	case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break;
+	case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break;
+	}
+
+	// read reg
+	regValue=READ_REG(regaddr);
+	// delete old value
+	regValue = regValue & ~mask;
+	// add new value
+	regValue = regValue | value << shift;
+	// write back
+	return WRITE_REG(regaddr,regValue);
+}
+
+bool rf69_get_flag(struct spi_device *spi, enum flag flag)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: flag");
+	#endif
+
+	switch(flag) {
+	case modeSwitchCompleted:     return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_MODE_READY);
+	case readyToReceive:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RX_READY);
+	case readyToSend:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TX_READY);
+	case pllLocked:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_PLL_LOCK);
+	case rssiExceededThreshold:   return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI);
+	case timeout:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TIMEOUT);
+	case automode:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_AUTOMODE);
+	case syncAddressMatch:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+	case fifoFull:		      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_FULL);
+/*	case fifoNotEmpty:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */
+	case fifoEmpty:		      return !(READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY);
+	case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_LEVEL);
+	case fifoOverrun:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_OVERRUN);
+	case packetSent:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PACKET_SENT);
+	case payloadReady:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PAYLOAD_READY);
+	case crcOk:		      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_CRC_OK);
+	case batteryLow:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_LOW_BAT);
+	default:		      return false;
+	}
+}
+
+int rf69_reset_flag(struct spi_device *spi, enum flag flag)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "reset: flag");
+	#endif
+
+	switch(flag) {
+	case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_RSSI);
+	case syncAddressMatch:	    return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+	case fifoOverrun:	    return WRITE_REG(REG_IRQFLAGS2, MASK_IRQFLAGS2_FIFO_OVERRUN);
+	default:		    INVALID_PARAM;
+	}
+}
+
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: rssi threshold");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RSSITHRESH, threshold);
+}
+
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: start timeout");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RXTIMEOUT1, timeout);
+}
+
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: rssi timeout");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RXTIMEOUT2, timeout);
+}
+
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+{
+	int retval;
+	u8 msb, lsb;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: preample length");
+	#endif
+
+	/* no value check needed - u16 exactly matches register size */
+
+	/* calculate reg settings */
+	msb = (preambleLength&0xff00)   >>  8;
+	lsb = (preambleLength&0xff);
+
+	/* transmit to chip */
+	retval = WRITE_REG(REG_PREAMBLE_MSB, msb);
+	if (retval) return retval;
+	retval = WRITE_REG(REG_PREAMBLE_LSB, lsb);
+
+	return retval;
+}
+
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync enable");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_SYNC_ON) );
+	case optionOff:	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: fifo fill condition");
+	#endif
+
+	switch(fifoFillCondition) {
+	case always:		 return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+	case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+	default:		 INVALID_PARAM;
+	}
+}
+
+int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync size");
+	#endif
+
+	// check input value
+	if (syncSize > 0x07)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) );
+}
+
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync tolerance");
+	#endif
+
+	// check input value
+	if (syncTolerance > 0x07)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance);
+}
+
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+{
+	int retval = 0;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync values");
+	#endif
+
+	retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]);
+	retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]);
+	retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]);
+	retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]);
+	retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]);
+	retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]);
+	retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]);
+	retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]);
+
+	return retval;
+}
+
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat packetFormat)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: packet format");
+	#endif
+
+	switch(packetFormat) {
+	case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+	case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+	default:	      INVALID_PARAM;
+	}
+}
+
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: crc enable");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_CRC_ON) );
+	case optionOff:	return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: address filtering");
+	#endif
+
+	switch (addressFiltering) {
+	case filteringOff:	     return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_OFF) );
+	case nodeAddress:	     return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODE) );
+	case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) );
+	default:		     INVALID_PARAM;
+	}
+}
+
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: payload length");
+	#endif
+
+	return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength);
+}
+
+u8  rf69_get_payload_length(struct spi_device *spi)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: payload length");
+	#endif
+
+	return (u8) READ_REG(REG_PAYLOAD_LENGTH);
+}
+
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: node address");
+	#endif
+
+	return WRITE_REG(REG_NODEADRS, nodeAddress);
+}
+
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: broadcast address");
+	#endif
+
+	return WRITE_REG(REG_BROADCASTADRS, broadcastAddress);
+}
+
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: start condition");
+	#endif
+
+	switch(txStartCondition) {
+	case fifoLevel:	   return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) );
+	case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) |  MASK_FIFO_THRESH_TXSTART) );
+	default:	   INVALID_PARAM;
+	}
+}
+
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
+{
+	int retval;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: fifo threshold");
+	#endif
+
+	// check input value
+	if (threshold & 0x80)
+		INVALID_PARAM;
+
+	// write value
+	retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_VALUE) | threshold);
+	if (retval)
+		return retval;
+
+	// access the fifo to activate new threshold
+	return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer
+}
+
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: dagc");
+	#endif
+
+	switch(dagc) {
+	case normalMode:		 return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL);
+	case improve:			 return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA0);
+	case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA1);
+	default:			 INVALID_PARAM;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+	#ifdef DEBUG_FIFO_ACCESS
+		int i;
+	#endif
+	struct spi_transfer transfer;
+	u8 local_buffer[FIFO_SIZE + 1];
+	int retval;
+
+	if (size > FIFO_SIZE)
+	{
+		#ifdef DEBUG
+			dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n");
+		#endif
+		return -EMSGSIZE;
+	}
+
+	/* prepare a bidirectional transfer */
+	local_buffer[0] = REG_FIFO;
+	memset(&transfer, 0, sizeof(transfer));
+  	transfer.tx_buf = local_buffer;
+  	transfer.rx_buf = local_buffer;
+	transfer.len	= size+1;
+
+	retval = spi_sync_transfer(spi, &transfer, 1);
+
+	#ifdef DEBUG_FIFO_ACCESS
+		for (i=0; i<size; i++)
+			dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]);
+	#endif
+
+	memcpy(buffer, &local_buffer[1], size);  // TODO: ohne memcopy wäre schöner
+
+	return retval;
+}
+
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+	#ifdef DEBUG_FIFO_ACCESS
+		int i;
+	#endif
+	char spi_address = REG_FIFO | WRITE_BIT;
+	u8 local_buffer[FIFO_SIZE + 1];
+
+	if (size > FIFO_SIZE)
+	{
+		#ifdef DEBUG
+			dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n");
+		#endif
+		return -EMSGSIZE;
+	}
+
+	local_buffer[0] = spi_address;
+	memcpy(&local_buffer[1], buffer, size);  // TODO: ohne memcopy wäre schöner
+
+	#ifdef DEBUG_FIFO_ACCESS
+		for (i=0; i<size; i++)
+			dev_dbg(&spi->dev, "0x%x\n",buffer[i]);
+	#endif
+
+	return spi_write (spi, local_buffer, size + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+u8 rf69_read_reg(struct spi_device *spi, u8 addr)
+{
+	int retval;
+
+	retval = spi_w8r8(spi, addr);
+
+	#ifdef DEBUG_VALUES
+		if (retval < 0)
+			/* should never happen, since we already checked,
+			   that module is connected. Therefore no error
+			   handling, just an optional error message... */
+			dev_dbg(&spi->dev, "read 0x%x FAILED\n",
+				addr);
+		else
+			dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n",
+				retval,
+				addr);
+	#endif
+
+	return retval;
+}
+
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value)
+{
+	int retval;
+	char buffer[2];
+
+	buffer[0] = addr | WRITE_BIT;
+	buffer[1] = value;
+
+	retval = spi_write(spi, &buffer, 2);
+
+	#ifdef DEBUG_VALUES
+		if (retval < 0)
+			/* should never happen, since we already checked,
+			   that module is connected. Therefore no error
+			   handling, just an optional error message... */
+			dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n",
+				value,
+				addr);
+		else
+			dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n",
+				value,
+				addr);
+	#endif
+
+	return retval;
+}
+
+
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
new file mode 100644
index 0000000..6a6841b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.h
@@ -0,0 +1,82 @@
+/*
+ * hardware abstraction/register access for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef RF69_H
+#define RF69_H
+
+#include "rf69_enum.h"
+#include "rf69_registers.h"
+
+#define F_OSC 		32000000  /* in Hz */
+#define FREQUENCY	433920000 /* in Hz, modifying this value impacts CE certification */
+#define FIFO_SIZE 	66        /* in byte */
+#define FIFO_THRESHOLD	15 	  /* in byte */
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode);
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode);
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
+enum modulation rf69_get_modulation(struct spi_device *spi);
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_deviation(struct spi_device *spi, u32 deviation);
+int rf69_set_frequency(struct spi_device *spi, u32 frequency);
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi);
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent);
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType);
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+bool rf69_get_flag(struct spi_device *spi, enum flag flag);
+int rf69_reset_flag(struct spi_device *spi, enum flag flag);
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition);
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance);
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat packetFormat);
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering);
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength);
+u8  rf69_get_payload_length(struct spi_device *spi);
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition);
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size);
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size);
+
+u8  rf69_read_reg (struct spi_device *spi, u8 addr);
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value);
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_enum.h b/drivers/staging/pi433/rf69_enum.h
new file mode 100644
index 0000000..fbfb59b
--- /dev/null
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -0,0 +1,201 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_registers.h b/drivers/staging/pi433/rf69_registers.h
new file mode 100644
index 0000000..d0c4992
--- /dev/null
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -0,0 +1,489 @@
+/*
+ * register description for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux@wolf-entwicklungen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*******************************************/
+/* RF69 register addresses		   */
+/*******************************************/
+#define  REG_FIFO			0x00
+#define  REG_OPMODE			0x01
+#define  REG_DATAMODUL			0x02
+#define  REG_BITRATE_MSB		0x03
+#define  REG_BITRATE_LSB		0x04
+#define  REG_FDEV_MSB			0x05
+#define  REG_FDEV_LSB			0x06
+#define  REG_FRF_MSB			0x07
+#define  REG_FRF_MID			0x08
+#define  REG_FRF_LSB			0x09
+#define  REG_OSC1			0x0A
+#define  REG_AFCCTRL			0x0B
+#define  REG_LOWBAT			0x0C
+#define  REG_LISTEN1			0x0D
+#define  REG_LISTEN2			0x0E
+#define  REG_LISTEN3			0x0F
+#define  REG_VERSION			0x10
+#define  REG_PALEVEL			0x11
+#define  REG_PARAMP			0x12
+#define  REG_OCP			0x13
+#define  REG_AGCREF			0x14 /* not available on RF69 */
+#define  REG_AGCTHRESH1			0x15 /* not available on RF69 */
+#define  REG_AGCTHRESH2			0x16 /* not available on RF69 */
+#define  REG_AGCTHRESH3			0x17 /* not available on RF69 */
+#define  REG_LNA			0x18
+#define  REG_RXBW			0x19
+#define  REG_AFCBW			0x1A
+#define  REG_OOKPEAK			0x1B
+#define  REG_OOKAVG			0x1C
+#define  REG_OOKFIX			0x1D
+#define  REG_AFCFEI			0x1E
+#define  REG_AFCMSB			0x1F
+#define  REG_AFCLSB			0x20
+#define  REG_FEIMSB			0x21
+#define  REG_FEILSB			0x22
+#define  REG_RSSICONFIG			0x23
+#define  REG_RSSIVALUE			0x24
+#define  REG_DIOMAPPING1		0x25
+#define  REG_DIOMAPPING2		0x26
+#define  REG_IRQFLAGS1			0x27
+#define  REG_IRQFLAGS2			0x28
+#define  REG_RSSITHRESH			0x29
+#define  REG_RXTIMEOUT1			0x2A
+#define  REG_RXTIMEOUT2			0x2B
+#define  REG_PREAMBLE_MSB		0x2C
+#define  REG_PREAMBLE_LSB		0x2D
+#define  REG_SYNC_CONFIG		0x2E
+#define  REG_SYNCVALUE1			0x2F
+#define  REG_SYNCVALUE2			0x30
+#define  REG_SYNCVALUE3			0x31
+#define  REG_SYNCVALUE4			0x32
+#define  REG_SYNCVALUE5			0x33
+#define  REG_SYNCVALUE6			0x34
+#define  REG_SYNCVALUE7			0x35
+#define  REG_SYNCVALUE8			0x36
+#define  REG_PACKETCONFIG1		0x37
+#define  REG_PAYLOAD_LENGTH		0x38
+#define  REG_NODEADRS			0x39
+#define  REG_BROADCASTADRS		0x3A
+#define  REG_AUTOMODES			0x3B
+#define  REG_FIFO_THRESH		0x3C
+#define  REG_PACKETCONFIG2		0x3D
+#define  REG_AESKEY1			0x3E
+#define  REG_AESKEY2			0x3F
+#define  REG_AESKEY3			0x40
+#define  REG_AESKEY4			0x41
+#define  REG_AESKEY5			0x42
+#define  REG_AESKEY6			0x43
+#define  REG_AESKEY7			0x44
+#define  REG_AESKEY8			0x45
+#define  REG_AESKEY9			0x46
+#define  REG_AESKEY10			0x47
+#define  REG_AESKEY11			0x48
+#define  REG_AESKEY12			0x49
+#define  REG_AESKEY13			0x4A
+#define  REG_AESKEY14			0x4B
+#define  REG_AESKEY15			0x4C
+#define  REG_AESKEY16			0x4D
+#define  REG_TEMP1			0x4E
+#define  REG_TEMP2			0x4F
+#define  REG_TESTPA1			0x5A /* only present on RFM69HW */
+#define  REG_TESTPA2			0x5C /* only present on RFM69HW */
+#define  REG_TESTDAGC			0x6F
+
+/******************************************************/
+/* RF69/SX1231 bit definition				*/
+/******************************************************/
+/* write bit */
+#define WRITE_BIT				0x80
+
+/* RegOpMode */
+#define  MASK_OPMODE_SEQUENCER_OFF		0x80
+#define  MASK_OPMODE_LISTEN_ON			0x40
+#define  MASK_OPMODE_LISTEN_ABORT		0x20
+#define  MASK_OPMODE_MODE			0x1C
+
+#define  OPMODE_MODE_SLEEP			0x00
+#define  OPMODE_MODE_STANDBY			0x04 /* default */
+#define  OPMODE_MODE_SYNTHESIZER		0x08
+#define  OPMODE_MODE_TRANSMIT			0x0C
+#define  OPMODE_MODE_RECEIVE			0x10
+
+/* RegDataModul */
+#define  MASK_DATAMODUL_MODE			0x06
+#define  MASK_DATAMODUL_MODULATION_TYPE		0x18
+#define  MASK_DATAMODUL_MODULATION_SHAPE	0x03
+
+#define  DATAMODUL_MODE_PACKET			0x00 /* default */
+#define  DATAMODUL_MODE_CONTINUOUS		0x40
+#define  DATAMODUL_MODE_CONTINUOUS_NOSYNC	0x60
+
+#define  DATAMODUL_MODULATION_TYPE_FSK		0x00 /* default */
+#define  DATAMODUL_MODULATION_TYPE_OOK		0x08
+
+#define  DATAMODUL_MODULATION_SHAPE_NONE	0x00 /* default */
+#define  DATAMODUL_MODULATION_SHAPE_1_0		0x01
+#define  DATAMODUL_MODULATION_SHAPE_0_5		0x02
+#define  DATAMODUL_MODULATION_SHAPE_0_3		0x03
+#define  DATAMODUL_MODULATION_SHAPE_BR		0x01
+#define  DATAMODUL_MODULATION_SHAPE_2BR		0x02
+
+/* RegFDevMsb (0x05)*/
+#define FDEVMASB_MASK				0x3f
+
+/*
+// RegOsc1
+#define  OSC1_RCCAL_START			0x80
+#define  OSC1_RCCAL_DONE			0x40
+
+// RegLowBat
+#define  LOWBAT_MONITOR				0x10
+#define  LOWBAT_ON				0x08
+#define  LOWBAT_OFF				0x00  // Default
+
+#define  LOWBAT_TRIM_1695			0x00
+#define  LOWBAT_TRIM_1764			0x01
+#define  LOWBAT_TRIM_1835			0x02  // Default
+#define  LOWBAT_TRIM_1905			0x03
+#define  LOWBAT_TRIM_1976			0x04
+#define  LOWBAT_TRIM_2045			0x05
+#define  LOWBAT_TRIM_2116			0x06
+#define  LOWBAT_TRIM_2185			0x07
+
+
+// RegListen1
+#define  LISTEN1_RESOL_64			0x50
+#define  LISTEN1_RESOL_4100			0xA0  // Default
+#define  LISTEN1_RESOL_262000			0xF0
+
+#define  LISTEN1_CRITERIA_RSSI			0x00  // Default
+#define  LISTEN1_CRITERIA_RSSIANDSYNC		0x08
+
+#define  LISTEN1_END_00				0x00
+#define  LISTEN1_END_01				0x02  // Default
+#define  LISTEN1_END_10				0x04
+
+
+// RegListen2
+#define  LISTEN2_COEFIDLE_VALUE			0xF5 // Default
+
+// RegListen3
+#define  LISTEN3_COEFRX_VALUE			0x20 // Default
+*/
+
+// RegPaLevel
+#define  MASK_PALEVEL_PA0			0x80
+#define  MASK_PALEVEL_PA1			0x40
+#define  MASK_PALEVEL_PA2			0x20
+#define  MASK_PALEVEL_OUTPUT_POWER		0x1F
+
+
+
+// RegPaRamp
+#define  PARAMP_3400				0x00
+#define  PARAMP_2000				0x01
+#define  PARAMP_1000				0x02
+#define  PARAMP_500				0x03
+#define  PARAMP_250				0x04
+#define  PARAMP_125				0x05
+#define  PARAMP_100				0x06
+#define  PARAMP_62				0x07
+#define  PARAMP_50				0x08
+#define  PARAMP_40				0x09 /* default */
+#define  PARAMP_31				0x0A
+#define  PARAMP_25				0x0B
+#define  PARAMP_20				0x0C
+#define  PARAMP_15				0x0D
+#define  PARAMP_12				0x0E
+#define  PARAMP_10				0x0F
+
+#define  MASK_PARAMP				0x0F
+
+/*
+// RegOcp
+#define  OCP_OFF				0x0F
+#define  OCP_ON					0x1A  // Default
+
+#define  OCP_TRIM_45				0x00
+#define  OCP_TRIM_50				0x01
+#define  OCP_TRIM_55				0x02
+#define  OCP_TRIM_60				0x03
+#define  OCP_TRIM_65				0x04
+#define  OCP_TRIM_70				0x05
+#define  OCP_TRIM_75				0x06
+#define  OCP_TRIM_80				0x07
+#define  OCP_TRIM_85				0x08
+#define  OCP_TRIM_90				0x09
+#define  OCP_TRIM_95				0x0A
+#define  OCP_TRIM_100				0x0B  // Default
+#define  OCP_TRIM_105				0x0C
+#define  OCP_TRIM_110				0x0D
+#define  OCP_TRIM_115				0x0E
+#define  OCP_TRIM_120				0x0F
+*/
+
+/* RegLna (0x18) */
+#define  MASK_LNA_ZIN				0x80
+#define  MASK_LNA_CURRENT_GAIN			0x38
+#define  MASK_LNA_GAIN				0x07
+
+#define  LNA_GAIN_AUTO				0x00 /* default */
+#define  LNA_GAIN_MAX				0x01
+#define  LNA_GAIN_MAX_MINUS_6			0x02
+#define  LNA_GAIN_MAX_MINUS_12			0x03
+#define  LNA_GAIN_MAX_MINUS_24			0x04
+#define  LNA_GAIN_MAX_MINUS_36			0x05
+#define  LNA_GAIN_MAX_MINUS_48			0x06
+
+
+/* RegRxBw (0x19) and RegAfcBw (0x1A) */
+#define  MASK_BW_DCC_FREQ			0xE0
+#define  MASK_BW_MANTISSE			0x18
+#define  MASK_BW_EXPONENT			0x07
+
+#define  BW_DCC_16_PERCENT			0x00
+#define  BW_DCC_8_PERCENT			0x20
+#define  BW_DCC_4_PERCENT			0x40 /* default */
+#define  BW_DCC_2_PERCENT			0x60
+#define  BW_DCC_1_PERCENT			0x80
+#define  BW_DCC_0_5_PERCENT			0xA0
+#define  BW_DCC_0_25_PERCENT			0xC0
+#define  BW_DCC_0_125_PERCENT			0xE0
+
+#define  BW_MANT_16				0x00
+#define  BW_MANT_20				0x08
+#define  BW_MANT_24				0x10 /* default */
+
+
+/* RegOokPeak (0x1B) */
+#define  MASK_OOKPEAK_THRESTYPE			0xc0
+#define  MASK_OOKPEAK_THRESSTEP			0x38
+#define  MASK_OOKPEAK_THRESDEC			0x07
+
+#define  OOKPEAK_THRESHTYPE_FIXED		0x00
+#define  OOKPEAK_THRESHTYPE_PEAK		0x40 /* default */
+#define  OOKPEAK_THRESHTYPE_AVERAGE		0x80
+
+#define  OOKPEAK_THRESHSTEP_0_5_DB		0x00 /* default */
+#define  OOKPEAK_THRESHSTEP_1_0_DB		0x08
+#define  OOKPEAK_THRESHSTEP_1_5_DB		0x10
+#define  OOKPEAK_THRESHSTEP_2_0_DB		0x18
+#define  OOKPEAK_THRESHSTEP_3_0_DB		0x20
+#define  OOKPEAK_THRESHSTEP_4_0_DB		0x28
+#define  OOKPEAK_THRESHSTEP_5_0_DB		0x30
+#define  OOKPEAK_THRESHSTEP_6_0_DB		0x38
+
+#define  OOKPEAK_THRESHDEC_ONCE			0x00 /* default */
+#define  OOKPEAK_THRESHDEC_EVERY_2ND		0x01
+#define  OOKPEAK_THRESHDEC_EVERY_4TH		0x02
+#define  OOKPEAK_THRESHDEC_EVERY_8TH		0x03
+#define  OOKPEAK_THRESHDEC_TWICE		0x04
+#define  OOKPEAK_THRESHDEC_4_TIMES		0x05
+#define  OOKPEAK_THRESHDEC_8_TIMES		0x06
+#define  OOKPEAK_THRESHDEC_16_TIMES		0x07
+
+/*
+// RegOokAvg
+#define  OOKAVG_AVERAGETHRESHFILT_00		0x00
+#define  OOKAVG_AVERAGETHRESHFILT_01		0x40
+#define  OOKAVG_AVERAGETHRESHFILT_10		0x80  // Default
+#define  OOKAVG_AVERAGETHRESHFILT_11		0xC0
+
+
+// RegAfcFei
+#define  AFCFEI_FEI_DONE			0x40
+#define  AFCFEI_FEI_START			0x20
+#define  AFCFEI_AFC_DONE			0x10
+#define  AFCFEI_AFCAUTOCLEAR_ON			0x08
+#define  AFCFEI_AFCAUTOCLEAR_OFF		0x00  // Default
+
+#define  AFCFEI_AFCAUTO_ON			0x04
+#define  AFCFEI_AFCAUTO_OFF			0x00  // Default
+
+#define  AFCFEI_AFC_CLEAR			0x02
+#define  AFCFEI_AFC_START			0x01
+
+// RegRssiConfig
+#define  RSSI_FASTRX_ON				0x08
+#define  RSSI_FASTRX_OFF			0x00  // Default
+#define  RSSI_DONE				0x02
+#define  RSSI_START				0x01
+*/
+
+/* RegDioMapping1 */
+#define  MASK_DIO0				0xC0
+#define  MASK_DIO1				0x30
+#define  MASK_DIO2				0x0C
+#define  MASK_DIO3				0x03
+#define  SHIFT_DIO0				6
+#define  SHIFT_DIO1				4
+#define  SHIFT_DIO2				2
+#define  SHIFT_DIO3				0
+
+/* RegDioMapping2 */
+#define  MASK_DIO4				0xC0
+#define  MASK_DIO5				0x30
+#define  SHIFT_DIO4				6
+#define  SHIFT_DIO5				4
+
+/* DIO numbers */
+#define  DIO0					0
+#define  DIO1					1
+#define  DIO2					2
+#define  DIO3					3
+#define  DIO4					4
+#define  DIO5					5
+
+/* DIO Mapping values (packet mode) */
+#define  DIO_ModeReady_DIO4			0x00
+#define  DIO_ModeReady_DIO5			0x03
+#define  DIO_ClkOut				0x00
+#define  DIO_Data				0x01
+#define  DIO_TimeOut_DIO1			0x03
+#define  DIO_TimeOut_DIO4			0x00
+#define  DIO_Rssi_DIO0				0x03
+#define  DIO_Rssi_DIO3_4			0x01
+#define  DIO_RxReady				0x02
+#define  DIO_PLLLock				0x03
+#define  DIO_TxReady				0x01
+#define  DIO_FifoFull_DIO1			0x01
+#define  DIO_FifoFull_DIO3			0x00
+#define  DIO_SyncAddress			0x02
+#define  DIO_FifoNotEmpty_DIO1			0x02
+#define  DIO_FifoNotEmpty_FIO2			0x00
+#define  DIO_Automode				0x04
+#define  DIO_FifoLevel				0x00
+#define  DIO_CrcOk				0x00
+#define  DIO_PayloadReady			0x01
+#define  DIO_PacketSent				0x00
+#define  DIO_Dclk				0x00
+
+/* RegDioMapping2 CLK_OUT part */
+#define  MASK_DIOMAPPING2_CLK_OUT		0x07
+
+#define  DIOMAPPING2_CLK_OUT_NO_DIV		0x00
+#define  DIOMAPPING2_CLK_OUT_DIV_2		0x01
+#define  DIOMAPPING2_CLK_OUT_DIV_4		0x02
+#define  DIOMAPPING2_CLK_OUT_DIV_8		0x03
+#define  DIOMAPPING2_CLK_OUT_DIV_16		0x04
+#define  DIOMAPPING2_CLK_OUT_DIV_32		0x05
+#define  DIOMAPPING2_CLK_OUT_RC			0x06
+#define  DIOMAPPING2_CLK_OUT_OFF		0x07 /* default */
+
+/* RegIrqFlags1 */
+#define  MASK_IRQFLAGS1_MODE_READY		0x80
+#define  MASK_IRQFLAGS1_RX_READY		0x40
+#define  MASK_IRQFLAGS1_TX_READY		0x20
+#define  MASK_IRQFLAGS1_PLL_LOCK		0x10
+#define  MASK_IRQFLAGS1_RSSI			0x08
+#define  MASK_IRQFLAGS1_TIMEOUT			0x04
+#define  MASK_IRQFLAGS1_AUTOMODE		0x02
+#define  MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH	0x01
+
+/* RegIrqFlags2 */
+#define  MASK_IRQFLAGS2_FIFO_FULL		0x80
+#define  MASK_IRQFLAGS2_FIFO_NOT_EMPTY		0x40
+#define  MASK_IRQFLAGS2_FIFO_LEVEL		0x20
+#define  MASK_IRQFLAGS2_FIFO_OVERRUN		0x10
+#define  MASK_IRQFLAGS2_PACKET_SENT		0x08
+#define  MASK_IRQFLAGS2_PAYLOAD_READY		0x04
+#define  MASK_IRQFLAGS2_CRC_OK			0x02
+#define  MASK_IRQFLAGS2_LOW_BAT			0x01
+
+/* RegSyncConfig */
+#define  MASK_SYNC_CONFIG_SYNC_ON		0x80 /* default */
+#define  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION	0x40
+#define  MASK_SYNC_CONFIG_SYNC_SIZE		0x38
+#define  MASK_SYNC_CONFIG_SYNC_TOLERANCE	0x07
+
+/* RegPacketConfig1 */
+#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE	0x80
+#define  MASK_PACKETCONFIG1_DCFREE			0x60
+#define  MASK_PACKETCONFIG1_CRC_ON			0x10 /* default */
+#define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF		0x08
+#define  MASK_PACKETCONFIG1_ADDRESSFILTERING		0x06
+
+#define  PACKETCONFIG1_DCFREE_OFF			0x00 /* default */
+#define  PACKETCONFIG1_DCFREE_MANCHESTER		0x20
+#define  PACKETCONFIG1_DCFREE_WHITENING			0x40
+#define  PACKETCONFIG1_ADDRESSFILTERING_OFF		0x00 /* default */
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODE		0x02
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST	0x04
+
+/*
+// RegAutoModes
+#define  AUTOMODES_ENTER_OFF			0x00  // Default
+#define  AUTOMODES_ENTER_FIFONOTEMPTY		0x20
+#define  AUTOMODES_ENTER_FIFOLEVEL		0x40
+#define  AUTOMODES_ENTER_CRCOK			0x60
+#define  AUTOMODES_ENTER_PAYLOADREADY		0x80
+#define  AUTOMODES_ENTER_SYNCADRSMATCH		0xA0
+#define  AUTOMODES_ENTER_PACKETSENT		0xC0
+#define  AUTOMODES_ENTER_FIFOEMPTY		0xE0
+
+#define  AUTOMODES_EXIT_OFF			0x00  // Default
+#define  AUTOMODES_EXIT_FIFOEMPTY		0x04
+#define  AUTOMODES_EXIT_FIFOLEVEL		0x08
+#define  AUTOMODES_EXIT_CRCOK			0x0C
+#define  AUTOMODES_EXIT_PAYLOADREADY		0x10
+#define  AUTOMODES_EXIT_SYNCADRSMATCH		0x14
+#define  AUTOMODES_EXIT_PACKETSENT		0x18
+#define  AUTOMODES_EXIT_RXTIMEOUT		0x1C
+
+#define  AUTOMODES_INTERMEDIATE_SLEEP		0x00  // Default
+#define  AUTOMODES_INTERMEDIATE_STANDBY		0x01
+#define  AUTOMODES_INTERMEDIATE_RECEIVER	0x02
+#define  AUTOMODES_INTERMEDIATE_TRANSMITTER	0x03
+
+*/
+/* RegFifoThresh (0x3c) */
+#define  MASK_FIFO_THRESH_TXSTART		0x80
+#define  MASK_FIFO_THRESH_VALUE			0x7F
+
+/*
+
+// RegPacketConfig2
+#define  PACKET2_RXRESTARTDELAY_1BIT		0x00  // Default
+#define  PACKET2_RXRESTARTDELAY_2BITS		0x10
+#define  PACKET2_RXRESTARTDELAY_4BITS		0x20
+#define  PACKET2_RXRESTARTDELAY_8BITS		0x30
+#define  PACKET2_RXRESTARTDELAY_16BITS		0x40
+#define  PACKET2_RXRESTARTDELAY_32BITS		0x50
+#define  PACKET2_RXRESTARTDELAY_64BITS		0x60
+#define  PACKET2_RXRESTARTDELAY_128BITS		0x70
+#define  PACKET2_RXRESTARTDELAY_256BITS		0x80
+#define  PACKET2_RXRESTARTDELAY_512BITS		0x90
+#define  PACKET2_RXRESTARTDELAY_1024BITS	0xA0
+#define  PACKET2_RXRESTARTDELAY_2048BITS	0xB0
+#define  PACKET2_RXRESTARTDELAY_NONE		0xC0
+#define  PACKET2_RXRESTART			0x04
+
+#define  PACKET2_AUTORXRESTART_ON		0x02  // Default
+#define  PACKET2_AUTORXRESTART_OFF		0x00
+
+#define  PACKET2_AES_ON				0x01
+#define  PACKET2_AES_OFF			0x00  // Default
+
+
+// RegTemp1
+#define  TEMP1_MEAS_START			0x08
+#define  TEMP1_MEAS_RUNNING			0x04
+#define  TEMP1_ADCLOWPOWER_ON			0x01  // Default
+#define  TEMP1_ADCLOWPOWER_OFF			0x00
+*/
+
+// RegTestDagc (0x6F)
+#define  DAGC_NORMAL				0x00 /* Reset value */
+#define  DAGC_IMPROVED_LOWBETA1			0x20
+#define  DAGC_IMPROVED_LOWBETA0			0x30 /* Recommended val */

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-16  9:52                         ` Wolf Entwicklungen
  0 siblings, 0 replies; 49+ messages in thread
From: Wolf Entwicklungen @ 2017-07-16  9:52 UTC (permalink / raw)
  To: Greg KH
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

From: Marcus Wolf <linux-79IPTMiko8heq5RAq1AYSxS11BummzK+@public.gmane.org>
Date: Tue,16 Jul 2017 11:52:06 +0100
Subject: [PATCH 1/1] drivers/staging/pi433: New driver

Added a driver for the pi433 radio module
(see https://www.pi433.de/en.html for details).

Signed-off-by: Marcus Wolf <linux-79IPTMiko8heq5RAq1AYSxS11BummzK+@public.gmane.org>
---
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 268d4e6..fdf060c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"

 source "drivers/staging/typec/Kconfig"

+source "drivers/staging/pi433/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b93e6f5..998f644 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)		+= ks7010/
 obj-$(CONFIG_GREYBUS)		+= greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)	+= vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)	+= ccree/
+obj-$(CONFIG_PI433)		+= pi433/
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
new file mode 100644
index 0000000..004b502
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
@@ -0,0 +1,53 @@
+// Definitions for Pi433
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			pi433_pins: pi433_pins {
+				brcm,pins = <7 25 24>;
+				brcm,function = <0 0 0>; // in in in
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pi433: pi433@0 {
+				compatible = "Smarthome-Wolf,pi433";
+				reg = <0>;
+				spi-max-frequency = <10000000>;
+				status = "okay";
+
+				pinctrl-0 = <&pi433_pins>;
+				DIO0-gpio = <&gpio 24 0>;
+				DIO1-gpio = <&gpio 25 0>;
+				DIO2-gpio = <&gpio  7 0>;
+			};
+		};
+	};
+};
diff --git a/drivers/staging/pi433/Documentation/devicetree/pi433.txt b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
new file mode 100644
index 0000000..14197c6
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/devicetree/pi433.txt
@@ -0,0 +1,62 @@
+* Smarthome-Wolf Pi433 - a 433MHz radio module/shield for Raspberry Pi (see www.pi433.de)
+
+Required properties:
+- compatible: must be "Smarthome-Wolf,pi433"
+- reg: chip select of SPI Interface
+- DIOx-gpio must be dedicated to the GPIO, connected with DIOx of the RFM69 module
+
+
+Example:
+
+With the following lines in gpio-section, the gpio pins, connected with pi433 are
+reserved/declared.
+
+&gpio{
+	[...]
+
+	pi433_pins: pi433_pins {
+		brcm,pins = <7 25 24>;
+		brcm,function = <0 0 0>; // in in in
+	};
+
+	[...]
+}
+
+With the following lines in spi section, the device pi433 is declared.
+It consists of the three gpio pins and an spi interface (here chip select 0)
+
+&spi0{
+	[...]
+
+	pi433: pi433@0 {
+		compatible = "Smarthome-Wolf,pi433";
+		reg = <0>; /* CE 0 */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-max-frequency = <10000000>;
+
+		pinctrl-0 = <&pi433_pins>;
+		DIO0-gpio = <&gpio 24 0>;
+		DIO1-gpio = <&gpio 25 0>;
+		DIO2-gpio = <&gpio  7 0>;
+	};
+}
+
+
+
+For Raspbian users only
+=======================
+Since Raspbian supports device tree overlays, you may use and overlay, instead
+of editing your boards device tree.
+For using the overlay, you need to compile the file pi433-overlay.dts you can
+find aside to this documentation.
+The file needs to be compiled - either manually or by integration in your kernel
+source tree. For a manual compile, you may use a command line like the following:
+'linux/scripts/dtc/dtc -@ -I dts -O dtb -o pi433.dtbo pi433-overlay.dts'
+
+For compiling inside of the kernel tree, you need to copy pi433-overlay.dts to
+arch/arm/boot/dts/overlays and you need to add the file to the list of files
+in the Makefile over there. Execute 'make dtbs' in kernel tree root to make the
+kernel make files compile the device tree overlay for you.
+
+
diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt
new file mode 100644
index 0000000..860dd0f
--- /dev/null
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -0,0 +1,274 @@
+=====
+Pi433
+=====
+
+
+Introduction
+============
+This driver is for controlling pi433, a radio module for the Raspberry Pi
+(www.pi433.de). It supports transmission and reception. It can be opened
+by multiple applications for transmission and reception. While transmit
+jobs were queued and process automatically in the background, the first
+application asking for reception will block out all other applications
+until something gets received terminates the read request.
+The driver supports on the fly reloading of the hardware fifo of the rf
+chip, thus enabling for much longer telegrams then hardware fifo size.
+
+Discription of driver operation
+===============================
+
+a) transmission
+
+Each transmission can take place with a different configuration of the rf
+module. Therfore each application can set its own set of parameters. The driver
+takes care, that each transmission takes place with the parameterset of the
+application, that requests the transmission. To allow the transmission to take
+place in the background, a tx thread is introduced.
+The transfer of data from the main thread to the tx thread is realised by a
+kfifo. With each write request of an application, the passed in data and the
+corresponding parameter set gets written to the kfifo.
+On the other "side" of the kfifo, the tx thread continuously checks, whether the
+kfifo is empty. If not, it gets one set of config and data from the kfifo. If
+there is no receive request or the receiver is still waiting for something in
+the air, the rf module is set to standby, the parameters for transmission gets
+set, the hardware fifo of the rf chip gets preloaded and the transmission gets
+started. Upon hardware fifo threshold interrupt it gets reloaded, thus enabling
+much longer telegrams then hardware fifo size. If the telegram is send and there
+is more data available in the kfifo, the procedure is repeated. If not the
+transmission cycle ends.
+
+b) reception
+
+Since there is only one application allowed to receive data at a time, for
+reception there is only one configuration set.
+As soon as an application sets an request for receiving a telegram, the reception
+configuration set is written to the rf module and it gets set into receiving mode.
+Now the driver is waiting, that a predefined RSSI level (signal strength at the
+receiver) is reached. Until this hasn't happened, the reception can be
+interrupted by the transmission thread at any time to insert a transmission cycle.
+As soon as the predefined RSSI level is meat, a receiving cycle starts. Similar
+as described for the transmission cycle the read out of the hardware fifo is done
+dynamically. Upon each hardware fifo threshold interrupt, a portion of data gets
+read. So also for reception it is possible to receive more data then the hardware
+fifo can hold.
+
+
+Driver API
+==========
+
+The driver is currently implemented as a character device. Therefore it supports
+the calls open, ioctl, read, write and close.
+
+
+params for ioctl
+----------------
+
+There are four options:
+PI433_IOC_RD_TX_CFG - get the transmission parameters from the driver
+PI433_IOC_WR_TX_CFG - set the transmission parameters
+PI433_IOC_RD_RX_CFG - get the receiving parameters from the driver
+PI433_IOC_WR_RX_CFG - set the receiving parameters
+
+The tx configuration is transfered via struct pi433_tx_cfg, the parameterset for transmission.
+It is devided into two sections: rf parameters and packet format.
+
+rf params:
+	frequency
+		frequency used for transmission.
+		Allowed values: 433050000...434790000
+	bit_rate
+		bit rate used for transmission.
+		Allowed values: #####
+	dev_frequency
+		frequency deviation in case of FSK.
+		Allowed values: 600...500000
+	modulation
+		FSK - frequency shift key
+		OOK - On-Off-key
+	modShaping
+		shapingOff	- no shaping
+		shaping1_0	- gauss filter with BT 1 (FSK only)
+		shaping0_5	- gauss filter with BT 0.5 (FSK only)
+		shaping0_3	- gauss filter with BT 0.3 (FSK only)
+		shapingBR	- filter cut off at BR (OOK only)
+		shaping2BR	- filter cut off at 2*BR (OOK only)
+	paRamp (FSK only)
+		ramp3400	- amp ramps up in 3.4ms
+		ramp2000	- amp ramps up in 2.0ms
+		ramp1000	- amp ramps up in 1ms
+		ramp500		- amp ramps up in 500us
+		ramp250		- amp ramps up in 250us
+		ramp125		- amp ramps up in 125us
+		ramp100		- amp ramps up in 100us
+		ramp62		- amp ramps up in 62us
+		ramp50		- amp ramps up in 50us
+		ramp40		- amp ramps up in 40us
+		ramp31		- amp ramps up in 31us
+		ramp25		- amp ramps up in 25us
+		ramp20		- amp ramps up in 20us
+		ramp15		- amp ramps up in 15us
+		ramp12		- amp ramps up in 12us
+		ramp10		- amp ramps up in 10us
+	tx_start_condition
+		fifoLevel	- transmission starts, if fifo is filled to
+				  threshold level
+		fifoNotEmpty	- transmission starts, as soon as there is one
+				  byte in internal fifo
+	repetitions
+		This gives the option, to send a telegram multiple times. Default: 1
+
+packet format:
+	enable_preamble
+		optionOn	- a preamble will be automatically generated
+		optionOff	- no preamble will be generated
+	enable_sync
+		optionOn	- a sync word will be automatically added to
+				  the telegram after preamble
+		optionOff	- no sync word will be added
+		Attention: While possible to generate sync without preamble, the
+		receiver won't be able to detect the sync without preamble.
+	enable_length_byte
+		optionOn	- the length of the telegram will be automatically
+				  added to the telegram. It's part of the payload
+		optionOff	- no length information will be automatically added
+				  to the telegram.
+		Attention: For telegram length over 255 bytes, this option can't be used
+		Attention: should be used in combination with sync, only
+	enable_address_byte
+		optionOn	- the address byte will be automatically added to the
+				  telgram. It's part of the payload
+		optionOff	- the address byte will not be added to the telegram.
+		The address byte can be used for address filtering, so the receiver
+		will only receive telegrams with a given address byte.
+		Attention: should be used in combination with sync, only
+	enable_crc
+		optionOn	- an crc will be automatically calculated over the
+				  payload of the telegram and added to the telegram
+				  after payload.
+		optionOff	- no crc will be calculated
+	preamble_length
+		length of the preamble. Allowed values: 0...65536
+	sync_length
+		length of the sync word. Allowed values: 0...8
+	fixed_message_length
+		length of the payload of the telegram. Will override the length
+		given by the buffer, passed in with the write command. Will be
+		ignored if set to zero.
+	sync_pattern[8]
+		contains up to eight values, that are used as the sync pattern
+		on sync option
+	address_byte
+		one byte, used as address byte on address byte option.
+
+
+The rx configuration is transfered via struct pi433_rx_cfg, the parameterset for receiving. It is devided into two sections: rf parameters and packet format.
+
+rf params:
+	frequency
+		frequency used for transmission.
+		Allowed values: 433050000...434790000
+	bit_rate
+		bit rate used for transmission.
+		Allowed values: #####
+	dev_frequency
+		frequency deviation in case of FSK.
+		Allowed values: 600...500000
+	modulation
+		FSK - frequency shift key
+		OOK - on off key
+	rssi_threshold
+		threshold value for the signal strength on the receiver input.
+		If this value is exeeded, a reception cycle starts
+		Allowed values: 0...255
+	thresholdDecrement
+		in order to adapt to different levels of singnal strength, over
+		time the receiver gets more and more sensitive. This value
+		determs, how fast the sensitivity increases.
+		step_0_5db	- increase in 0,5dB steps
+		step_1_0db	- increase in 1 db steps
+		step_1_5db	- increase in 1,5dB steps
+		step_2_0db	- increase in 2 db steps
+		step_3_0db	- increase in 3 db steps
+		step_4_0db	- increase in 4 db steps
+		step_5_0db	- increase in 5 db steps
+		step_6_0db	- increase in 6 db steps
+	antennaImpedance
+		sets the electrical adoption of the antenna
+		fiftyOhm	- for antennas with an impedance of 50Ohm
+		twohundretOhm	- for antennas with an impedance of 200Ohm
+	lnaGain
+		sets the gain of the low noise amp
+		automatic	- lna gain is determed by an agc
+		max		- lna gain is set to maximum
+		maxMinus6	- lna gain is set to  6db below max
+		maxMinus12	- lna gain is set to 12db below max
+		maxMinus24	- lna gain is set to 24db below max
+		maxMinus36	- lna gain is set to 36db below max
+		maxMinus48	- lna gain is set to 48db below max
+	bw_mantisse
+		sets the bandwidth of the channel filter - part one: mantisse.
+		mantisse16	- mantisse is set to 16
+		mantisse20	- mantisse is set to 20
+		mantisse24	- mantisse is set to 24
+	bw_exponent
+		sets the bandwidth of the channel filter - part two: exponent.
+		Allowd values: 0...7
+	dagc;
+		operation mode of the digital automatic gain control
+		normalMode
+		improve
+		improve4LowModulationIndex
+
+ packet format:
+	enable_sync
+		optionOn  - sync detection is enabled. If configured sync pattern
+			    isn't found, telegram will be internally discarded
+		optionOff - sync detection is disabled.
+	enable_length_byte
+		optionOn   - First byte of payload will be used as length byte,
+			     regardless of the amount of bytes that were requested
+			     by the read request.
+		optionOff  - Number of bytes to be read will be set according to
+			     amount of bytes that were requested by the read request.
+		Attention: should be used in combination with sync, only
+	enable_address_filtering;
+		filteringOff		- no adress filtering will take place
+		nodeAddress		- all telegrams, not matching the node
+					  address will be internally discarded
+		nodeOrBroadcastAddress	- all telegrams, neither matching the
+					  node, nor the broadcast address will
+					  be internally discarded
+		Attention: Sync option must be enabled in order to use this feature
+	enable_crc
+		optionOn	- a crc will be calculated over the payload of
+				  the telegram, that was received. If the
+				  calculated crc doesn't match to two bytes,
+				  that follow the payload, the telegram will be
+				  internally discarded.
+		Attention: This option is only operational, if sync on and fixed length
+		or length byte is used
+	sync_length
+		Gives the length of the payload.
+		Attention: This setting must meet the setting of the transmitter,
+		if sync option is used.
+	fixed_message_length
+		Overrides the telegram length either given by the first byte of
+		payload or by the read request.
+	bytes_to_drop
+		gives the number of bytes, that will be dropped before transfering
+		data to the read buffer
+		This option is only usefull, if all packet helper are switched
+		off and the rf chip is used in raw receiving mode. This may be
+		needed, if a telegram of a third party device should be received,
+		using a protocol not compatible with the packet engine of the rf69 chip.
+	sync_pattern[8]
+		contains up to eight values, that are used as the sync pattern
+		on sync option.
+		This setting must meet the configuration of the transmitting device,
+		if sync option is enabled.
+	node_address
+		one byte, used as node address byte on address byte option.
+	broadcast_address
+		one byte, used as broadcast address byte on address byte option.
+
+
diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
new file mode 100644
index 0000000..61b4b4e
--- /dev/null
+++ b/drivers/staging/pi433/Kconfig
@@ -0,0 +1,16 @@
+config PI433
+        tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
+        default n
+        ---help---
+          This option allows you to enable support for the radio module Pi433.
+
+          Pi433 is a shield that fits onto the GPIO header of a Raspberry Pi
+          or compatible. It extends the Raspberry Pi with the option, to
+          send and receive data in the 433MHz ISM band - for example to
+          communicate between two systems without using ethernet or bluetooth
+          or for control or read sockets, actors, sensors, widely available
+          for low price.
+
+          For details or the option to buy, please visit https://pi433.de/en.html
+
+          If in doubt, say N here, but saying yes most probably won't hurt
diff --git a/drivers/staging/pi433/Makefile b/drivers/staging/pi433/Makefile
new file mode 100644
index 0000000..417f3e4
--- /dev/null
+++ b/drivers/staging/pi433/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PI433) += pi433.o
+
+pi433-objs := pi433_if.o rf69.o
diff --git a/drivers/staging/pi433/TODO b/drivers/staging/pi433/TODO
new file mode 100644
index 0000000..63a40bf
--- /dev/null
+++ b/drivers/staging/pi433/TODO
@@ -0,0 +1,5 @@
+* coding style does not fully comply with the kernel style guide.
+* still TODOs, annotated in the code
+* currently the code introduces new IOCTLs. I'm afraid this is a bad idea.
+  -> Replace this with another interface, hints are welcome!
+* Some missing data (marked with ###) needs to be added in the documentation
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
new file mode 100644
index 0000000..541ca78
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.c
@@ -0,0 +1,1314 @@
+/*
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+#endif
+
+#include "pi433_if.h"
+#include "rf69.h"
+
+
+#define N_PI433_MINORS			(1U << MINORBITS) /*32*/	/* ... up to 256 */
+#define MAX_MSG_SIZE			900	/* min: FIFO_SIZE! */
+#define MSG_FIFO_SIZE			65536   /* 65536 = 2^16  */
+#define NUM_DIO				2
+
+static dev_t pi433_dev;
+static DEFINE_IDR(pi433_idr);
+static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+
+static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
+
+/* tx config is instance specific
+	so with each open a new tx config struct is needed */
+/* rx config is device specific
+	so we have just one rx config, ebedded in device struct */
+struct pi433_device {
+	/* device handling related values */
+	dev_t			devt;
+	int			minor;
+	struct device		*dev;
+	struct cdev		*cdev;
+	struct spi_device	*spi;
+	unsigned		users;
+
+	/* irq related values */
+	struct gpio_desc	*gpiod[NUM_DIO];
+	int			irq_num[NUM_DIO];
+	u8			irq_state[NUM_DIO];
+
+	/* tx related values */
+	STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo;
+	struct mutex		tx_fifo_lock; // TODO: check, whether necessary or obsolete
+	struct task_struct	*tx_task_struct;
+	wait_queue_head_t	tx_wait_queue;
+	u8			free_in_fifo;
+
+	/* rx related values */
+	struct pi433_rx_cfg	rx_cfg;
+	u8			*rx_buffer;
+	unsigned int		rx_buffer_size;
+	u32			rx_bytes_to_drop;
+	u32			rx_bytes_dropped;
+	unsigned int		rx_position;
+	struct mutex		rx_lock;
+	wait_queue_head_t	rx_wait_queue;
+
+	/* fifo wait queue */
+	struct task_struct	*fifo_task_struct;
+	wait_queue_head_t	fifo_wait_queue;
+
+	/* flags */
+	bool			rx_active;
+	bool			tx_active;
+	bool			interrupt_rx_allowed;
+};
+
+struct pi433_instance {
+	struct pi433_device	*device;
+	struct pi433_tx_cfg	tx_cfg;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* macro for checked access of registers of radio module */
+#define SET_CHECKED(retval) \
+	if (retval < 0) \
+		return retval;
+
+/*-------------------------------------------------------------------------*/
+
+/* GPIO interrupt handlers */
+static irq_handler_t
+DIO0_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pi433_device *device = dev_id;
+
+	if      (device->irq_state[DIO0] == DIO_PacketSent)
+	{
+		device->free_in_fifo = FIFO_SIZE;
+		printk("DIO0 irq: Packet sent\n"); // TODO: printk() should include KERN_ facility level
+		wake_up_interruptible(&device->fifo_wait_queue);
+	}
+	else if (device->irq_state[DIO0] == DIO_Rssi_DIO0)
+	{
+		printk("DIO0 irq: RSSI level over threshold\n");
+		wake_up_interruptible(&device->rx_wait_queue);
+	}
+	else if (device->irq_state[DIO0] == DIO_PayloadReady)
+	{
+		printk("DIO0 irq: PayloadReady\n");
+		device->free_in_fifo = 0;
+		wake_up_interruptible(&device->fifo_wait_queue);
+	}
+
+	return (irq_handler_t) IRQ_HANDLED;
+}
+
+static irq_handler_t
+DIO1_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pi433_device *device = dev_id;
+
+	if      (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1)
+	{
+		device->free_in_fifo = FIFO_SIZE;
+	}
+	else if (device->irq_state[DIO1] == DIO_FifoLevel)
+	{
+		if (device->rx_active)	device->free_in_fifo = FIFO_THRESHOLD - 1;
+		else			device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1;
+	}
+	printk("DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); // TODO: printk() should include KERN_ facility level
+	wake_up_interruptible(&device->fifo_wait_queue);
+
+	return (irq_handler_t) IRQ_HANDLED;
+}
+
+static void *DIO_irq_handler[NUM_DIO] = {
+	DIO0_irq_handler,
+	DIO1_irq_handler
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
+{
+	int payload_length;
+
+	/* receiver config */
+	SET_CHECKED(rf69_set_frequency	(dev->spi, rx_cfg->frequency));
+	SET_CHECKED(rf69_set_bit_rate	(dev->spi, rx_cfg->bit_rate));
+	SET_CHECKED(rf69_set_modulation	(dev->spi, rx_cfg->modulation));
+	SET_CHECKED(rf69_set_antenna_impedance	 (dev->spi, rx_cfg->antenna_impedance));
+	SET_CHECKED(rf69_set_rssi_threshold	 (dev->spi, rx_cfg->rssi_threshold));
+	SET_CHECKED(rf69_set_ook_threshold_dec	 (dev->spi, rx_cfg->thresholdDecrement));
+	SET_CHECKED(rf69_set_bandwidth 		 (dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent));
+	SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent));
+	SET_CHECKED(rf69_set_dagc 		 (dev->spi, rx_cfg->dagc));
+
+	dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop;
+
+	/* packet config */
+	/* enable */
+	SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync));
+	if (rx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always));
+	}
+	SET_CHECKED(rf69_set_packet_format  (dev->spi, rx_cfg->enable_length_byte));
+	SET_CHECKED(rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering));
+	SET_CHECKED(rf69_set_crc_enable	    (dev->spi, rx_cfg->enable_crc));
+
+	/* lengths */
+	SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length));
+	if (rx_cfg->enable_length_byte == optionOn)
+	{
+		SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff));
+	}
+	else if (rx_cfg->fixed_message_length != 0)
+	{
+		payload_length = rx_cfg->fixed_message_length;
+		if (rx_cfg->enable_length_byte  == optionOn) payload_length++;
+		if (rx_cfg->enable_address_filtering != filteringOff) payload_length++;
+		SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_payload_length(dev->spi, 0));
+	}
+
+	/* values */
+	if (rx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern));
+	}
+	if (rx_cfg->enable_address_filtering != filteringOff)
+	{
+		SET_CHECKED(rf69_set_node_address     (dev->spi, rx_cfg->node_address));
+		SET_CHECKED(rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address));
+	}
+
+	return 0;
+}
+
+static int
+rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
+{
+	SET_CHECKED(rf69_set_frequency	(dev->spi, tx_cfg->frequency));
+	SET_CHECKED(rf69_set_bit_rate	(dev->spi, tx_cfg->bit_rate));
+	SET_CHECKED(rf69_set_modulation	(dev->spi, tx_cfg->modulation));
+	SET_CHECKED(rf69_set_deviation	(dev->spi, tx_cfg->dev_frequency));
+	SET_CHECKED(rf69_set_pa_ramp	(dev->spi, tx_cfg->pa_ramp));
+	SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping));
+	SET_CHECKED(rf69_set_tx_start_condition(dev->spi, tx_cfg->tx_start_condition));
+
+	/* packet format enable */
+	if (tx_cfg->enable_preamble == optionOn)
+	{
+		SET_CHECKED(rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length));
+	}
+	else
+	{
+		SET_CHECKED(rf69_set_preamble_length(dev->spi, 0));
+	}
+	SET_CHECKED(rf69_set_sync_enable  (dev->spi, tx_cfg->enable_sync));
+	SET_CHECKED(rf69_set_packet_format(dev->spi, tx_cfg->enable_length_byte));
+	SET_CHECKED(rf69_set_crc_enable	  (dev->spi, tx_cfg->enable_crc));
+
+	/* configure sync, if enabled */
+	if (tx_cfg->enable_sync == optionOn)
+	{
+		SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length));
+		SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern));
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pi433_start_rx(struct pi433_device *dev)
+{
+	int retval;
+
+	/* return without action, if no pending read request */
+	if (!dev->rx_active)
+		return 0;
+
+	/* setup for receiving */
+	retval = rf69_set_rx_cfg(dev, &dev->rx_cfg);
+	if (retval) return retval;
+
+	/* setup rssi irq */
+	SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0));
+	dev->irq_state[DIO0] = DIO_Rssi_DIO0;
+	irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+	/* setup fifo level interrupt */
+	SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD));
+	SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel));
+	dev->irq_state[DIO1] = DIO_FifoLevel;
+	irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING);
+
+	/* set module to receiving mode */
+	SET_CHECKED(rf69_set_mode(dev->spi, receive));
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int
+pi433_receive(void *data)
+{
+	struct pi433_device *dev = data;
+	struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */
+	int bytes_to_read, bytes_total;
+	int retval;
+
+	dev->interrupt_rx_allowed = false;
+
+	/* wait for any tx to finish */
+	dev_dbg(dev->dev,"rx: going to wait for any tx to finish");
+	retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
+	if(retval) /* wait was interrupted */
+	{
+		dev->interrupt_rx_allowed = true;
+		wake_up_interruptible(&dev->tx_wait_queue);
+		return retval;
+	}
+
+	/* prepare status vars */
+	dev->free_in_fifo = FIFO_SIZE;
+	dev->rx_position = 0;
+	dev->rx_bytes_dropped = 0;
+
+	/* setup radio module to listen for something "in the air" */
+	retval = pi433_start_rx(dev);
+	if (retval)
+		return retval;
+
+	/* now check RSSI, if low wait for getting high (RSSI interrupt) */
+	while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) )
+	{
+		/* allow tx to interrupt us while waiting for high RSSI */
+		dev->interrupt_rx_allowed = true;
+		wake_up_interruptible(&dev->tx_wait_queue);
+
+		/* wait for RSSI level to become high */
+		dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
+		retval = wait_event_interruptible(dev->rx_wait_queue,
+			                          rf69_get_flag(dev->spi,
+		                                                rssiExceededThreshold));
+		if (retval) goto abort; /* wait was interrupted */
+		dev->interrupt_rx_allowed = false;
+
+		/* cross check for ongoing tx */
+		if (!dev->tx_active) break;
+	}
+
+	/* configure payload ready irq */
+	SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady));
+	dev->irq_state[DIO0] = DIO_PayloadReady;
+	irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+
+	/* fixed or unlimited length? */
+	if (dev->rx_cfg.fixed_message_length != 0)
+	{
+		if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size)
+		{
+			retval = -1;
+			goto abort;
+		}
+		bytes_total = dev->rx_cfg.fixed_message_length;
+		dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total);
+	}
+	else
+	{
+		bytes_total = dev->rx_buffer_size;
+		dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total);
+	}
+
+	/* length byte enabled? */
+	if (dev->rx_cfg.enable_length_byte == optionOn)
+	{
+		retval = wait_event_interruptible(dev->fifo_wait_queue,
+						  dev->free_in_fifo < FIFO_SIZE);
+		if (retval) goto abort; /* wait was interrupted */
+
+		rf69_read_fifo(spi, (u8 *)&bytes_total, 1);
+		if (bytes_total > dev->rx_buffer_size)
+		{
+			retval = -1;
+			goto abort;
+		}
+		dev->free_in_fifo++;
+		dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total);
+	}
+
+	/* address byte enabled? */
+	if (dev->rx_cfg.enable_address_filtering != filteringOff)
+	{
+		u8 dummy;
+
+		bytes_total--;
+
+		retval = wait_event_interruptible(dev->fifo_wait_queue,
+						  dev->free_in_fifo < FIFO_SIZE);
+		if (retval) goto abort; /* wait was interrupted */
+
+		rf69_read_fifo(spi, &dummy, 1);
+		dev->free_in_fifo++;
+		dev_dbg(dev->dev, "rx: address byte stripped off");
+	}
+
+	/* get payload */
+	while (dev->rx_position < bytes_total)
+	{
+		if ( !rf69_get_flag(dev->spi, payloadReady) )
+		{
+			retval = wait_event_interruptible(dev->fifo_wait_queue,
+							  dev->free_in_fifo < FIFO_SIZE);
+			if (retval) goto abort; /* wait was interrupted */
+		}
+
+		/* need to drop bytes or acquire? */
+		if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+			bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+		else
+			bytes_to_read = bytes_total - dev->rx_position;
+
+
+		/* access the fifo */
+		if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo)
+			bytes_to_read = FIFO_SIZE - dev->free_in_fifo;
+		retval = rf69_read_fifo(spi,
+					&dev->rx_buffer[dev->rx_position],
+					bytes_to_read);
+		if (retval) goto abort; /* read failed */
+		dev->free_in_fifo += bytes_to_read;
+
+		/* adjust status vars */
+		if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
+			dev->rx_bytes_dropped += bytes_to_read;
+		else
+			dev->rx_position += bytes_to_read;
+	}
+
+
+	/* rx done, wait was interrupted or error occured */
+abort:
+	dev->interrupt_rx_allowed = true;
+	SET_CHECKED(rf69_set_mode(dev->spi, standby));
+	wake_up_interruptible(&dev->tx_wait_queue);
+
+	if (retval)
+		return retval;
+	else
+		return bytes_total;
+}
+
+int
+pi433_tx_thread(void *data)
+{
+	struct pi433_device *device = data;
+	struct spi_device *spi = device->spi; /* needed for SET_CHECKED */
+	struct pi433_tx_cfg tx_cfg;
+	u8     buffer[MAX_MSG_SIZE];
+	size_t size;
+	bool   rx_interrupted = false;
+	int    position, repetitions;
+	int    retval;
+
+	while (1)
+	{
+		/* wait for fifo to be populated or for request to terminate*/
+		dev_dbg(device->dev, "thread: going to wait for new messages");
+		wait_event_interruptible(device->tx_wait_queue,
+					 ( !kfifo_is_empty(&device->tx_fifo) ||
+					    kthread_should_stop() ));
+		if ( kthread_should_stop() )
+			return 0;
+
+		/* get data from fifo in the following order:
+		   - tx_cfg
+		   - size of message
+		   - message */
+		mutex_lock(&device->tx_fifo_lock);
+
+		retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg));
+		if (retval != sizeof(tx_cfg))
+		{
+			dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) );
+			mutex_unlock(&device->tx_fifo_lock);
+			continue;
+		}
+
+		retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t));
+		if (retval != sizeof(size_t))
+		{
+			dev_dbg(device->dev, "reading msg size from fifo failed: got %d, expected %d", retval, (unsigned int)sizeof(size_t) );
+			mutex_unlock(&device->tx_fifo_lock);
+			continue;
+		}
+
+		/* use fixed message length, if requested */
+		if (tx_cfg.fixed_message_length != 0)
+			size = tx_cfg.fixed_message_length;
+
+		/* increase size, if len byte is requested */
+		if (tx_cfg.enable_length_byte == optionOn)
+			size++;
+
+		/* increase size, if adr byte is requested */
+		if (tx_cfg.enable_address_byte == optionOn)
+			size++;
+
+		/* prime buffer */
+		memset(buffer, 0, size);
+		position = 0;
+
+		/* add length byte, if requested */
+		if (tx_cfg.enable_length_byte  == optionOn)
+			buffer[position++] = size-1; /* according to spec length byte itself must be excluded from the length calculation */
+
+		/* add adr byte, if requested */
+		if (tx_cfg.enable_address_byte == optionOn)
+			buffer[position++] = tx_cfg.address_byte;
+
+		/* finally get message data from fifo */
+		retval = kfifo_out(&device->tx_fifo, &buffer[position], sizeof(buffer)-position );
+		dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval);
+		mutex_unlock(&device->tx_fifo_lock);
+
+		/* if rx is active, we need to interrupt the waiting for
+		   incoming telegrams, to be able to send something.
+		   We are only allowed, if currently no reception takes
+		   place otherwise we need to  wait for the incoming telegram
+		   to finish */
+		wait_event_interruptible(device->tx_wait_queue,
+					 !device->rx_active ||
+					  device->interrupt_rx_allowed == true);
+
+		/* prevent race conditions
+		   irq will be reenabled after tx config is set */
+		disable_irq(device->irq_num[DIO0]);
+		device->tx_active = true;
+
+		if (device->rx_active && rx_interrupted == false)
+		{
+			/* rx is currently waiting for a telegram;
+			   we need to set the radio module to standby */
+			SET_CHECKED(rf69_set_mode(device->spi, standby));
+			rx_interrupted = true;
+		}
+
+		/* clear fifo, set fifo threshold, set payload length */
+		SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */
+		SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD));
+		if (tx_cfg.enable_length_byte == optionOn)
+		{
+			SET_CHECKED(rf69_set_payload_length(spi, size * tx_cfg.repetitions));
+		}
+		else
+		{
+			SET_CHECKED(rf69_set_payload_length(spi, 0));
+		}
+
+		/* configure the rf chip */
+		rf69_set_tx_cfg(device, &tx_cfg);
+
+		/* enable fifo level interrupt */
+		SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel));
+		device->irq_state[DIO1] = DIO_FifoLevel;
+		irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING);
+
+		/* enable packet sent interrupt */
+		SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent));
+		device->irq_state[DIO0] = DIO_PacketSent;
+		irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING);
+		enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check */
+
+		/* enable transmission */
+		SET_CHECKED(rf69_set_mode(spi, transmit));
+
+		/* transfer this msg (and repetitions) to chip fifo */
+		device->free_in_fifo = FIFO_SIZE;
+		position = 0;
+		repetitions = tx_cfg.repetitions;
+		while( (repetitions > 0) && (size > position) )
+		{
+			if ( (size - position) > device->free_in_fifo)
+			{	/* msg to big for fifo - take a part */
+				int temp = device->free_in_fifo;
+				device->free_in_fifo = 0;
+				rf69_write_fifo(spi,
+				                &buffer[position],
+				                temp);
+				position +=temp;
+			}
+			else
+			{	/* msg fits into fifo - take all */
+				device->free_in_fifo -= size;
+				repetitions--;
+				rf69_write_fifo(spi,
+						&buffer[position],
+						(size - position) );
+				position = 0; /* reset for next repetition */
+			}
+
+			retval = wait_event_interruptible(device->fifo_wait_queue,
+							  device->free_in_fifo > 0);
+			if (retval) { printk("ABORT\n"); goto abort; }
+		}
+
+		/* we are done. Wait for packet to get sent */
+		dev_dbg(device->dev, "thread: wiat for packet to get sent/fifo to be empty");
+		wait_event_interruptible(device->fifo_wait_queue,
+					 device->free_in_fifo == FIFO_SIZE ||
+					 kthread_should_stop() );
+		if ( kthread_should_stop() )	printk("ABORT\n");
+
+
+		/* STOP_TRANSMISSION */
+		dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.");
+		SET_CHECKED(rf69_set_mode(spi, standby));
+
+		/* everything sent? */
+		if ( kfifo_is_empty(&device->tx_fifo) )
+		{
+abort:
+			if (rx_interrupted)
+			{
+				rx_interrupted = false;
+				pi433_start_rx(device);
+			}
+			device->tx_active = false;
+			wake_up_interruptible(&device->rx_wait_queue);
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t
+pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	int			bytes_received;
+	ssize_t			retval;
+
+	/* check, whether internal buffer is big enough for requested size */
+	if (size > MAX_MSG_SIZE)
+		return -EMSGSIZE;
+
+	instance = filp->private_data;
+	device = instance->device;
+
+	/* just one read request at a time */
+	mutex_lock(&device->rx_lock);
+	if (device->rx_active)
+	{
+		mutex_unlock(&device->rx_lock);
+		return -EAGAIN;
+	}
+	else
+	{
+		device->rx_active = true;
+		mutex_unlock(&device->rx_lock);
+	}
+
+	/* start receiving */
+	/* will block until something was received*/
+	device->rx_buffer_size = size;
+	bytes_received = pi433_receive(device);
+
+	/* release rx */
+	mutex_lock(&device->rx_lock);
+	device->rx_active = false;
+	mutex_unlock(&device->rx_lock);
+
+	/* if read was successful copy to user space*/
+	if (bytes_received > 0)
+	{
+		retval = copy_to_user(buf, device->rx_buffer, bytes_received);
+		if (retval)
+			return retval;
+	}
+
+	return bytes_received;
+}
+
+
+static ssize_t
+pi433_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	int                     copied, retval;
+
+	instance = filp->private_data;
+	device = instance->device;
+
+	/* check, whether internal buffer (tx thread) is big enough for requested size */
+	if (count > MAX_MSG_SIZE)
+		return -EMSGSIZE;
+
+	/* write the following sequence into fifo:
+	   - tx_cfg
+	   - size of message
+	   - message */
+	mutex_lock(&device->tx_fifo_lock);
+	retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg));
+	if ( retval != sizeof(instance->tx_cfg) )
+		goto abort;
+
+	retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t));
+	if ( retval != sizeof(size_t) )
+		goto abort;
+
+	retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied);
+	if (retval || copied != count)
+		goto abort;
+
+	mutex_unlock(&device->tx_fifo_lock);
+
+	/* start transfer */
+	wake_up_interruptible(&device->tx_wait_queue);
+	dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied);
+
+	return 0;
+
+abort:
+	dev_dbg(device->dev, "write to fifo failed: 0x%x", retval);
+	kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to discard already stored, valid entries
+	mutex_unlock(&device->tx_fifo_lock);
+	return -EAGAIN;
+}
+
+
+static long
+pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int			err = 0;
+	int			retval = 0;
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+	u32			tmp;
+
+	/* Check type and command number */
+	if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
+		return -ENOTTY;
+
+	/* Check access direction once here; don't repeat below.
+	 * IOC_DIR is from the user perspective, while access_ok is
+	 * from the kernel perspective; so they look reversed.
+	 */
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok(VERIFY_WRITE,
+				 (void __user *)arg,
+				 _IOC_SIZE(cmd));
+
+	if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok(VERIFY_READ,
+				 (void __user *)arg,
+				 _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	/* TODO? guard against device removal before, or while,
+	 * we issue this ioctl. --> device_get()
+	 */
+	instance = filp->private_data;
+	device = instance->device;
+
+	if (device == NULL)
+		return -ESHUTDOWN;
+
+	switch (cmd) {
+	case PI433_IOC_RD_TX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+		{
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_to_user((void __user *)arg,
+				    &instance->tx_cfg,
+				    tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+	case PI433_IOC_WR_TX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0) )
+		{
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_from_user(&instance->tx_cfg,
+				     (void __user *)arg,
+				     tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+
+	case PI433_IOC_RD_RX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+			retval = -EINVAL;
+			break;
+		}
+
+		if (__copy_to_user((void __user *)arg,
+				   &device->rx_cfg,
+				   tmp))
+		{
+			retval = -EFAULT;
+			break;
+		}
+
+		break;
+	case PI433_IOC_WR_RX_CFG:
+		tmp = _IOC_SIZE(cmd);
+		mutex_lock(&device->rx_lock);
+
+		/* during pendig read request, change of config not allowed */
+		if (device->rx_active) {
+			retval = -EAGAIN;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
+			retval = -EINVAL;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		if (__copy_from_user(&device->rx_cfg,
+				     (void __user *)arg,
+				     tmp))
+		{
+			retval = -EFAULT;
+			mutex_unlock(&device->rx_lock);
+			break;
+		}
+
+		mutex_unlock(&device->rx_lock);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define pi433_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_open(struct inode *inode, struct file *filp)
+{
+	struct pi433_device	*device;
+	struct pi433_instance	*instance;
+
+	mutex_lock(&minor_lock);
+	device = idr_find(&pi433_idr, iminor(inode));
+	mutex_unlock(&minor_lock);
+	if (!device) {
+		pr_debug("device: minor %d unknown.\n", iminor(inode));
+		return -ENODEV;
+	}
+
+	if (!device->rx_buffer) {
+		device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL);
+		if (!device->rx_buffer)
+		{
+			dev_dbg(device->dev, "open/ENOMEM\n");
+			return -ENOMEM;
+		}
+	}
+
+	device->users++;
+	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+	if (!instance)
+	{
+		kfree(device->rx_buffer);
+		device->rx_buffer = NULL;
+		return -ENOMEM;
+	}
+
+	/* setup instance data*/
+	instance->device = device;
+	instance->tx_cfg.bit_rate = 4711;
+	// TODO: fill instance->tx_cfg;
+
+	/* instance data as context */
+	filp->private_data = instance;
+	nonseekable_open(inode, filp);
+
+	return 0;
+}
+
+static int pi433_release(struct inode *inode, struct file *filp)
+{
+	struct pi433_instance	*instance;
+	struct pi433_device	*device;
+
+	instance = filp->private_data;
+	device = instance->device;
+	kfree(instance);
+	filp->private_data = NULL;
+
+	/* last close? */
+	device->users--;
+
+	if (!device->users) {
+		kfree(device->rx_buffer);
+		device->rx_buffer = NULL;
+		if (device->spi == NULL)
+			kfree(device);
+	}
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int setup_GPIOs(struct pi433_device *device)
+{
+	char 	name[5];
+	int	retval;
+	int	i;
+
+	for (i=0; i<NUM_DIO; i++)
+	{
+		/* "construct" name and get the gpio descriptor */
+		snprintf(name, sizeof(name), "DIO%d", i);
+		device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+
+		if (device->gpiod[i] == ERR_PTR(-ENOENT))
+		{
+			dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name);
+			continue;
+		}
+
+		if (device->gpiod[i] == ERR_PTR(-EBUSY))
+			dev_dbg(&device->spi->dev, "%s is busy.", name);
+
+		if ( IS_ERR(device->gpiod[i]) )
+		{
+			retval = PTR_ERR(device->gpiod[i]);
+			/* release already allocated gpios */
+			for (i--; i>=0; i--)
+			{
+				free_irq(device->irq_num[i], device);
+				gpiod_put(device->gpiod[i]);
+			}
+			return retval;
+		}
+
+
+		/* configure the pin */
+		gpiod_unexport(device->gpiod[i]);
+		retval = gpiod_direction_input(device->gpiod[i]);
+		if (retval) return retval;
+
+
+		/* configure irq */
+		device->irq_num[i] = gpiod_to_irq(device->gpiod[i]);
+		if (device->irq_num[i] < 0)
+		{
+			device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc *)device->irq_num[i];
+			return device->irq_num[i];
+		}
+		retval = request_irq(device->irq_num[i],
+				     DIO_irq_handler[i],
+				     0, /* flags */
+				     name,
+				     device);
+
+		if (retval)
+			return retval;
+
+		dev_dbg(&device->spi->dev, "%s succesfully configured", name);
+	}
+
+	return 0;
+}
+
+static void free_GPIOs(struct pi433_device *device)
+{
+	int i;
+
+	for (i=0; i<NUM_DIO; i++)
+	{
+		/* check if gpiod is valid */
+		if ( IS_ERR(device->gpiod[i]) )
+			continue;
+
+		free_irq(device->irq_num[i], device);
+		gpiod_put(device->gpiod[i]);
+	}
+	return;
+}
+
+static int pi433_get_minor(struct pi433_device *device)
+{
+	int retval = -ENOMEM;
+
+	mutex_lock(&minor_lock);
+	retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL);
+	if (retval >= 0) {
+		device->minor = retval;
+		retval = 0;
+	} else if (retval == -ENOSPC) {
+		dev_err(device->dev, "too many pi433 devices\n");
+		retval = -EINVAL;
+	}
+	mutex_unlock(&minor_lock);
+	return retval;
+}
+
+static void pi433_free_minor(struct pi433_device *dev)
+{
+	mutex_lock(&minor_lock);
+	idr_remove(&pi433_idr, dev->minor);
+	mutex_unlock(&minor_lock);
+}
+/*-------------------------------------------------------------------------*/
+
+static const struct file_operations pi433_fops = {
+	.owner =	THIS_MODULE,
+	/* REVISIT switch to aio primitives, so that userspace
+	 * gets more complete API coverage.  It'll simplify things
+	 * too, except for the locking.
+	 */
+	.write =	pi433_write,
+	.read =		pi433_read,
+	.unlocked_ioctl = pi433_ioctl,
+	.compat_ioctl = pi433_compat_ioctl,
+	.open =		pi433_open,
+	.release =	pi433_release,
+	.llseek =	no_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pi433_probe(struct spi_device *spi)
+{
+	struct pi433_device	*device;
+	int			retval;
+
+	/* setup spi parameters */
+	spi->mode = 0x00;
+	spi->bits_per_word = 8;
+	/* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay */
+
+	retval = spi_setup(spi);
+	if (retval)
+	{
+		dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
+		return retval;
+	}
+	else
+	{
+		dev_dbg(&spi->dev,
+			"spi interface setup: mode 0x%2x, %d bits per word, %dhz max speed",
+			spi->mode, spi->bits_per_word, spi->max_speed_hz);
+	}
+
+	/* Ping the chip by reading the version register */
+	retval = spi_w8r8(spi, 0x10);
+	if (retval < 0)
+		return retval;
+
+	switch(retval)
+	{
+		case 0x24:
+			dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
+			break;
+		default:
+			dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
+			return -ENODEV;
+	}
+
+	/* Allocate driver data */
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	/* Initialize the driver data */
+	device->spi = spi;
+	device->rx_active = false;
+	device->tx_active = false;
+	device->interrupt_rx_allowed = false;
+
+	/* init wait queues */
+	init_waitqueue_head(&device->tx_wait_queue);
+	init_waitqueue_head(&device->rx_wait_queue);
+	init_waitqueue_head(&device->fifo_wait_queue);
+
+	/* init fifo */
+	INIT_KFIFO(device->tx_fifo);
+
+	/* init mutexes and locks */
+	mutex_init(&device->tx_fifo_lock);
+	mutex_init(&device->rx_lock);
+
+	/* setup GPIO (including irq_handler) for the different DIOs */
+	retval = setup_GPIOs(device);
+	if (retval)
+	{
+		dev_dbg(&spi->dev, "setup of GPIOs failed");
+		goto GPIO_failed;
+	}
+
+	/* setup the radio module */
+	SET_CHECKED(rf69_set_mode		(spi, standby));
+	SET_CHECKED(rf69_set_data_mode		(spi, packet));
+	SET_CHECKED(rf69_set_amplifier_0	(spi, optionOn));
+	SET_CHECKED(rf69_set_amplifier_1	(spi, optionOff));
+	SET_CHECKED(rf69_set_amplifier_2	(spi, optionOff));
+	SET_CHECKED(rf69_set_output_power_level	(spi, 13));
+	SET_CHECKED(rf69_set_antenna_impedance	(spi, fiftyOhm));
+
+	/* start tx thread */
+	device->tx_task_struct = kthread_run(pi433_tx_thread,
+					     device,
+					     "pi433_tx_task");
+	if (device->tx_task_struct < 0)
+	{
+		dev_dbg(device->dev, "start of send thread failed");
+		goto send_thread_failed;
+	}
+
+	/* determ minor number */
+	retval = pi433_get_minor(device);
+	if (retval)
+	{
+		dev_dbg(device->dev, "get of minor number failed");
+		goto minor_failed;
+	}
+
+	/* create device */
+	device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
+	device->dev = device_create(pi433_class,
+				    &spi->dev,
+				    device->devt,
+				    device,
+				    "pi433");
+	if (IS_ERR(device->dev)) {
+		pr_err("pi433: device register failed\n");
+		retval = PTR_ERR(device->dev);
+		goto device_create_failed;
+	}
+	else {
+		dev_dbg(device->dev,
+			"created device for major %d, minor %d\n",
+			MAJOR(pi433_dev),
+			device->minor);
+	}
+
+	/* create cdev */
+	device->cdev = cdev_alloc();
+	device->cdev->owner = THIS_MODULE;
+	cdev_init(device->cdev, &pi433_fops);
+	retval = cdev_add(device->cdev, device->devt, 1);
+	if (retval)
+	{
+		dev_dbg(device->dev, "register of cdev failed");
+		goto cdev_failed;
+	}
+
+	/* spi setup */
+	spi_set_drvdata(spi, device);
+
+	return 0;
+
+cdev_failed:
+	device_destroy(pi433_class, device->devt);
+device_create_failed:
+	pi433_free_minor(device);
+minor_failed:
+	kthread_stop(device->tx_task_struct);
+send_thread_failed:
+	free_GPIOs(device);
+GPIO_failed:
+	kfree(device);
+
+	return retval;
+}
+
+static int pi433_remove(struct spi_device *spi)
+{
+	struct pi433_device	*device = spi_get_drvdata(spi);
+
+	/* free GPIOs */
+	free_GPIOs(device);
+
+	/* make sure ops on existing fds can abort cleanly */
+	device->spi = NULL;
+
+	kthread_stop(device->tx_task_struct);
+
+	device_destroy(pi433_class, device->devt);
+
+	cdev_del(device->cdev);
+
+	pi433_free_minor(device);
+
+	if (device->users == 0)
+		kfree(device);
+
+	return 0;
+}
+
+static const struct of_device_id pi433_dt_ids[] = {
+	{ .compatible = "Smarthome-Wolf,pi433" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, pi433_dt_ids);
+
+static struct spi_driver pi433_spi_driver = {
+	.driver = {
+		.name =		"pi433",
+		.owner =	THIS_MODULE,
+		.of_match_table = of_match_ptr(pi433_dt_ids),
+	},
+	.probe =	pi433_probe,
+	.remove =	pi433_remove,
+
+	/* NOTE:  suspend/resume methods are not necessary here.
+	 * We don't do anything except pass the requests to/from
+	 * the underlying controller.  The refrigerator handles
+	 * most issues; the controller driver handles the rest.
+	 */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init pi433_init(void)
+{
+	int status;
+
+	/* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't
+           work stable - risk of buffer overflow */
+	if (MAX_MSG_SIZE < FIFO_SIZE)
+		return -EINVAL;
+
+	/* Claim device numbers.  Then register a class
+	 * that will key udev/mdev to add/remove /dev nodes.  Last, register
+	 * Last, register the driver which manages those device numbers.
+	 */
+	status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/);
+	if (status < 0)
+		return status;
+
+	pi433_class = class_create(THIS_MODULE, "pi433");
+	if (IS_ERR(pi433_class))
+	{
+		unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+		return PTR_ERR(pi433_class);
+	}
+
+	status = spi_register_driver(&pi433_spi_driver);
+	if (status < 0)
+	{
+		class_destroy(pi433_class);
+		unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+	}
+
+	return status;
+}
+
+module_init(pi433_init);
+
+static void __exit pi433_exit(void)
+{
+	spi_unregister_driver(&pi433_spi_driver);
+	class_destroy(pi433_class);
+	unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
+}
+module_exit(pi433_exit);
+
+MODULE_AUTHOR("Marcus Wolf, <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>");
+MODULE_DESCRIPTION("Driver for Pi433");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:pi433");
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
new file mode 100644
index 0000000..e6ed3cd
--- /dev/null
+++ b/drivers/staging/pi433/pi433_if.h
@@ -0,0 +1,152 @@
+/*
+ * include/linux/TODO
+ *
+ * userspace interface for pi433 radio module
+ *
+ * Pi433 is a 433MHz radio module for the Raspberry Pi.
+ * It is based on the HopeRf Module RFM69CW. Therefore inside of this
+ * driver, you'll find an abstraction of the rf69 chip.
+ *
+ * If needed, this driver could be extended, to also support other
+ * devices, basing on HopeRfs rf69.
+ *
+ * The driver can also be extended, to support other modules of
+ * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ...
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PI433_H
+#define PI433_H
+
+#include <linux/types.h>
+#include "rf69_enum.h"
+
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL structs and commands */
+
+/**
+ * struct pi433_tx_config - describes the configuration of the radio module for sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_tx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_TX_CFG_IOCTL_NR 	0
+struct pi433_tx_cfg
+{
+	__u32			frequency;
+	__u16			bit_rate;
+	__u32			dev_frequency;
+	enum modulation		modulation;
+	enum modShaping		modShaping;
+
+	enum paRamp		pa_ramp;
+
+	enum txStartCondition	tx_start_condition;
+
+	__u16			repetitions;
+
+
+	/* packet format */
+	enum optionOnOff	enable_preamble;
+	enum optionOnOff	enable_sync;
+	enum optionOnOff	enable_length_byte;
+	enum optionOnOff	enable_address_byte;
+	enum optionOnOff	enable_crc;
+
+	__u16			preamble_length;
+	__u8			sync_length;
+	__u8			fixed_message_length;
+
+	__u8			sync_pattern[8];
+	__u8			address_byte;
+};
+
+
+/**
+ * struct pi433_rx_config - describes the configuration of the radio module for sending
+ * @frequency:
+ * @bit_rate:
+ * @modulation:
+ * @data_mode:
+ * @preamble_length:
+ * @sync_pattern:
+ * @tx_start_condition:
+ * @payload_length:
+ * @repetitions:
+ *
+ * ATTENTION:
+ * If the contents of 'pi433_rx_config' ever change
+ * incompatibly, then the ioctl number (see define below) must change
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+#define PI433_RX_CFG_IOCTL_NR 	1
+struct pi433_rx_cfg {
+	__u32			frequency;
+	__u16			bit_rate;
+	__u32			dev_frequency;
+
+	enum modulation		modulation;
+
+	__u8			rssi_threshold;
+	enum thresholdDecrement	thresholdDecrement;
+	enum antennaImpedance	antenna_impedance;
+	enum lnaGain		lna_gain;
+	enum mantisse		bw_mantisse;	/* normal: 0x50 */
+	__u8			bw_exponent;	/* during AFC: 0x8b */
+	enum dagc		dagc;
+
+
+
+	/* packet format */
+	enum optionOnOff	enable_sync;
+	enum optionOnOff	enable_length_byte;	  /* should be used in combination with sync, only */
+	enum addressFiltering	enable_address_filtering; /* operational with sync, only */
+	enum optionOnOff	enable_crc;		  /* only operational, if sync on and fixed length or length byte is used */
+
+	__u8			sync_length;
+	__u8			fixed_message_length;
+	__u32			bytes_to_drop;
+
+	__u8			sync_pattern[8];
+	__u8			node_address;
+	__u8			broadcast_address;
+};
+
+
+#define PI433_IOC_MAGIC			'r'
+
+#define PI433_IOC_RD_TX_CFG	_IOR(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)])
+#define PI433_IOC_WR_TX_CFG	_IOW(PI433_IOC_MAGIC, PI433_TX_CFG_IOCTL_NR, char[sizeof(struct pi433_tx_cfg)])
+
+#define PI433_IOC_RD_RX_CFG	_IOR(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)])
+#define PI433_IOC_WR_RX_CFG	_IOW(PI433_IOC_MAGIC, PI433_RX_CFG_IOCTL_NR, char[sizeof(struct pi433_rx_cfg)])
+
+#endif /* PI433_H */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
new file mode 100644
index 0000000..b6bc45b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.c
@@ -0,0 +1,982 @@
+/*
+ * abstraction of the spi interface of HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* enable prosa debug info */
+#undef DEBUG
+/* enable print of values on reg access */
+#undef DEBUG_VALUES
+/* enable print of values on fifo access */
+#undef DEBUG_FIFO_ACCESS
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include "rf69.h"
+#include "rf69_registers.h"
+
+#define F_OSC	  32000000 /* in Hz */
+#define FIFO_SIZE 66 	   /* in byte */
+
+/*-------------------------------------------------------------------------*/
+
+#define READ_REG(x)	rf69_read_reg (spi, x)
+#define WRITE_REG(x,y)	rf69_write_reg(spi, x, y)
+#define INVALID_PARAM \
+	{ \
+		dev_dbg(&spi->dev, "set: illegal input param"); \
+		return -EINVAL; \
+	}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: mode");
+	#endif
+
+	switch (mode){
+	case transmit:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_TRANSMIT);
+	case receive:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_RECEIVE);
+	case synthesizer: return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SYNTHESIZER);
+	case standby:	  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_STANDBY);
+	case mode_sleep:  return WRITE_REG(REG_OPMODE, (READ_REG(REG_OPMODE) & ~MASK_OPMODE_MODE) | OPMODE_MODE_SLEEP);
+	default:	  INVALID_PARAM;
+	}
+
+	// we are using packet mode, so this check is not really needed
+	// but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode
+	//while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
+
+}
+
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: data mode");
+	#endif
+
+	switch (dataMode) {
+	case packet:		return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_PACKET);
+	case continuous:	return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS);
+	case continuousNoSync:  return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODE) | DATAMODUL_MODE_CONTINUOUS_NOSYNC);
+	default:		INVALID_PARAM;
+	}
+}
+
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: modulation");
+	#endif
+
+	switch (modulation) {
+	case OOK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_OOK);
+	case FSK:   return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_TYPE) | DATAMODUL_MODULATION_TYPE_FSK);
+	default:    INVALID_PARAM;
+	}
+}
+
+enum modulation rf69_get_modulation(struct spi_device *spi)
+{
+	u8 currentValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: mode");
+	#endif
+
+	currentValue = READ_REG(REG_DATAMODUL);
+
+	switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE >> 3)  // TODO improvement: change 3 to define
+	{
+	case DATAMODUL_MODULATION_TYPE_OOK: return OOK;
+	case DATAMODUL_MODULATION_TYPE_FSK: return FSK;
+	default:			    return undefined;
+	}
+}
+
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: mod shaping");
+	#endif
+
+	if (rf69_get_modulation(spi) == FSK)
+	{
+		switch (modShaping) {
+		case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE);
+		case shaping1_0: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_1_0);
+		case shaping0_5: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_3);
+		case shaping0_3: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_0_5);
+		default:	 INVALID_PARAM;
+		}
+	}
+	else
+	{
+		switch (modShaping) {
+		case shapingOff: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_NONE);
+		case shapingBR:	 return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_BR);
+		case shaping2BR: return WRITE_REG(REG_DATAMODUL, (READ_REG(REG_DATAMODUL) & ~MASK_DATAMODUL_MODULATION_SHAPE) | DATAMODUL_MODULATION_SHAPE_2BR);
+		default:	 INVALID_PARAM;
+		}
+	}
+}
+
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+{
+	int retval;
+	u32 bitRate_min;
+	u32 bitRate_reg;
+	u8 msb;
+	u8 lsb;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: bit rate");
+	#endif
+
+	// check input value
+	bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
+	if (bitRate < bitRate_min)
+	{
+		dev_dbg(&spi->dev, "setBitRate: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculate reg settings
+	bitRate_reg = (F_OSC / bitRate);
+
+	msb = (bitRate_reg&0xff00)   >>  8;
+	lsb = (bitRate_reg&0xff);
+
+	// transmit to RF 69
+	retval = WRITE_REG(REG_BITRATE_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_BITRATE_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_deviation(struct spi_device *spi, u32 deviation)
+{
+	int retval;
+//	u32 f_max; TODO: Abhängigkeit von Bitrate beachten!!
+	u64 f_reg;
+	u64 f_step;
+	u8 msb;
+	u8 lsb;
+	u64 factor = 1000000; // to improve precision of calculation
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: deviation");
+	#endif
+
+	if (deviation < 600 || deviation > 500000) //TODO: Abhängigkeit von Bitrate beachten!!
+	{
+		dev_dbg(&spi->dev, "set_deviation: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculat f step
+	f_step = F_OSC * factor;
+	do_div(f_step, 524288); //  524288 = 2^19
+
+	// calculate register settings
+	f_reg = deviation * factor;
+	do_div(f_reg  , f_step);
+
+	msb = (f_reg&0xff00)   >>  8;
+	lsb = (f_reg&0xff);
+
+	// check msb
+	if (msb & !FDEVMASB_MASK)
+	{
+		dev_dbg(&spi->dev, "set_deviation: err in calc of msb");
+		INVALID_PARAM;
+	}
+
+	// write to chip
+	retval = WRITE_REG(REG_FDEV_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FDEV_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_frequency(struct spi_device *spi, u32 frequency)
+{
+	int retval;
+	u32 f_max;
+	u64 f_reg;
+	u64 f_step;
+	u8 msb;
+	u8 mid;
+	u8 lsb;
+	u64 factor = 1000000; // to improve precision of calculation
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: frequency");
+	#endif
+
+	// calculat f step
+	f_step = F_OSC * factor;
+	do_div(f_step, 524288); //  524288 = 2^19
+
+	// check input value
+	f_max = f_step * 8388608 / factor;
+	if (frequency > f_max)
+	{
+		dev_dbg(&spi->dev, "setFrequency: illegal input param");
+		INVALID_PARAM;
+	}
+
+	// calculate reg settings
+	f_reg = frequency * factor;
+	do_div(f_reg  , f_step);
+
+	msb = (f_reg&0xff0000) >> 16;
+	mid = (f_reg&0xff00)   >>  8;
+	lsb = (f_reg&0xff);
+
+	// write to chip
+	retval = WRITE_REG(REG_FRF_MSB, msb);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FRF_MID, mid);
+	if (retval)  return retval;
+	retval = WRITE_REG(REG_FRF_LSB, lsb);
+	if (retval)  return retval;
+
+	return 0;
+}
+
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #0");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA0) );
+	case optionOff:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA0) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #1");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA1) );
+	case optionOff: return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA1) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: amp #2");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) |  MASK_PALEVEL_PA2) );
+	case optionOff:	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_PA2) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: power level");
+	#endif
+
+	powerLevel +=18; // TODO Abhängigkeit von PA0,1,2 setting
+
+	// check input value
+	if (powerLevel > 0x1f)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_PALEVEL, (READ_REG(REG_PALEVEL) & ~MASK_PALEVEL_OUTPUT_POWER) | powerLevel);
+}
+
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: pa ramp");
+	#endif
+
+	switch(paRamp) {
+	case ramp3400:	return WRITE_REG(REG_PARAMP, PARAMP_3400);
+	case ramp2000:	return WRITE_REG(REG_PARAMP, PARAMP_2000);
+	case ramp1000:	return WRITE_REG(REG_PARAMP, PARAMP_1000);
+	case ramp500:	return WRITE_REG(REG_PARAMP, PARAMP_500);
+	case ramp250:	return WRITE_REG(REG_PARAMP, PARAMP_250);
+	case ramp125:	return WRITE_REG(REG_PARAMP, PARAMP_125);
+	case ramp100:	return WRITE_REG(REG_PARAMP, PARAMP_100);
+	case ramp62:	return WRITE_REG(REG_PARAMP, PARAMP_62);
+	case ramp50:	return WRITE_REG(REG_PARAMP, PARAMP_50);
+	case ramp40:	return WRITE_REG(REG_PARAMP, PARAMP_40);
+	case ramp31:	return WRITE_REG(REG_PARAMP, PARAMP_31);
+	case ramp25:	return WRITE_REG(REG_PARAMP, PARAMP_25);
+	case ramp20:	return WRITE_REG(REG_PARAMP, PARAMP_20);
+	case ramp15:	return WRITE_REG(REG_PARAMP, PARAMP_15);
+	case ramp12:	return WRITE_REG(REG_PARAMP, PARAMP_12);
+	case ramp10:	return WRITE_REG(REG_PARAMP, PARAMP_10);
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: antenna impedance");
+	#endif
+
+	switch(antennaImpedance) {
+	case fiftyOhm:	    return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) & ~MASK_LNA_ZIN) );
+	case twohundretOhm: return WRITE_REG(REG_LNA, (READ_REG(REG_LNA) |  MASK_LNA_ZIN) );
+	default:	    INVALID_PARAM;
+	}
+}
+
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: lna gain");
+	#endif
+
+	switch(lnaGain) {
+	case automatic:	 return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_AUTO) );
+	case max:	 return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX) );
+	case maxMinus6:  return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_6) );
+	case maxMinus12: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_12) );
+	case maxMinus24: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_24) );
+	case maxMinus36: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_36) );
+	case maxMinus48: return WRITE_REG(REG_LNA, ( (READ_REG(REG_LNA) & ~MASK_LNA_GAIN) & LNA_GAIN_MAX_MINUS_48) );
+	default:	 INVALID_PARAM;
+	}
+}
+
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi)
+{
+	u8 currentValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: lna gain");
+	#endif
+
+	currentValue = READ_REG(REG_LNA);
+
+	switch (currentValue & MASK_LNA_CURRENT_GAIN >> 3)  // improvement: change 3 to define
+	{
+	case LNA_GAIN_AUTO:	    return automatic;
+	case LNA_GAIN_MAX:	    return max;
+	case LNA_GAIN_MAX_MINUS_6:  return maxMinus6;
+	case LNA_GAIN_MAX_MINUS_12: return maxMinus12;
+	case LNA_GAIN_MAX_MINUS_24: return maxMinus24;
+	case LNA_GAIN_MAX_MINUS_36: return maxMinus36;
+	case LNA_GAIN_MAX_MINUS_48: return maxMinus48;
+	default:		    return undefined;
+	}
+}
+
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi ,u8 reg, enum dccPercent dccPercent)
+{
+	switch (dccPercent) {
+	case dcc16Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_16_PERCENT) );
+	case dcc8Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_8_PERCENT) );
+	case dcc4Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_4_PERCENT) );
+	case dcc2Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_2_PERCENT) );
+	case dcc1Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_1_PERCENT) );
+	case dcc0_5Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_5_PERCENT) );
+	case dcc0_25Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_25_PERCENT) );
+	case dcc0_125Percent:	return WRITE_REG(reg, ( (READ_REG(reg) & ~MASK_BW_DCC_FREQ) | BW_DCC_0_125_PERCENT) );
+	default:		INVALID_PARAM;
+	}
+}
+
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: cut off freq");
+	#endif
+
+	return rf69_set_dc_cut_off_frequency_intern(spi, REG_RXBW, dccPercent);
+}
+
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: cut off freq during afc");
+	#endif
+
+	return rf69_set_dc_cut_off_frequency_intern(spi, REG_AFCBW, dccPercent);
+}
+
+int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse mantisse, u8 exponent)
+{
+	u8 newValue;
+
+	// check value for mantisse and exponent
+	if (exponent > 7)   INVALID_PARAM;
+	if ( (mantisse!=mantisse16) &&
+	     (mantisse!=mantisse20) &&
+             (mantisse!=mantisse24) ) INVALID_PARAM;
+
+	// read old value
+	newValue = READ_REG(reg);
+
+	// "delete" mantisse and exponent = just keep the DCC setting
+	newValue = newValue & MASK_BW_DCC_FREQ;
+
+	// add new mantisse
+	switch(mantisse) {
+	case mantisse16: newValue = newValue | BW_MANT_16;	break;
+	case mantisse20: newValue = newValue | BW_MANT_20;	break;
+	case mantisse24: newValue = newValue | BW_MANT_24;	break;
+	}
+
+	// add new exponent
+	newValue = newValue | exponent;
+
+	// write back
+	return WRITE_REG(reg, newValue);
+}
+
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: band width");
+	#endif
+
+	return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent);
+}
+
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: band width during afc");
+	#endif
+
+	return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
+}
+
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold type");
+	#endif
+
+	switch (thresholdType)
+	{
+	case fixed:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_FIXED) );
+	case peak:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_PEAK) );
+	case average:	return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESTYPE) | OOKPEAK_THRESHTYPE_AVERAGE) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold step");
+	#endif
+
+	switch (thresholdStep) {
+	case step_0_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_0_5_DB) );
+	case step_1_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_0_DB) );
+	case step_1_5db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_1_5_DB) );
+	case step_2_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_2_0_DB) );
+	case step_3_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_3_0_DB) );
+	case step_4_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_4_0_DB) );
+	case step_5_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_5_0_DB) );
+	case step_6_0db: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESSTEP) | OOKPEAK_THRESHSTEP_6_0_DB) );
+	default:	 INVALID_PARAM;
+	}
+}
+
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: threshold decrement");
+	#endif
+
+	switch (thresholdDecrement) {
+	case dec_every8th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_8TH) );
+	case dec_every4th: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_4TH) );
+	case dec_every2nd: return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_EVERY_2ND) );
+	case dec_once:	   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_ONCE) );
+	case dec_twice:	   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_TWICE) );
+	case dec_4times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_4_TIMES) );
+	case dec_8times:   return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_8_TIMES) );
+	case dec_16times:  return WRITE_REG(REG_OOKPEAK, ( (READ_REG(REG_OOKPEAK) & ~MASK_OOKPEAK_THRESDEC) | OOKPEAK_THRESHDEC_16_TIMES) );
+	default:	   INVALID_PARAM;
+	}
+}
+
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+{
+	u8 mask;
+	u8 shift;
+	u8 regaddr;
+	u8 regValue;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: DIO mapping");
+	#endif
+
+	// check DIO number
+	if (DIONumber > 5) INVALID_PARAM;
+
+	switch (DIONumber) {
+	case 0: mask=MASK_DIO0; shift=SHIFT_DIO0; regaddr=REG_DIOMAPPING1; break;
+	case 1: mask=MASK_DIO1; shift=SHIFT_DIO1; regaddr=REG_DIOMAPPING1; break;
+	case 2: mask=MASK_DIO2; shift=SHIFT_DIO2; regaddr=REG_DIOMAPPING1; break;
+	case 3: mask=MASK_DIO3; shift=SHIFT_DIO3; regaddr=REG_DIOMAPPING1; break;
+	case 4: mask=MASK_DIO4; shift=SHIFT_DIO4; regaddr=REG_DIOMAPPING2; break;
+	case 5: mask=MASK_DIO5; shift=SHIFT_DIO5; regaddr=REG_DIOMAPPING2; break;
+	}
+
+	// read reg
+	regValue=READ_REG(regaddr);
+	// delete old value
+	regValue = regValue & ~mask;
+	// add new value
+	regValue = regValue | value << shift;
+	// write back
+	return WRITE_REG(regaddr,regValue);
+}
+
+bool rf69_get_flag(struct spi_device *spi, enum flag flag)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: flag");
+	#endif
+
+	switch(flag) {
+	case modeSwitchCompleted:     return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_MODE_READY);
+	case readyToReceive:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RX_READY);
+	case readyToSend:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TX_READY);
+	case pllLocked:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_PLL_LOCK);
+	case rssiExceededThreshold:   return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI);
+	case timeout:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_TIMEOUT);
+	case automode:		      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_AUTOMODE);
+	case syncAddressMatch:	      return (READ_REG(REG_IRQFLAGS1) & MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+	case fifoFull:		      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_FULL);
+/*	case fifoNotEmpty:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY); */
+	case fifoEmpty:		      return !(READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_NOT_EMPTY);
+	case fifoLevelBelowThreshold: return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_LEVEL);
+	case fifoOverrun:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_OVERRUN);
+	case packetSent:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PACKET_SENT);
+	case payloadReady:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_PAYLOAD_READY);
+	case crcOk:		      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_CRC_OK);
+	case batteryLow:	      return (READ_REG(REG_IRQFLAGS2) & MASK_IRQFLAGS2_LOW_BAT);
+	default:		      return false;
+	}
+}
+
+int rf69_reset_flag(struct spi_device *spi, enum flag flag)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "reset: flag");
+	#endif
+
+	switch(flag) {
+	case rssiExceededThreshold: return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_RSSI);
+	case syncAddressMatch:	    return WRITE_REG(REG_IRQFLAGS1, MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
+	case fifoOverrun:	    return WRITE_REG(REG_IRQFLAGS2, MASK_IRQFLAGS2_FIFO_OVERRUN);
+	default:		    INVALID_PARAM;
+	}
+}
+
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: rssi threshold");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RSSITHRESH, threshold);
+}
+
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: start timeout");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RXTIMEOUT1, timeout);
+}
+
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: rssi timeout");
+	#endif
+
+	/* no value check needed - u8 exactly matches register size */
+
+	return WRITE_REG(REG_RXTIMEOUT2, timeout);
+}
+
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+{
+	int retval;
+	u8 msb, lsb;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: preample length");
+	#endif
+
+	/* no value check needed - u16 exactly matches register size */
+
+	/* calculate reg settings */
+	msb = (preambleLength&0xff00)   >>  8;
+	lsb = (preambleLength&0xff);
+
+	/* transmit to chip */
+	retval = WRITE_REG(REG_PREAMBLE_MSB, msb);
+	if (retval) return retval;
+	retval = WRITE_REG(REG_PREAMBLE_LSB, lsb);
+
+	return retval;
+}
+
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync enable");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_SYNC_ON) );
+	case optionOff:	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_ON) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: fifo fill condition");
+	#endif
+
+	switch(fifoFillCondition) {
+	case always:		 return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) |  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+	case afterSyncInterrupt: return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_FIFO_FILL_CONDITION) );
+	default:		 INVALID_PARAM;
+	}
+}
+
+int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync size");
+	#endif
+
+	// check input value
+	if (syncSize > 0x07)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | (syncSize << 3) );
+}
+
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync tolerance");
+	#endif
+
+	// check input value
+	if (syncTolerance > 0x07)
+		INVALID_PARAM;
+
+	// write value
+	return WRITE_REG(REG_SYNC_CONFIG, (READ_REG(REG_SYNC_CONFIG) & ~MASK_SYNC_CONFIG_SYNC_SIZE) | syncTolerance);
+}
+
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+{
+	int retval = 0;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: sync values");
+	#endif
+
+	retval += WRITE_REG(REG_SYNCVALUE1, syncValues[0]);
+	retval += WRITE_REG(REG_SYNCVALUE2, syncValues[1]);
+	retval += WRITE_REG(REG_SYNCVALUE3, syncValues[2]);
+	retval += WRITE_REG(REG_SYNCVALUE4, syncValues[3]);
+	retval += WRITE_REG(REG_SYNCVALUE5, syncValues[4]);
+	retval += WRITE_REG(REG_SYNCVALUE6, syncValues[5]);
+	retval += WRITE_REG(REG_SYNCVALUE7, syncValues[6]);
+	retval += WRITE_REG(REG_SYNCVALUE8, syncValues[7]);
+
+	return retval;
+}
+
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat packetFormat)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: packet format");
+	#endif
+
+	switch(packetFormat) {
+	case packetLengthVar: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+	case packetLengthFix: return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE) );
+	default:	      INVALID_PARAM;
+	}
+}
+
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: crc enable");
+	#endif
+
+	switch(optionOnOff) {
+	case optionOn:	return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) |  MASK_PACKETCONFIG1_CRC_ON) );
+	case optionOff:	return WRITE_REG(REG_PACKETCONFIG1, (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_CRC_ON) );
+	default:	INVALID_PARAM;
+	}
+}
+
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: address filtering");
+	#endif
+
+	switch (addressFiltering) {
+	case filteringOff:	     return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_OFF) );
+	case nodeAddress:	     return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODE) );
+	case nodeOrBroadcastAddress: return WRITE_REG(REG_PACKETCONFIG1, ( (READ_REG(REG_PACKETCONFIG1) & ~MASK_PACKETCONFIG1_ADDRESSFILTERING) | PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST) );
+	default:		     INVALID_PARAM;
+	}
+}
+
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: payload length");
+	#endif
+
+	return WRITE_REG(REG_PAYLOAD_LENGTH, payloadLength);
+}
+
+u8  rf69_get_payload_length(struct spi_device *spi)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "get: payload length");
+	#endif
+
+	return (u8) READ_REG(REG_PAYLOAD_LENGTH);
+}
+
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: node address");
+	#endif
+
+	return WRITE_REG(REG_NODEADRS, nodeAddress);
+}
+
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: broadcast address");
+	#endif
+
+	return WRITE_REG(REG_BROADCASTADRS, broadcastAddress);
+}
+
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: start condition");
+	#endif
+
+	switch(txStartCondition) {
+	case fifoLevel:	   return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_TXSTART) );
+	case fifoNotEmpty: return WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) |  MASK_FIFO_THRESH_TXSTART) );
+	default:	   INVALID_PARAM;
+	}
+}
+
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
+{
+	int retval;
+
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: fifo threshold");
+	#endif
+
+	// check input value
+	if (threshold & 0x80)
+		INVALID_PARAM;
+
+	// write value
+	retval = WRITE_REG(REG_FIFO_THRESH, (READ_REG(REG_FIFO_THRESH) & ~MASK_FIFO_THRESH_VALUE) | threshold);
+	if (retval)
+		return retval;
+
+	// access the fifo to activate new threshold
+	return rf69_read_fifo (spi, (u8*) &retval, 1); // retval used as buffer
+}
+
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
+{
+	#ifdef DEBUG
+		dev_dbg(&spi->dev, "set: dagc");
+	#endif
+
+	switch(dagc) {
+	case normalMode:		 return WRITE_REG(REG_TESTDAGC, DAGC_NORMAL);
+	case improve:			 return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA0);
+	case improve4LowModulationIndex: return WRITE_REG(REG_TESTDAGC, DAGC_IMPROVED_LOWBETA1);
+	default:			 INVALID_PARAM;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+	#ifdef DEBUG_FIFO_ACCESS
+		int i;
+	#endif
+	struct spi_transfer transfer;
+	u8 local_buffer[FIFO_SIZE + 1];
+	int retval;
+
+	if (size > FIFO_SIZE)
+	{
+		#ifdef DEBUG
+			dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n");
+		#endif
+		return -EMSGSIZE;
+	}
+
+	/* prepare a bidirectional transfer */
+	local_buffer[0] = REG_FIFO;
+	memset(&transfer, 0, sizeof(transfer));
+  	transfer.tx_buf = local_buffer;
+  	transfer.rx_buf = local_buffer;
+	transfer.len	= size+1;
+
+	retval = spi_sync_transfer(spi, &transfer, 1);
+
+	#ifdef DEBUG_FIFO_ACCESS
+		for (i=0; i<size; i++)
+			dev_dbg(&spi->dev, "%d - 0x%x\n", i, local_buffer[i+1]);
+	#endif
+
+	memcpy(buffer, &local_buffer[1], size);  // TODO: ohne memcopy wäre schöner
+
+	return retval;
+}
+
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
+{
+	#ifdef DEBUG_FIFO_ACCESS
+		int i;
+	#endif
+	char spi_address = REG_FIFO | WRITE_BIT;
+	u8 local_buffer[FIFO_SIZE + 1];
+
+	if (size > FIFO_SIZE)
+	{
+		#ifdef DEBUG
+			dev_dbg(&spi->dev, "read fifo: passed in buffer bigger then internal buffer \n");
+		#endif
+		return -EMSGSIZE;
+	}
+
+	local_buffer[0] = spi_address;
+	memcpy(&local_buffer[1], buffer, size);  // TODO: ohne memcopy wäre schöner
+
+	#ifdef DEBUG_FIFO_ACCESS
+		for (i=0; i<size; i++)
+			dev_dbg(&spi->dev, "0x%x\n",buffer[i]);
+	#endif
+
+	return spi_write (spi, local_buffer, size + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+u8 rf69_read_reg(struct spi_device *spi, u8 addr)
+{
+	int retval;
+
+	retval = spi_w8r8(spi, addr);
+
+	#ifdef DEBUG_VALUES
+		if (retval < 0)
+			/* should never happen, since we already checked,
+			   that module is connected. Therefore no error
+			   handling, just an optional error message... */
+			dev_dbg(&spi->dev, "read 0x%x FAILED\n",
+				addr);
+		else
+			dev_dbg(&spi->dev, "read 0x%x from reg 0x%x\n",
+				retval,
+				addr);
+	#endif
+
+	return retval;
+}
+
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value)
+{
+	int retval;
+	char buffer[2];
+
+	buffer[0] = addr | WRITE_BIT;
+	buffer[1] = value;
+
+	retval = spi_write(spi, &buffer, 2);
+
+	#ifdef DEBUG_VALUES
+		if (retval < 0)
+			/* should never happen, since we already checked,
+			   that module is connected. Therefore no error
+			   handling, just an optional error message... */
+			dev_dbg(&spi->dev, "write 0x%x to 0x%x FAILED\n",
+				value,
+				addr);
+		else
+			dev_dbg(&spi->dev, "wrote 0x%x to reg 0x%x\n",
+				value,
+				addr);
+	#endif
+
+	return retval;
+}
+
+
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
new file mode 100644
index 0000000..6a6841b
--- /dev/null
+++ b/drivers/staging/pi433/rf69.h
@@ -0,0 +1,82 @@
+/*
+ * hardware abstraction/register access for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef RF69_H
+#define RF69_H
+
+#include "rf69_enum.h"
+#include "rf69_registers.h"
+
+#define F_OSC 		32000000  /* in Hz */
+#define FREQUENCY	433920000 /* in Hz, modifying this value impacts CE certification */
+#define FIFO_SIZE 	66        /* in byte */
+#define FIFO_THRESHOLD	15 	  /* in byte */
+
+int rf69_set_mode(struct spi_device *spi, enum mode mode);
+int rf69_set_data_mode(struct spi_device *spi, enum dataMode dataMode);
+int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
+enum modulation rf69_get_modulation(struct spi_device *spi);
+int rf69_set_modulation_shaping(struct spi_device *spi, enum modShaping modShaping);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_deviation(struct spi_device *spi, u32 deviation);
+int rf69_set_frequency(struct spi_device *spi, u32 frequency);
+int rf69_set_amplifier_0(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_1(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_amplifier_2(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+enum lnaGain rf69_get_lna_gain(struct spi_device *spi);
+int rf69_set_dc_cut_off_frequency_intern(struct spi_device *spi, u8 reg, enum dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency(struct spi_device *spi, enum dccPercent dccPercent);
+int rf69_set_dc_cut_off_frequency_during_afc(struct spi_device *spi, enum dccPercent dccPercent);
+int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
+int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
+int rf69_set_ook_threshold_type(struct spi_device *spi, enum thresholdType thresholdType);
+int rf69_set_ook_threshold_step(struct spi_device *spi, enum thresholdStep thresholdStep);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+bool rf69_get_flag(struct spi_device *spi, enum flag flag);
+int rf69_reset_flag(struct spi_device *spi, enum flag flag);
+int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_rx_start_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_rssi_timeout(struct spi_device *spi, u8 timeout);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_sync_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifoFillCondition fifoFillCondition);
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
+int rf69_set_sync_tolerance(struct spi_device *spi, u8 syncTolerance);
+int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_packet_format(struct spi_device * spi, enum packetFormat packetFormat);
+int rf69_set_crc_enable(struct spi_device *spi, enum optionOnOff optionOnOff);
+int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering);
+int rf69_set_payload_length(struct spi_device *spi, u8 payloadLength);
+u8  rf69_get_payload_length(struct spi_device *spi);
+int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition);
+int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
+int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
+
+int rf69_read_fifo (struct spi_device *spi, u8 *buffer, unsigned int size);
+int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size);
+
+u8  rf69_read_reg (struct spi_device *spi, u8 addr);
+int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value);
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_enum.h b/drivers/staging/pi433/rf69_enum.h
new file mode 100644
index 0000000..fbfb59b
--- /dev/null
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -0,0 +1,201 @@
+/*
+ * enumerations for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RF69_ENUM_H
+#define RF69_ENUM_H
+
+enum optionOnOff
+{
+    optionOff,
+    optionOn
+};
+
+enum mode
+{
+    mode_sleep,
+    standby,
+    synthesizer,
+    transmit,
+    receive
+};
+
+enum dataMode
+{
+    packet,
+    continuous,
+    continuousNoSync
+};
+
+enum modulation
+{
+    OOK,
+    FSK
+};
+
+enum modShaping
+{
+    shapingOff,
+    shaping1_0,
+    shaping0_5,
+    shaping0_3,
+    shapingBR,
+    shaping2BR
+};
+
+enum paRamp
+{
+    ramp3400,
+    ramp2000,
+    ramp1000,
+    ramp500,
+    ramp250,
+    ramp125,
+    ramp100,
+    ramp62,
+    ramp50,
+    ramp40,
+    ramp31,
+    ramp25,
+    ramp20,
+    ramp15,
+    ramp12,
+    ramp10
+};
+
+enum antennaImpedance
+{
+    fiftyOhm,
+    twohundretOhm
+};
+
+enum lnaGain
+{
+    automatic,
+    max,
+    maxMinus6,
+    maxMinus12,
+    maxMinus24,
+    maxMinus36,
+    maxMinus48,
+    undefined
+};
+
+enum dccPercent
+{
+    dcc16Percent,
+    dcc8Percent,
+    dcc4Percent,
+    dcc2Percent,
+    dcc1Percent,
+    dcc0_5Percent,
+    dcc0_25Percent,
+    dcc0_125Percent
+};
+
+enum mantisse
+{
+    mantisse16,
+    mantisse20,
+    mantisse24
+};
+
+enum thresholdType
+{
+    fixed,
+    peak,
+    average
+};
+
+enum thresholdStep
+{
+    step_0_5db,
+    step_1_0db,
+    step_1_5db,
+    step_2_0db,
+    step_3_0db,
+    step_4_0db,
+    step_5_0db,
+    step_6_0db
+};
+
+enum thresholdDecrement
+{
+    dec_every8th,
+    dec_every4th,
+    dec_every2nd,
+    dec_once,
+    dec_twice,
+    dec_4times,
+    dec_8times,
+    dec_16times
+};
+
+enum flag
+{
+    modeSwitchCompleted,
+    readyToReceive,
+    readyToSend,
+    pllLocked,
+    rssiExceededThreshold,
+    timeout,
+    automode,
+    syncAddressMatch,
+    fifoFull,
+//    fifoNotEmpty, collision with next enum; replaced by following enum...
+    fifoEmpty,
+    fifoLevelBelowThreshold,
+    fifoOverrun,
+    packetSent,
+    payloadReady,
+    crcOk,
+    batteryLow
+};
+
+enum fifoFillCondition
+{
+    afterSyncInterrupt,
+    always
+};
+
+enum packetFormat
+{
+    packetLengthFix,
+    packetLengthVar
+};
+
+enum txStartCondition
+{
+    fifoLevel,
+    fifoNotEmpty
+};
+
+enum addressFiltering
+{
+    filteringOff,
+    nodeAddress,
+    nodeOrBroadcastAddress
+};
+
+enum dagc
+{
+    normalMode,
+    improve,
+    improve4LowModulationIndex
+};
+
+
+#endif
diff --git a/drivers/staging/pi433/rf69_registers.h b/drivers/staging/pi433/rf69_registers.h
new file mode 100644
index 0000000..d0c4992
--- /dev/null
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -0,0 +1,489 @@
+/*
+ * register description for HopeRf rf69 radio module
+ *
+ * Copyright (C) 2016 Wolf-Entwicklungen
+ *	Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*******************************************/
+/* RF69 register addresses		   */
+/*******************************************/
+#define  REG_FIFO			0x00
+#define  REG_OPMODE			0x01
+#define  REG_DATAMODUL			0x02
+#define  REG_BITRATE_MSB		0x03
+#define  REG_BITRATE_LSB		0x04
+#define  REG_FDEV_MSB			0x05
+#define  REG_FDEV_LSB			0x06
+#define  REG_FRF_MSB			0x07
+#define  REG_FRF_MID			0x08
+#define  REG_FRF_LSB			0x09
+#define  REG_OSC1			0x0A
+#define  REG_AFCCTRL			0x0B
+#define  REG_LOWBAT			0x0C
+#define  REG_LISTEN1			0x0D
+#define  REG_LISTEN2			0x0E
+#define  REG_LISTEN3			0x0F
+#define  REG_VERSION			0x10
+#define  REG_PALEVEL			0x11
+#define  REG_PARAMP			0x12
+#define  REG_OCP			0x13
+#define  REG_AGCREF			0x14 /* not available on RF69 */
+#define  REG_AGCTHRESH1			0x15 /* not available on RF69 */
+#define  REG_AGCTHRESH2			0x16 /* not available on RF69 */
+#define  REG_AGCTHRESH3			0x17 /* not available on RF69 */
+#define  REG_LNA			0x18
+#define  REG_RXBW			0x19
+#define  REG_AFCBW			0x1A
+#define  REG_OOKPEAK			0x1B
+#define  REG_OOKAVG			0x1C
+#define  REG_OOKFIX			0x1D
+#define  REG_AFCFEI			0x1E
+#define  REG_AFCMSB			0x1F
+#define  REG_AFCLSB			0x20
+#define  REG_FEIMSB			0x21
+#define  REG_FEILSB			0x22
+#define  REG_RSSICONFIG			0x23
+#define  REG_RSSIVALUE			0x24
+#define  REG_DIOMAPPING1		0x25
+#define  REG_DIOMAPPING2		0x26
+#define  REG_IRQFLAGS1			0x27
+#define  REG_IRQFLAGS2			0x28
+#define  REG_RSSITHRESH			0x29
+#define  REG_RXTIMEOUT1			0x2A
+#define  REG_RXTIMEOUT2			0x2B
+#define  REG_PREAMBLE_MSB		0x2C
+#define  REG_PREAMBLE_LSB		0x2D
+#define  REG_SYNC_CONFIG		0x2E
+#define  REG_SYNCVALUE1			0x2F
+#define  REG_SYNCVALUE2			0x30
+#define  REG_SYNCVALUE3			0x31
+#define  REG_SYNCVALUE4			0x32
+#define  REG_SYNCVALUE5			0x33
+#define  REG_SYNCVALUE6			0x34
+#define  REG_SYNCVALUE7			0x35
+#define  REG_SYNCVALUE8			0x36
+#define  REG_PACKETCONFIG1		0x37
+#define  REG_PAYLOAD_LENGTH		0x38
+#define  REG_NODEADRS			0x39
+#define  REG_BROADCASTADRS		0x3A
+#define  REG_AUTOMODES			0x3B
+#define  REG_FIFO_THRESH		0x3C
+#define  REG_PACKETCONFIG2		0x3D
+#define  REG_AESKEY1			0x3E
+#define  REG_AESKEY2			0x3F
+#define  REG_AESKEY3			0x40
+#define  REG_AESKEY4			0x41
+#define  REG_AESKEY5			0x42
+#define  REG_AESKEY6			0x43
+#define  REG_AESKEY7			0x44
+#define  REG_AESKEY8			0x45
+#define  REG_AESKEY9			0x46
+#define  REG_AESKEY10			0x47
+#define  REG_AESKEY11			0x48
+#define  REG_AESKEY12			0x49
+#define  REG_AESKEY13			0x4A
+#define  REG_AESKEY14			0x4B
+#define  REG_AESKEY15			0x4C
+#define  REG_AESKEY16			0x4D
+#define  REG_TEMP1			0x4E
+#define  REG_TEMP2			0x4F
+#define  REG_TESTPA1			0x5A /* only present on RFM69HW */
+#define  REG_TESTPA2			0x5C /* only present on RFM69HW */
+#define  REG_TESTDAGC			0x6F
+
+/******************************************************/
+/* RF69/SX1231 bit definition				*/
+/******************************************************/
+/* write bit */
+#define WRITE_BIT				0x80
+
+/* RegOpMode */
+#define  MASK_OPMODE_SEQUENCER_OFF		0x80
+#define  MASK_OPMODE_LISTEN_ON			0x40
+#define  MASK_OPMODE_LISTEN_ABORT		0x20
+#define  MASK_OPMODE_MODE			0x1C
+
+#define  OPMODE_MODE_SLEEP			0x00
+#define  OPMODE_MODE_STANDBY			0x04 /* default */
+#define  OPMODE_MODE_SYNTHESIZER		0x08
+#define  OPMODE_MODE_TRANSMIT			0x0C
+#define  OPMODE_MODE_RECEIVE			0x10
+
+/* RegDataModul */
+#define  MASK_DATAMODUL_MODE			0x06
+#define  MASK_DATAMODUL_MODULATION_TYPE		0x18
+#define  MASK_DATAMODUL_MODULATION_SHAPE	0x03
+
+#define  DATAMODUL_MODE_PACKET			0x00 /* default */
+#define  DATAMODUL_MODE_CONTINUOUS		0x40
+#define  DATAMODUL_MODE_CONTINUOUS_NOSYNC	0x60
+
+#define  DATAMODUL_MODULATION_TYPE_FSK		0x00 /* default */
+#define  DATAMODUL_MODULATION_TYPE_OOK		0x08
+
+#define  DATAMODUL_MODULATION_SHAPE_NONE	0x00 /* default */
+#define  DATAMODUL_MODULATION_SHAPE_1_0		0x01
+#define  DATAMODUL_MODULATION_SHAPE_0_5		0x02
+#define  DATAMODUL_MODULATION_SHAPE_0_3		0x03
+#define  DATAMODUL_MODULATION_SHAPE_BR		0x01
+#define  DATAMODUL_MODULATION_SHAPE_2BR		0x02
+
+/* RegFDevMsb (0x05)*/
+#define FDEVMASB_MASK				0x3f
+
+/*
+// RegOsc1
+#define  OSC1_RCCAL_START			0x80
+#define  OSC1_RCCAL_DONE			0x40
+
+// RegLowBat
+#define  LOWBAT_MONITOR				0x10
+#define  LOWBAT_ON				0x08
+#define  LOWBAT_OFF				0x00  // Default
+
+#define  LOWBAT_TRIM_1695			0x00
+#define  LOWBAT_TRIM_1764			0x01
+#define  LOWBAT_TRIM_1835			0x02  // Default
+#define  LOWBAT_TRIM_1905			0x03
+#define  LOWBAT_TRIM_1976			0x04
+#define  LOWBAT_TRIM_2045			0x05
+#define  LOWBAT_TRIM_2116			0x06
+#define  LOWBAT_TRIM_2185			0x07
+
+
+// RegListen1
+#define  LISTEN1_RESOL_64			0x50
+#define  LISTEN1_RESOL_4100			0xA0  // Default
+#define  LISTEN1_RESOL_262000			0xF0
+
+#define  LISTEN1_CRITERIA_RSSI			0x00  // Default
+#define  LISTEN1_CRITERIA_RSSIANDSYNC		0x08
+
+#define  LISTEN1_END_00				0x00
+#define  LISTEN1_END_01				0x02  // Default
+#define  LISTEN1_END_10				0x04
+
+
+// RegListen2
+#define  LISTEN2_COEFIDLE_VALUE			0xF5 // Default
+
+// RegListen3
+#define  LISTEN3_COEFRX_VALUE			0x20 // Default
+*/
+
+// RegPaLevel
+#define  MASK_PALEVEL_PA0			0x80
+#define  MASK_PALEVEL_PA1			0x40
+#define  MASK_PALEVEL_PA2			0x20
+#define  MASK_PALEVEL_OUTPUT_POWER		0x1F
+
+
+
+// RegPaRamp
+#define  PARAMP_3400				0x00
+#define  PARAMP_2000				0x01
+#define  PARAMP_1000				0x02
+#define  PARAMP_500				0x03
+#define  PARAMP_250				0x04
+#define  PARAMP_125				0x05
+#define  PARAMP_100				0x06
+#define  PARAMP_62				0x07
+#define  PARAMP_50				0x08
+#define  PARAMP_40				0x09 /* default */
+#define  PARAMP_31				0x0A
+#define  PARAMP_25				0x0B
+#define  PARAMP_20				0x0C
+#define  PARAMP_15				0x0D
+#define  PARAMP_12				0x0E
+#define  PARAMP_10				0x0F
+
+#define  MASK_PARAMP				0x0F
+
+/*
+// RegOcp
+#define  OCP_OFF				0x0F
+#define  OCP_ON					0x1A  // Default
+
+#define  OCP_TRIM_45				0x00
+#define  OCP_TRIM_50				0x01
+#define  OCP_TRIM_55				0x02
+#define  OCP_TRIM_60				0x03
+#define  OCP_TRIM_65				0x04
+#define  OCP_TRIM_70				0x05
+#define  OCP_TRIM_75				0x06
+#define  OCP_TRIM_80				0x07
+#define  OCP_TRIM_85				0x08
+#define  OCP_TRIM_90				0x09
+#define  OCP_TRIM_95				0x0A
+#define  OCP_TRIM_100				0x0B  // Default
+#define  OCP_TRIM_105				0x0C
+#define  OCP_TRIM_110				0x0D
+#define  OCP_TRIM_115				0x0E
+#define  OCP_TRIM_120				0x0F
+*/
+
+/* RegLna (0x18) */
+#define  MASK_LNA_ZIN				0x80
+#define  MASK_LNA_CURRENT_GAIN			0x38
+#define  MASK_LNA_GAIN				0x07
+
+#define  LNA_GAIN_AUTO				0x00 /* default */
+#define  LNA_GAIN_MAX				0x01
+#define  LNA_GAIN_MAX_MINUS_6			0x02
+#define  LNA_GAIN_MAX_MINUS_12			0x03
+#define  LNA_GAIN_MAX_MINUS_24			0x04
+#define  LNA_GAIN_MAX_MINUS_36			0x05
+#define  LNA_GAIN_MAX_MINUS_48			0x06
+
+
+/* RegRxBw (0x19) and RegAfcBw (0x1A) */
+#define  MASK_BW_DCC_FREQ			0xE0
+#define  MASK_BW_MANTISSE			0x18
+#define  MASK_BW_EXPONENT			0x07
+
+#define  BW_DCC_16_PERCENT			0x00
+#define  BW_DCC_8_PERCENT			0x20
+#define  BW_DCC_4_PERCENT			0x40 /* default */
+#define  BW_DCC_2_PERCENT			0x60
+#define  BW_DCC_1_PERCENT			0x80
+#define  BW_DCC_0_5_PERCENT			0xA0
+#define  BW_DCC_0_25_PERCENT			0xC0
+#define  BW_DCC_0_125_PERCENT			0xE0
+
+#define  BW_MANT_16				0x00
+#define  BW_MANT_20				0x08
+#define  BW_MANT_24				0x10 /* default */
+
+
+/* RegOokPeak (0x1B) */
+#define  MASK_OOKPEAK_THRESTYPE			0xc0
+#define  MASK_OOKPEAK_THRESSTEP			0x38
+#define  MASK_OOKPEAK_THRESDEC			0x07
+
+#define  OOKPEAK_THRESHTYPE_FIXED		0x00
+#define  OOKPEAK_THRESHTYPE_PEAK		0x40 /* default */
+#define  OOKPEAK_THRESHTYPE_AVERAGE		0x80
+
+#define  OOKPEAK_THRESHSTEP_0_5_DB		0x00 /* default */
+#define  OOKPEAK_THRESHSTEP_1_0_DB		0x08
+#define  OOKPEAK_THRESHSTEP_1_5_DB		0x10
+#define  OOKPEAK_THRESHSTEP_2_0_DB		0x18
+#define  OOKPEAK_THRESHSTEP_3_0_DB		0x20
+#define  OOKPEAK_THRESHSTEP_4_0_DB		0x28
+#define  OOKPEAK_THRESHSTEP_5_0_DB		0x30
+#define  OOKPEAK_THRESHSTEP_6_0_DB		0x38
+
+#define  OOKPEAK_THRESHDEC_ONCE			0x00 /* default */
+#define  OOKPEAK_THRESHDEC_EVERY_2ND		0x01
+#define  OOKPEAK_THRESHDEC_EVERY_4TH		0x02
+#define  OOKPEAK_THRESHDEC_EVERY_8TH		0x03
+#define  OOKPEAK_THRESHDEC_TWICE		0x04
+#define  OOKPEAK_THRESHDEC_4_TIMES		0x05
+#define  OOKPEAK_THRESHDEC_8_TIMES		0x06
+#define  OOKPEAK_THRESHDEC_16_TIMES		0x07
+
+/*
+// RegOokAvg
+#define  OOKAVG_AVERAGETHRESHFILT_00		0x00
+#define  OOKAVG_AVERAGETHRESHFILT_01		0x40
+#define  OOKAVG_AVERAGETHRESHFILT_10		0x80  // Default
+#define  OOKAVG_AVERAGETHRESHFILT_11		0xC0
+
+
+// RegAfcFei
+#define  AFCFEI_FEI_DONE			0x40
+#define  AFCFEI_FEI_START			0x20
+#define  AFCFEI_AFC_DONE			0x10
+#define  AFCFEI_AFCAUTOCLEAR_ON			0x08
+#define  AFCFEI_AFCAUTOCLEAR_OFF		0x00  // Default
+
+#define  AFCFEI_AFCAUTO_ON			0x04
+#define  AFCFEI_AFCAUTO_OFF			0x00  // Default
+
+#define  AFCFEI_AFC_CLEAR			0x02
+#define  AFCFEI_AFC_START			0x01
+
+// RegRssiConfig
+#define  RSSI_FASTRX_ON				0x08
+#define  RSSI_FASTRX_OFF			0x00  // Default
+#define  RSSI_DONE				0x02
+#define  RSSI_START				0x01
+*/
+
+/* RegDioMapping1 */
+#define  MASK_DIO0				0xC0
+#define  MASK_DIO1				0x30
+#define  MASK_DIO2				0x0C
+#define  MASK_DIO3				0x03
+#define  SHIFT_DIO0				6
+#define  SHIFT_DIO1				4
+#define  SHIFT_DIO2				2
+#define  SHIFT_DIO3				0
+
+/* RegDioMapping2 */
+#define  MASK_DIO4				0xC0
+#define  MASK_DIO5				0x30
+#define  SHIFT_DIO4				6
+#define  SHIFT_DIO5				4
+
+/* DIO numbers */
+#define  DIO0					0
+#define  DIO1					1
+#define  DIO2					2
+#define  DIO3					3
+#define  DIO4					4
+#define  DIO5					5
+
+/* DIO Mapping values (packet mode) */
+#define  DIO_ModeReady_DIO4			0x00
+#define  DIO_ModeReady_DIO5			0x03
+#define  DIO_ClkOut				0x00
+#define  DIO_Data				0x01
+#define  DIO_TimeOut_DIO1			0x03
+#define  DIO_TimeOut_DIO4			0x00
+#define  DIO_Rssi_DIO0				0x03
+#define  DIO_Rssi_DIO3_4			0x01
+#define  DIO_RxReady				0x02
+#define  DIO_PLLLock				0x03
+#define  DIO_TxReady				0x01
+#define  DIO_FifoFull_DIO1			0x01
+#define  DIO_FifoFull_DIO3			0x00
+#define  DIO_SyncAddress			0x02
+#define  DIO_FifoNotEmpty_DIO1			0x02
+#define  DIO_FifoNotEmpty_FIO2			0x00
+#define  DIO_Automode				0x04
+#define  DIO_FifoLevel				0x00
+#define  DIO_CrcOk				0x00
+#define  DIO_PayloadReady			0x01
+#define  DIO_PacketSent				0x00
+#define  DIO_Dclk				0x00
+
+/* RegDioMapping2 CLK_OUT part */
+#define  MASK_DIOMAPPING2_CLK_OUT		0x07
+
+#define  DIOMAPPING2_CLK_OUT_NO_DIV		0x00
+#define  DIOMAPPING2_CLK_OUT_DIV_2		0x01
+#define  DIOMAPPING2_CLK_OUT_DIV_4		0x02
+#define  DIOMAPPING2_CLK_OUT_DIV_8		0x03
+#define  DIOMAPPING2_CLK_OUT_DIV_16		0x04
+#define  DIOMAPPING2_CLK_OUT_DIV_32		0x05
+#define  DIOMAPPING2_CLK_OUT_RC			0x06
+#define  DIOMAPPING2_CLK_OUT_OFF		0x07 /* default */
+
+/* RegIrqFlags1 */
+#define  MASK_IRQFLAGS1_MODE_READY		0x80
+#define  MASK_IRQFLAGS1_RX_READY		0x40
+#define  MASK_IRQFLAGS1_TX_READY		0x20
+#define  MASK_IRQFLAGS1_PLL_LOCK		0x10
+#define  MASK_IRQFLAGS1_RSSI			0x08
+#define  MASK_IRQFLAGS1_TIMEOUT			0x04
+#define  MASK_IRQFLAGS1_AUTOMODE		0x02
+#define  MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH	0x01
+
+/* RegIrqFlags2 */
+#define  MASK_IRQFLAGS2_FIFO_FULL		0x80
+#define  MASK_IRQFLAGS2_FIFO_NOT_EMPTY		0x40
+#define  MASK_IRQFLAGS2_FIFO_LEVEL		0x20
+#define  MASK_IRQFLAGS2_FIFO_OVERRUN		0x10
+#define  MASK_IRQFLAGS2_PACKET_SENT		0x08
+#define  MASK_IRQFLAGS2_PAYLOAD_READY		0x04
+#define  MASK_IRQFLAGS2_CRC_OK			0x02
+#define  MASK_IRQFLAGS2_LOW_BAT			0x01
+
+/* RegSyncConfig */
+#define  MASK_SYNC_CONFIG_SYNC_ON		0x80 /* default */
+#define  MASK_SYNC_CONFIG_FIFO_FILL_CONDITION	0x40
+#define  MASK_SYNC_CONFIG_SYNC_SIZE		0x38
+#define  MASK_SYNC_CONFIG_SYNC_TOLERANCE	0x07
+
+/* RegPacketConfig1 */
+#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE	0x80
+#define  MASK_PACKETCONFIG1_DCFREE			0x60
+#define  MASK_PACKETCONFIG1_CRC_ON			0x10 /* default */
+#define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF		0x08
+#define  MASK_PACKETCONFIG1_ADDRESSFILTERING		0x06
+
+#define  PACKETCONFIG1_DCFREE_OFF			0x00 /* default */
+#define  PACKETCONFIG1_DCFREE_MANCHESTER		0x20
+#define  PACKETCONFIG1_DCFREE_WHITENING			0x40
+#define  PACKETCONFIG1_ADDRESSFILTERING_OFF		0x00 /* default */
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODE		0x02
+#define  PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST	0x04
+
+/*
+// RegAutoModes
+#define  AUTOMODES_ENTER_OFF			0x00  // Default
+#define  AUTOMODES_ENTER_FIFONOTEMPTY		0x20
+#define  AUTOMODES_ENTER_FIFOLEVEL		0x40
+#define  AUTOMODES_ENTER_CRCOK			0x60
+#define  AUTOMODES_ENTER_PAYLOADREADY		0x80
+#define  AUTOMODES_ENTER_SYNCADRSMATCH		0xA0
+#define  AUTOMODES_ENTER_PACKETSENT		0xC0
+#define  AUTOMODES_ENTER_FIFOEMPTY		0xE0
+
+#define  AUTOMODES_EXIT_OFF			0x00  // Default
+#define  AUTOMODES_EXIT_FIFOEMPTY		0x04
+#define  AUTOMODES_EXIT_FIFOLEVEL		0x08
+#define  AUTOMODES_EXIT_CRCOK			0x0C
+#define  AUTOMODES_EXIT_PAYLOADREADY		0x10
+#define  AUTOMODES_EXIT_SYNCADRSMATCH		0x14
+#define  AUTOMODES_EXIT_PACKETSENT		0x18
+#define  AUTOMODES_EXIT_RXTIMEOUT		0x1C
+
+#define  AUTOMODES_INTERMEDIATE_SLEEP		0x00  // Default
+#define  AUTOMODES_INTERMEDIATE_STANDBY		0x01
+#define  AUTOMODES_INTERMEDIATE_RECEIVER	0x02
+#define  AUTOMODES_INTERMEDIATE_TRANSMITTER	0x03
+
+*/
+/* RegFifoThresh (0x3c) */
+#define  MASK_FIFO_THRESH_TXSTART		0x80
+#define  MASK_FIFO_THRESH_VALUE			0x7F
+
+/*
+
+// RegPacketConfig2
+#define  PACKET2_RXRESTARTDELAY_1BIT		0x00  // Default
+#define  PACKET2_RXRESTARTDELAY_2BITS		0x10
+#define  PACKET2_RXRESTARTDELAY_4BITS		0x20
+#define  PACKET2_RXRESTARTDELAY_8BITS		0x30
+#define  PACKET2_RXRESTARTDELAY_16BITS		0x40
+#define  PACKET2_RXRESTARTDELAY_32BITS		0x50
+#define  PACKET2_RXRESTARTDELAY_64BITS		0x60
+#define  PACKET2_RXRESTARTDELAY_128BITS		0x70
+#define  PACKET2_RXRESTARTDELAY_256BITS		0x80
+#define  PACKET2_RXRESTARTDELAY_512BITS		0x90
+#define  PACKET2_RXRESTARTDELAY_1024BITS	0xA0
+#define  PACKET2_RXRESTARTDELAY_2048BITS	0xB0
+#define  PACKET2_RXRESTARTDELAY_NONE		0xC0
+#define  PACKET2_RXRESTART			0x04
+
+#define  PACKET2_AUTORXRESTART_ON		0x02  // Default
+#define  PACKET2_AUTORXRESTART_OFF		0x00
+
+#define  PACKET2_AES_ON				0x01
+#define  PACKET2_AES_OFF			0x00  // Default
+
+
+// RegTemp1
+#define  TEMP1_MEAS_START			0x08
+#define  TEMP1_MEAS_RUNNING			0x04
+#define  TEMP1_ADCLOWPOWER_ON			0x01  // Default
+#define  TEMP1_ADCLOWPOWER_OFF			0x00
+*/
+
+// RegTestDagc (0x6F)
+#define  DAGC_NORMAL				0x00 /* Reset value */
+#define  DAGC_IMPROVED_LOWBETA1			0x20
+#define  DAGC_IMPROVED_LOWBETA0			0x30 /* Recommended val */
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-16 10:15                           ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-16 10:15 UTC (permalink / raw)
  To: Wolf Entwicklungen; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

On Sun, Jul 16, 2017 at 11:52:32AM +0200, Wolf Entwicklungen wrote:
> From: Marcus Wolf <linux@Wolf-Entwicklungen.de>
> Date: Tue,16 Jul 2017 11:52:06 +0100
> Subject: [PATCH 1/1] drivers/staging/pi433: New driver

Why is this all here in the patch body?  Usually git will strip this
out, but in the future, please don't put it here.

I'll try to queue this up in a few days and let's see what breaks :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-16 10:15                           ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-16 10:15 UTC (permalink / raw)
  To: Wolf Entwicklungen
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Sun, Jul 16, 2017 at 11:52:32AM +0200, Wolf Entwicklungen wrote:
> From: Marcus Wolf <linux-79IPTMiko8heq5RAq1AYSxS11BummzK+@public.gmane.org>
> Date: Tue,16 Jul 2017 11:52:06 +0100
> Subject: [PATCH 1/1] drivers/staging/pi433: New driver

Why is this all here in the patch body?  Usually git will strip this
out, but in the future, please don't put it here.

I'll try to queue this up in a few days and let's see what breaks :)

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-16 13:53                             ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-16 13:53 UTC (permalink / raw)
  To: Greg KH; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

Hi Greg,
 
like I wrote before - unfortunally I couldn't find a git command, squashing
all my commits into one single patch. Therfore I copy and pasted the patch
manually.
 
Never the less, the first three rows were copied from a patch, originally
generated by git.
 
I used
git format-patch master --stdout -p > pi433_patch
for the first rows
and
git diff master > pi433_patch
fot the dif/patch itself.

If someone could help me with better git commands, I would be happy :-)
 
Thanks a lot,
 
Marcus

> Greg KH <gregkh@linuxfoundation.org> hat am 16. Juli 2017 um 12:15
> geschrieben:
>
>
> On Sun, Jul 16, 2017 at 11:52:32AM +0200, Wolf Entwicklungen wrote:
> > From: Marcus Wolf <linux@Wolf-Entwicklungen.de>
> > Date: Tue,16 Jul 2017 11:52:06 +0100
> > Subject: [PATCH 1/1] drivers/staging/pi433: New driver
>
> Why is this all here in the patch body? Usually git will strip this
> out, but in the future, please don't put it here.
>
> I'll try to queue this up in a few days and let's see what breaks :)
>
> thanks,
>
> greg k-h
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-16 13:53                             ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-16 13:53 UTC (permalink / raw)
  To: Greg KH
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Greg,
 
like I wrote before - unfortunally I couldn't find a git command, squashing
all my commits into one single patch. Therfore I copy and pasted the patch
manually.
 
Never the less, the first three rows were copied from a patch, originally
generated by git.
 
I used
git format-patch master --stdout -p > pi433_patch
for the first rows
and
git diff master > pi433_patch
fot the dif/patch itself.

If someone could help me with better git commands, I would be happy :-)
 
Thanks a lot,
 
Marcus

> Greg KH <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org> hat am 16. Juli 2017 um 12:15
> geschrieben:
>
>
> On Sun, Jul 16, 2017 at 11:52:32AM +0200, Wolf Entwicklungen wrote:
> > From: Marcus Wolf <linux-79IPTMiko8heq5RAq1AYSxS11BummzK+@public.gmane.org>
> > Date: Tue,16 Jul 2017 11:52:06 +0100
> > Subject: [PATCH 1/1] drivers/staging/pi433: New driver
>
> Why is this all here in the patch body? Usually git will strip this
> out, but in the future, please don't put it here.
>
> I'll try to queue this up in a few days and let's see what breaks :)
>
> thanks,
>
> greg k-h
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
  2017-07-16 13:53                             ` Marcus Wolf
@ 2017-07-16 14:47                               ` Greg KH
  -1 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-16 14:47 UTC (permalink / raw)
  To: Marcus Wolf; +Cc: robh+dt, linux-kernel, devel, grant.likely, devicetree

On Sun, Jul 16, 2017 at 03:53:57PM +0200, Marcus Wolf wrote:
> Hi Greg,
>  
> like I wrote before - unfortunally I couldn't find a git command, squashing
> all my commits into one single patch. Therfore I copy and pasted the patch
> manually.

git diff FIRST_PATCH..HEAD > my.patch

will do it.

> Never the less, the first three rows were copied from a patch, originally
> generated by git.
>  
> I used
> git format-patch master --stdout -p > pi433_patch
> for the first rows
> and
> git diff master > pi433_patch
> fot the dif/patch itself.
> 
> If someone could help me with better git commands, I would be happy :-)


The issue is that the header was in the email body, if you use git
send-email, it should not show up.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-16 14:47                               ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-16 14:47 UTC (permalink / raw)
  To: Marcus Wolf; +Cc: devel, grant.likely, robh+dt, linux-kernel, devicetree

On Sun, Jul 16, 2017 at 03:53:57PM +0200, Marcus Wolf wrote:
> Hi Greg,
>  
> like I wrote before - unfortunally I couldn't find a git command, squashing
> all my commits into one single patch. Therfore I copy and pasted the patch
> manually.

git diff FIRST_PATCH..HEAD > my.patch

will do it.

> Never the less, the first three rows were copied from a patch, originally
> generated by git.
>  
> I used
> git format-patch master --stdout -p > pi433_patch
> for the first rows
> and
> git diff master > pi433_patch
> fot the dif/patch itself.
> 
> If someone could help me with better git commands, I would be happy :-)


The issue is that the header was in the email body, if you use git
send-email, it should not show up.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
  2017-07-16  9:52                         ` Wolf Entwicklungen
  (?)
  (?)
@ 2017-07-17  6:18                         ` kbuild test robot
  -1 siblings, 0 replies; 49+ messages in thread
From: kbuild test robot @ 2017-07-17  6:18 UTC (permalink / raw)
  To: Wolf Entwicklungen
  Cc: kbuild-all, Greg KH, robh+dt, linux-kernel, devel, grant.likely,
	devicetree

Hi Marcus,

[auto build test WARNING on staging/staging-testing]
[also build test WARNING on v4.13-rc1 next-20170714]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Wolf-Entwicklungen/drivers-staging-pi433-New-driver/20170716-181617
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

   include/linux/compiler.h:260:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/staging/pi433/pi433_if.c:1155:36: sparse: incompatible types for operation (<)
   drivers/staging/pi433/pi433_if.c:1155:36:    left side has type struct task_struct *tx_task_struct
   drivers/staging/pi433/pi433_if.c:1155:36:    right side has type int

vim +1155 drivers/staging/pi433/pi433_if.c

  1072	
  1073	static int pi433_probe(struct spi_device *spi)
  1074	{
  1075		struct pi433_device	*device;
  1076		int			retval;
  1077	
  1078		/* setup spi parameters */
  1079		spi->mode = 0x00;
  1080		spi->bits_per_word = 8;
  1081		/* spi->max_speed_hz = 10000000;  1MHz already set by device tree overlay */
  1082	
  1083		retval = spi_setup(spi);
  1084		if (retval)
  1085		{
  1086			dev_dbg(&spi->dev, "configuration of SPI interface failed!\n");
  1087			return retval;
  1088		}
  1089		else
  1090		{
  1091			dev_dbg(&spi->dev,
  1092				"spi interface setup: mode 0x%2x, %d bits per word, %dhz max speed",
  1093				spi->mode, spi->bits_per_word, spi->max_speed_hz);
  1094		}
  1095	
  1096		/* Ping the chip by reading the version register */
  1097		retval = spi_w8r8(spi, 0x10);
  1098		if (retval < 0)
  1099			return retval;
  1100	
  1101		switch(retval)
  1102		{
  1103			case 0x24:
  1104				dev_dbg(&spi->dev, "fonud pi433 (ver. 0x%x)", retval);
  1105				break;
  1106			default:
  1107				dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval);
  1108				return -ENODEV;
  1109		}
  1110	
  1111		/* Allocate driver data */
  1112		device = kzalloc(sizeof(*device), GFP_KERNEL);
  1113		if (!device)
  1114			return -ENOMEM;
  1115	
  1116		/* Initialize the driver data */
  1117		device->spi = spi;
  1118		device->rx_active = false;
  1119		device->tx_active = false;
  1120		device->interrupt_rx_allowed = false;
  1121	
  1122		/* init wait queues */
  1123		init_waitqueue_head(&device->tx_wait_queue);
  1124		init_waitqueue_head(&device->rx_wait_queue);
  1125		init_waitqueue_head(&device->fifo_wait_queue);
  1126	
  1127		/* init fifo */
  1128		INIT_KFIFO(device->tx_fifo);
  1129	
  1130		/* init mutexes and locks */
  1131		mutex_init(&device->tx_fifo_lock);
  1132		mutex_init(&device->rx_lock);
  1133	
  1134		/* setup GPIO (including irq_handler) for the different DIOs */
  1135		retval = setup_GPIOs(device);
  1136		if (retval)
  1137		{
  1138			dev_dbg(&spi->dev, "setup of GPIOs failed");
  1139			goto GPIO_failed;
  1140		}
  1141	
  1142		/* setup the radio module */
  1143		SET_CHECKED(rf69_set_mode		(spi, standby));
  1144		SET_CHECKED(rf69_set_data_mode		(spi, packet));
  1145		SET_CHECKED(rf69_set_amplifier_0	(spi, optionOn));
  1146		SET_CHECKED(rf69_set_amplifier_1	(spi, optionOff));
  1147		SET_CHECKED(rf69_set_amplifier_2	(spi, optionOff));
  1148		SET_CHECKED(rf69_set_output_power_level	(spi, 13));
  1149		SET_CHECKED(rf69_set_antenna_impedance	(spi, fiftyOhm));
  1150	
  1151		/* start tx thread */
  1152		device->tx_task_struct = kthread_run(pi433_tx_thread,
  1153						     device,
  1154						     "pi433_tx_task");
> 1155		if (device->tx_task_struct < 0)
  1156		{
  1157			dev_dbg(device->dev, "start of send thread failed");
  1158			goto send_thread_failed;
  1159		}
  1160	
  1161		/* determ minor number */
  1162		retval = pi433_get_minor(device);
  1163		if (retval)
  1164		{
  1165			dev_dbg(device->dev, "get of minor number failed");
  1166			goto minor_failed;
  1167		}
  1168	
  1169		/* create device */
  1170		device->devt = MKDEV(MAJOR(pi433_dev), device->minor);
  1171		device->dev = device_create(pi433_class,
  1172					    &spi->dev,
  1173					    device->devt,
  1174					    device,
  1175					    "pi433");
  1176		if (IS_ERR(device->dev)) {
  1177			pr_err("pi433: device register failed\n");
  1178			retval = PTR_ERR(device->dev);
  1179			goto device_create_failed;
  1180		}
  1181		else {
  1182			dev_dbg(device->dev,
  1183				"created device for major %d, minor %d\n",
  1184				MAJOR(pi433_dev),
  1185				device->minor);
  1186		}
  1187	
  1188		/* create cdev */
  1189		device->cdev = cdev_alloc();
  1190		device->cdev->owner = THIS_MODULE;
  1191		cdev_init(device->cdev, &pi433_fops);
  1192		retval = cdev_add(device->cdev, device->devt, 1);
  1193		if (retval)
  1194		{
  1195			dev_dbg(device->dev, "register of cdev failed");
  1196			goto cdev_failed;
  1197		}
  1198	
  1199		/* spi setup */
  1200		spi_set_drvdata(spi, device);
  1201	
  1202		return 0;
  1203	
  1204	cdev_failed:
  1205		device_destroy(pi433_class, device->devt);
  1206	device_create_failed:
  1207		pi433_free_minor(device);
  1208	minor_failed:
  1209		kthread_stop(device->tx_task_struct);
  1210	send_thread_failed:
  1211		free_GPIOs(device);
  1212	GPIO_failed:
  1213		kfree(device);
  1214	
  1215		return retval;
  1216	}
  1217	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-17 13:26                           ` kbuild test robot
  0 siblings, 0 replies; 49+ messages in thread
From: kbuild test robot @ 2017-07-17 13:26 UTC (permalink / raw)
  To: Wolf Entwicklungen
  Cc: kbuild-all, Greg KH, robh+dt, linux-kernel, devel, grant.likely,
	devicetree

[-- Attachment #1: Type: text/plain, Size: 981 bytes --]

Hi Marcus,

[auto build test ERROR on staging/staging-testing]
[also build test ERROR on v4.13-rc1 next-20170717]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Wolf-Entwicklungen/drivers-staging-pi433-New-driver/20170716-181617
config: m68k-allyesconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=m68k 

All errors (new ones prefixed by >>):

   drivers/staging/pi433/rf69.o: In function `rf69_set_frequency':
>> rf69.c:(.text+0x9e2): undefined reference to `__udivdi3'

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 43822 bytes --]

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-17 13:26                           ` kbuild test robot
  0 siblings, 0 replies; 49+ messages in thread
From: kbuild test robot @ 2017-07-17 13:26 UTC (permalink / raw)
  To: Wolf Entwicklungen
  Cc: kbuild-all-JC7UmRfGjtg, Greg KH, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 981 bytes --]

Hi Marcus,

[auto build test ERROR on staging/staging-testing]
[also build test ERROR on v4.13-rc1 next-20170717]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Wolf-Entwicklungen/drivers-staging-pi433-New-driver/20170716-181617
config: m68k-allyesconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=m68k 

All errors (new ones prefixed by >>):

   drivers/staging/pi433/rf69.o: In function `rf69_set_frequency':
>> rf69.c:(.text+0x9e2): undefined reference to `__udivdi3'

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 43822 bytes --]

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-20 11:23                             ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-20 11:23 UTC (permalink / raw)
  To: Greg KH
  Cc: kbuild-all, robh+dt, linux-kernel, devel, grant.likely,
	devicetree, kbuild test robot

Hi Greg,

below you can see the report with the error on m68k. It was sent to me from a
test robot of intel.

According to my research, this problem occured, because there is no hardware
support for floating point on the m68k (or it was configured not to use it).
Therefore gcc uses an internal function, provided by libgcc. Obviously libgcc
wasn't linked...

I don't know how to come arround this problem by modifying my code (except
reducing the accuracy of the calculation by not using floating point).

Can we ignore the error or can I do something else?
Maybe a special include just in case of m68k can help??!?
I don't have an environment for building m68k.

Cheers,

Marcus

> kbuild test robot <lkp@intel.com> hat am 17. Juli 2017 um 15:26 geschrieben:
>
>
> Hi Marcus,
>
> [auto build test ERROR on staging/staging-testing]
> [also build test ERROR on v4.13-rc1 next-20170717]
> [if your patch is applied to the wrong git tree, please drop us a note to help
> improve the system]
>
> url:
> https://github.com/0day-ci/linux/commits/Wolf-Entwicklungen/drivers-staging-pi433-New-driver/20170716-181617
> config: m68k-allyesconfig (attached as .config)
> compiler: m68k-linux-gcc (GCC) 4.9.0
> reproduce:
> wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross
> -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=m68k
>
> All errors (new ones prefixed by >>):
>
> drivers/staging/pi433/rf69.o: In function `rf69_set_frequency':
> >> rf69.c:(.text+0x9e2): undefined reference to `__udivdi3'
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-20 11:23                             ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-20 11:23 UTC (permalink / raw)
  To: Greg KH
  Cc: kbuild-all-JC7UmRfGjtg, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA, kbuild test robot

Hi Greg,

below you can see the report with the error on m68k. It was sent to me from a
test robot of intel.

According to my research, this problem occured, because there is no hardware
support for floating point on the m68k (or it was configured not to use it).
Therefore gcc uses an internal function, provided by libgcc. Obviously libgcc
wasn't linked...

I don't know how to come arround this problem by modifying my code (except
reducing the accuracy of the calculation by not using floating point).

Can we ignore the error or can I do something else?
Maybe a special include just in case of m68k can help??!?
I don't have an environment for building m68k.

Cheers,

Marcus

> kbuild test robot <lkp-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> hat am 17. Juli 2017 um 15:26 geschrieben:
>
>
> Hi Marcus,
>
> [auto build test ERROR on staging/staging-testing]
> [also build test ERROR on v4.13-rc1 next-20170717]
> [if your patch is applied to the wrong git tree, please drop us a note to help
> improve the system]
>
> url:
> https://github.com/0day-ci/linux/commits/Wolf-Entwicklungen/drivers-staging-pi433-New-driver/20170716-181617
> config: m68k-allyesconfig (attached as .config)
> compiler: m68k-linux-gcc (GCC) 4.9.0
> reproduce:
> wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross
> -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=m68k
>
> All errors (new ones prefixed by >>):
>
> drivers/staging/pi433/rf69.o: In function `rf69_set_frequency':
> >> rf69.c:(.text+0x9e2): undefined reference to `__udivdi3'
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
  2017-07-20 11:23                             ` Marcus Wolf
  (?)
@ 2017-07-20 11:31                             ` Greg KH
  -1 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-20 11:31 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: devel, devicetree, linux-kernel, robh+dt, kbuild-all, grant.likely

On Thu, Jul 20, 2017 at 01:23:05PM +0200, Marcus Wolf wrote:
> Hi Greg,
> 
> below you can see the report with the error on m68k. It was sent to me from a
> test robot of intel.
> 
> According to my research, this problem occured, because there is no hardware
> support for floating point on the m68k (or it was configured not to use it).
> Therefore gcc uses an internal function, provided by libgcc. Obviously libgcc
> wasn't linked...
> 
> I don't know how to come arround this problem by modifying my code (except
> reducing the accuracy of the calculation by not using floating point).
> 
> Can we ignore the error or can I do something else?
> Maybe a special include just in case of m68k can help??!?
> I don't have an environment for building m68k.

It looks like a 64bit issue, try wrapping your division in that function
with a call to do_div() like you do elsewhere in that function.  That
should solve the issue.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
  2017-07-20 11:23                             ` Marcus Wolf
@ 2017-07-20 11:37                               ` Dan Carpenter
  -1 siblings, 0 replies; 49+ messages in thread
From: Dan Carpenter @ 2017-07-20 11:37 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: Greg KH, devel, devicetree, linux-kernel, robh+dt, kbuild-all,
	grant.likely



On Thu, Jul 20, 2017 at 01:23:05PM +0200, Marcus Wolf wrote:
> Hi Greg,
> 
> below you can see the report with the error on m68k. It was sent to me from a
> test robot of intel.
> 
> According to my research, this problem occured, because there is no hardware
> support for floating point on the m68k (or it was configured not to use it).
> Therefore gcc uses an internal function, provided by libgcc. Obviously libgcc
> wasn't linked...
> 
> I don't know how to come arround this problem by modifying my code (except
> reducing the accuracy of the calculation by not using floating point).

I don't see any floating point?  You're not allowed to use floating
point in the kernel.

> 
> Can we ignore the error or can I do something else?
> Maybe a special include just in case of m68k can help??!?
> I don't have an environment for building m68k.
> 

I think the answer is to use div_u64() and div64_u64 instead of
do_div()?  Or you could just add a depend in the Kconfig.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-20 11:37                               ` Dan Carpenter
  0 siblings, 0 replies; 49+ messages in thread
From: Dan Carpenter @ 2017-07-20 11:37 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: devel, devicetree, Greg KH, linux-kernel, robh+dt, kbuild-all,
	grant.likely



On Thu, Jul 20, 2017 at 01:23:05PM +0200, Marcus Wolf wrote:
> Hi Greg,
> 
> below you can see the report with the error on m68k. It was sent to me from a
> test robot of intel.
> 
> According to my research, this problem occured, because there is no hardware
> support for floating point on the m68k (or it was configured not to use it).
> Therefore gcc uses an internal function, provided by libgcc. Obviously libgcc
> wasn't linked...
> 
> I don't know how to come arround this problem by modifying my code (except
> reducing the accuracy of the calculation by not using floating point).

I don't see any floating point?  You're not allowed to use floating
point in the kernel.

> 
> Can we ignore the error or can I do something else?
> Maybe a special include just in case of m68k can help??!?
> I don't have an environment for building m68k.
> 

I think the answer is to use div_u64() and div64_u64 instead of
do_div()?  Or you could just add a depend in the Kconfig.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
  2017-07-20 11:37                               ` Dan Carpenter
@ 2017-07-20 12:27                                 ` Geert Uytterhoeven
  -1 siblings, 0 replies; 49+ messages in thread
From: Geert Uytterhoeven @ 2017-07-20 12:27 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Marcus Wolf, Greg KH, driverdevel, devicetree, linux-kernel,
	Rob Herring, kbuild-all, Grant Likely

Hi Dan,

On Thu, Jul 20, 2017 at 1:37 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> On Thu, Jul 20, 2017 at 01:23:05PM +0200, Marcus Wolf wrote:
>> below you can see the report with the error on m68k. It was sent to me from a
>> test robot of intel.
>>
>> According to my research, this problem occured, because there is no hardware
>> support for floating point on the m68k (or it was configured not to use it).
>> Therefore gcc uses an internal function, provided by libgcc. Obviously libgcc
>> wasn't linked...
>>
>> I don't know how to come arround this problem by modifying my code (except
>> reducing the accuracy of the calculation by not using floating point).
>
> I don't see any floating point?  You're not allowed to use floating
> point in the kernel.

Indeed. __udivdi3 is used for 64-bit by 32-bit division.

>> Can we ignore the error or can I do something else?
>> Maybe a special include just in case of m68k can help??!?
>> I don't have an environment for building m68k.

https://www.kernel.org/pub/tools/crosstool/

> I think the answer is to use div_u64() and div64_u64 instead of
> do_div()?

do_div() is fine
The link error is not caused by do_div(), but by not using do_div() where
needed.

> Or you could just add a depend in the Kconfig.

Depend on what? !M68K? It's gonna fail on several 32-bit platforms.
Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] drivers/staging/pi433: New driver
@ 2017-07-20 12:27                                 ` Geert Uytterhoeven
  0 siblings, 0 replies; 49+ messages in thread
From: Geert Uytterhoeven @ 2017-07-20 12:27 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Marcus Wolf, driverdevel, devicetree, Greg KH, linux-kernel,
	Rob Herring, kbuild-all, Grant Likely

Hi Dan,

On Thu, Jul 20, 2017 at 1:37 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> On Thu, Jul 20, 2017 at 01:23:05PM +0200, Marcus Wolf wrote:
>> below you can see the report with the error on m68k. It was sent to me from a
>> test robot of intel.
>>
>> According to my research, this problem occured, because there is no hardware
>> support for floating point on the m68k (or it was configured not to use it).
>> Therefore gcc uses an internal function, provided by libgcc. Obviously libgcc
>> wasn't linked...
>>
>> I don't know how to come arround this problem by modifying my code (except
>> reducing the accuracy of the calculation by not using floating point).
>
> I don't see any floating point?  You're not allowed to use floating
> point in the kernel.

Indeed. __udivdi3 is used for 64-bit by 32-bit division.

>> Can we ignore the error or can I do something else?
>> Maybe a special include just in case of m68k can help??!?
>> I don't have an environment for building m68k.

https://www.kernel.org/pub/tools/crosstool/

> I think the answer is to use div_u64() and div64_u64 instead of
> do_div()?

do_div() is fine
The link error is not caused by do_div(), but by not using do_div() where
needed.

> Or you could just add a depend in the Kconfig.

Depend on what? !M68K? It's gonna fail on several 32-bit platforms.
Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
  2017-07-20 12:27                                 ` Geert Uytterhoeven
@ 2017-07-20 15:56                                   ` Marcus Wolf
  -1 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-20 15:56 UTC (permalink / raw)
  To: Dan Carpenter, Geert Uytterhoeven, Greg KH
  Cc: kbuild-all, linux-kernel, Rob Herring, driverdevel, devicetree,
	Grant Likely

Fixes problem with division in rf69_set_deviation

Fixes: 874bcba65f9a ("staging: pi433: New driver")
Signed-off-by: Marcus Wolf <linux@wolf-entwicklungen.de>

diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
--- a/drivers/staging/pi433/rf69.c
+++ b/drivers/staging/pi433/rf69.c
@@ -221,7 +221,7 @@ int rf69_set_frequency(struct spi_device *spi, u32
frequency)
 int rf69_set_frequency(struct spi_device *spi, u32 frequency)
 {
 	int retval;
-	u32 f_max;
+	u64 f_max;
 	u64 f_reg;
 	u64 f_step;
 	u8 msb;
@@ -238,7 +238,8 @@ int rf69_set_frequency(struct spi_device *spi, u32
frequency)
 	do_div(f_step, 524288); //  524288 = 2^19
 
 	// check input value
-	f_max = f_step * 8388608 / factor;
+	f_max = f_step * 8388608;
+	do_div(f_max, factor);
 	if (frequency > f_max)
 	{
 		dev_dbg(&spi->dev, "setFrequency: illegal input param");

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-20 15:56                                   ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-20 15:56 UTC (permalink / raw)
  To: Dan Carpenter, Geert Uytterhoeven, Greg KH
  Cc: driverdevel, devicetree, linux-kernel, Rob Herring, kbuild-all,
	Grant Likely

Fixes problem with division in rf69_set_deviation

Fixes: 874bcba65f9a ("staging: pi433: New driver")
Signed-off-by: Marcus Wolf <linux@wolf-entwicklungen.de>

diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
--- a/drivers/staging/pi433/rf69.c
+++ b/drivers/staging/pi433/rf69.c
@@ -221,7 +221,7 @@ int rf69_set_frequency(struct spi_device *spi, u32
frequency)
 int rf69_set_frequency(struct spi_device *spi, u32 frequency)
 {
 	int retval;
-	u32 f_max;
+	u64 f_max;
 	u64 f_reg;
 	u64 f_step;
 	u8 msb;
@@ -238,7 +238,8 @@ int rf69_set_frequency(struct spi_device *spi, u32
frequency)
 	do_div(f_step, 524288); //  524288 = 2^19
 
 	// check input value
-	f_max = f_step * 8388608 / factor;
+	f_max = f_step * 8388608;
+	do_div(f_max, factor);
 	if (frequency > f_max)
 	{
 		dev_dbg(&spi->dev, "setFrequency: illegal input param");

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Test of [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-20 15:57                                   ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-20 15:57 UTC (permalink / raw)
  To: Dan Carpenter, Geert Uytterhoeven, kbuild-all, Greg KH,
	linux-kernel, driverdevel, devicetree, Grant Likely, Rob Herring

Hi!

Since I don't have an environment for m68k and I would appreciate not
having to set it up, I would be very happy, if someone could give
the patch, named in the subjext, a try on ARCH=m68k...

Thanks,

Marcus



> Geert Uytterhoeven <geert@linux-m68k.org> hat am 20. Juli 2017 um 14:27
> geschrieben:
>
>
> Hi Dan,
>
> On Thu, Jul 20, 2017 at 1:37 PM, Dan Carpenter <dan.carpenter@oracle.com>
> wrote:
> > On Thu, Jul 20, 2017 at 01:23:05PM +0200, Marcus Wolf wrote:
> >> below you can see the report with the error on m68k. It was sent to me from
> >> a
> >> test robot of intel.
> >>
> >> According to my research, this problem occured, because there is no
> >> hardware
> >> support for floating point on the m68k (or it was configured not to use
> >> it).
> >> Therefore gcc uses an internal function, provided by libgcc. Obviously
> >> libgcc
> >> wasn't linked...
> >>
> >> I don't know how to come arround this problem by modifying my code (except
> >> reducing the accuracy of the calculation by not using floating point).
> >
> > I don't see any floating point? You're not allowed to use floating
> > point in the kernel.
>
> Indeed. __udivdi3 is used for 64-bit by 32-bit division.
>
> >> Can we ignore the error or can I do something else?
> >> Maybe a special include just in case of m68k can help??!?
> >> I don't have an environment for building m68k.
>
> https://www.kernel.org/pub/tools/crosstool/
>
> > I think the answer is to use div_u64() and div64_u64 instead of
> > do_div()?
>
> do_div() is fine
> The link error is not caused by do_div(), but by not using do_div() where
> needed.
>
> > Or you could just add a depend in the Kconfig.
>
> Depend on what? !M68K? It's gonna fail on several 32-bit platforms.
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 --
> geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like
> that.
> -- Linus Torvalds
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Test of [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-20 15:57                                   ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-20 15:57 UTC (permalink / raw)
  To: Dan Carpenter, Geert Uytterhoeven, kbuild-all-JC7UmRfGjtg,
	Greg KH, linux-kernel-u79uwXL29TY76Z2rM5mHXA, driverdevel,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Grant Likely, Rob Herring

Hi!

Since I don't have an environment for m68k and I would appreciate not
having to set it up, I would be very happy, if someone could give
the patch, named in the subjext, a try on ARCH=m68k...

Thanks,

Marcus



> Geert Uytterhoeven <geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org> hat am 20. Juli 2017 um 14:27
> geschrieben:
>
>
> Hi Dan,
>
> On Thu, Jul 20, 2017 at 1:37 PM, Dan Carpenter <dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
> wrote:
> > On Thu, Jul 20, 2017 at 01:23:05PM +0200, Marcus Wolf wrote:
> >> below you can see the report with the error on m68k. It was sent to me from
> >> a
> >> test robot of intel.
> >>
> >> According to my research, this problem occured, because there is no
> >> hardware
> >> support for floating point on the m68k (or it was configured not to use
> >> it).
> >> Therefore gcc uses an internal function, provided by libgcc. Obviously
> >> libgcc
> >> wasn't linked...
> >>
> >> I don't know how to come arround this problem by modifying my code (except
> >> reducing the accuracy of the calculation by not using floating point).
> >
> > I don't see any floating point? You're not allowed to use floating
> > point in the kernel.
>
> Indeed. __udivdi3 is used for 64-bit by 32-bit division.
>
> >> Can we ignore the error or can I do something else?
> >> Maybe a special include just in case of m68k can help??!?
> >> I don't have an environment for building m68k.
>
> https://www.kernel.org/pub/tools/crosstool/
>
> > I think the answer is to use div_u64() and div64_u64 instead of
> > do_div()?
>
> do_div() is fine
> The link error is not caused by do_div(), but by not using do_div() where
> needed.
>
> > Or you could just add a depend in the Kconfig.
>
> Depend on what? !M68K? It's gonna fail on several 32-bit platforms.
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 --
> geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like
> that.
> -- Linus Torvalds
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-29  0:01                                     ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-29  0:01 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: Dan Carpenter, Geert Uytterhoeven, driverdevel, devicetree,
	linux-kernel, Rob Herring, kbuild-all, Grant Likely

On Thu, Jul 20, 2017 at 05:56:36PM +0200, Marcus Wolf wrote:
> Fixes problem with division in rf69_set_deviation
> 
> Fixes: 874bcba65f9a ("staging: pi433: New driver")
> Signed-off-by: Marcus Wolf <linux@wolf-entwicklungen.de>
> 
> diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
> --- a/drivers/staging/pi433/rf69.c
> +++ b/drivers/staging/pi433/rf69.c
> @@ -221,7 +221,7 @@ int rf69_set_frequency(struct spi_device *spi, u32
> frequency)

Patch is line-wrapped and does not apply :(

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-29  0:01                                     ` Greg KH
  0 siblings, 0 replies; 49+ messages in thread
From: Greg KH @ 2017-07-29  0:01 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: Dan Carpenter, Geert Uytterhoeven, driverdevel,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
	kbuild-all-JC7UmRfGjtg, Grant Likely

On Thu, Jul 20, 2017 at 05:56:36PM +0200, Marcus Wolf wrote:
> Fixes problem with division in rf69_set_deviation
> 
> Fixes: 874bcba65f9a ("staging: pi433: New driver")
> Signed-off-by: Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
> 
> diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
> --- a/drivers/staging/pi433/rf69.c
> +++ b/drivers/staging/pi433/rf69.c
> @@ -221,7 +221,7 @@ int rf69_set_frequency(struct spi_device *spi, u32
> frequency)

Patch is line-wrapped and does not apply :(
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-29  8:51                                       ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-29  8:51 UTC (permalink / raw)
  To: Greg KH
  Cc: kbuild-all, Dan Carpenter, linux-kernel, Rob Herring,
	driverdevel, Geert Uytterhoeven, devicetree, Grant Likely

Hi Greg,
 
already had a discussion concerning that patch with Dan yesterday.
I really don't know what's going on there. I detached the patch once more from
my outbox and had a very close look in an editor and looked at it with a
difftool. In my outbox the patch is fine. I really don't knwo why it reaches you
crapped.
 
Since there are contsant problems with my patches, I will stop sending patches
for a while. As soon as I can find time to deeply confess with the tooling, I
will start over with trying.
 
Concerning this patch: You can use Arnds Patch from yesterday instead:
[PATCH] staging: pi433: use div_u64 for 64-bit division
It's a bit different to my patch, but according to yesterdays discussion, it
should also fix the problem.
 
Sorry for any inconvenience,
 
Marcus
 

> Greg KH <gregkh@linuxfoundation.org> hat am 29. Juli 2017 um 02:01
> geschrieben:
>
>
> On Thu, Jul 20, 2017 at 05:56:36PM +0200, Marcus Wolf wrote:
> > Fixes problem with division in rf69_set_deviation
> >
> > Fixes: 874bcba65f9a ("staging: pi433: New driver")
> > Signed-off-by: Marcus Wolf <linux@wolf-entwicklungen.de>
> >
> > diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
> > --- a/drivers/staging/pi433/rf69.c
> > +++ b/drivers/staging/pi433/rf69.c
> > @@ -221,7 +221,7 @@ int rf69_set_frequency(struct spi_device *spi, u32
> > frequency)
>
> Patch is line-wrapped and does not apply :(
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-29  8:51                                       ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-29  8:51 UTC (permalink / raw)
  To: Greg KH
  Cc: kbuild-all-JC7UmRfGjtg, Dan Carpenter,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, driverdevel,
	Geert Uytterhoeven, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Grant Likely

Hi Greg,
 
already had a discussion concerning that patch with Dan yesterday.
I really don't know what's going on there. I detached the patch once more from
my outbox and had a very close look in an editor and looked at it with a
difftool. In my outbox the patch is fine. I really don't knwo why it reaches you
crapped.
 
Since there are contsant problems with my patches, I will stop sending patches
for a while. As soon as I can find time to deeply confess with the tooling, I
will start over with trying.
 
Concerning this patch: You can use Arnds Patch from yesterday instead:
[PATCH] staging: pi433: use div_u64 for 64-bit division
It's a bit different to my patch, but according to yesterdays discussion, it
should also fix the problem.
 
Sorry for any inconvenience,
 
Marcus
 

> Greg KH <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org> hat am 29. Juli 2017 um 02:01
> geschrieben:
>
>
> On Thu, Jul 20, 2017 at 05:56:36PM +0200, Marcus Wolf wrote:
> > Fixes problem with division in rf69_set_deviation
> >
> > Fixes: 874bcba65f9a ("staging: pi433: New driver")
> > Signed-off-by: Marcus Wolf <linux-hymvNObv7Fheq5RAq1AYSxS11BummzK+@public.gmane.org>
> >
> > diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
> > --- a/drivers/staging/pi433/rf69.c
> > +++ b/drivers/staging/pi433/rf69.c
> > @@ -221,7 +221,7 @@ int rf69_set_frequency(struct spi_device *spi, u32
> > frequency)
>
> Patch is line-wrapped and does not apply :(
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
  2017-07-29  8:51                                       ` Marcus Wolf
  (?)
@ 2017-07-29 22:21                                       ` Greg KH
  2017-07-30 15:21                                           ` Marcus Wolf
  -1 siblings, 1 reply; 49+ messages in thread
From: Greg KH @ 2017-07-29 22:21 UTC (permalink / raw)
  To: Marcus Wolf
  Cc: driverdevel, devicetree, linux-kernel, Rob Herring,
	Geert Uytterhoeven, kbuild-all, Grant Likely, Dan Carpenter

On Sat, Jul 29, 2017 at 10:51:15AM +0200, Marcus Wolf wrote:
> Hi Greg,
>  
> already had a discussion concerning that patch with Dan yesterday.
> I really don't know what's going on there. I detached the patch once more from
> my outbox and had a very close look in an editor and looked at it with a
> difftool. In my outbox the patch is fine. I really don't knwo why it reaches you
> crapped.
>  
> Since there are contsant problems with my patches, I will stop sending patches
> for a while. As soon as I can find time to deeply confess with the tooling, I
> will start over with trying.

Just use 'git send-email' for patches if you are having problems with
your email client.  And get a better email client the kernel
Documentation has a whole file just about that topic and how to do it
correctly.

> Concerning this patch: You can use Arnds Patch from yesterday instead:
> [PATCH] staging: pi433: use div_u64 for 64-bit division
> It's a bit different to my patch, but according to yesterdays discussion, it
> should also fix the problem.

I already took it into my tree.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-30 15:21                                           ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-30 15:21 UTC (permalink / raw)
  To: Greg KH, Dan Carpenter; +Cc: kbuild-all, linux-kernel, driverdevel, devicetree

Hi Greg, hi Dan

the toolingproblem is a little bit more complicated. Since a mainline kernel
isn't directly able to boot on the RasPi, for testing I work with a Raspbian
kernel. Since at the beginning, I never thought of submitting the driver, I
started with a side-build project with SVN - that's stil my master... In
addition, disk is full :-( 

So in principle nothing is really adequate to meet the need of easy
participating in kernel development.
I will revise my tooling, as soon as I find the time and quietness - most
probably I need to setup from scratch.

For the announced change in rf69.c I will try to equip an SVN-diff with
apropriate headers next week, so Dan can crosscheck with his work - I hope, I
will make it without errors...

Have a nice weekend,

Marcus


> Greg KH <gregkh@linuxfoundation.org> hat am 30. Juli 2017 um 00:21
> geschrieben:
>
>
> On Sat, Jul 29, 2017 at 10:51:15AM +0200, Marcus Wolf wrote:
> > Hi Greg,
> >
> > already had a discussion concerning that patch with Dan yesterday.
> > I really don't know what's going on there. I detached the patch once more
> > from
> > my outbox and had a very close look in an editor and looked at it with a
> > difftool. In my outbox the patch is fine. I really don't knwo why it reaches
> > you
> > crapped.
> >
> > Since there are contsant problems with my patches, I will stop sending
> > patches
> > for a while. As soon as I can find time to deeply confess with the tooling,
> > I
> > will start over with trying.
>
> Just use 'git send-email' for patches if you are having problems with
> your email client. And get a better email client the kernel
> Documentation has a whole file just about that topic and how to do it
> correctly.
>
> > Concerning this patch: You can use Arnds Patch from yesterday instead:
> > [PATCH] staging: pi433: use div_u64 for 64-bit division
> > It's a bit different to my patch, but according to yesterdays discussion, it
> > should also fix the problem.
>
> I already took it into my tree.
>
> thanks,
>
> greg k-h
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation
@ 2017-07-30 15:21                                           ` Marcus Wolf
  0 siblings, 0 replies; 49+ messages in thread
From: Marcus Wolf @ 2017-07-30 15:21 UTC (permalink / raw)
  To: Greg KH, Dan Carpenter
  Cc: kbuild-all-JC7UmRfGjtg, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	driverdevel, devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Greg, hi Dan

the toolingproblem is a little bit more complicated. Since a mainline kernel
isn't directly able to boot on the RasPi, for testing I work with a Raspbian
kernel. Since at the beginning, I never thought of submitting the driver, I
started with a side-build project with SVN - that's stil my master... In
addition, disk is full :-( 

So in principle nothing is really adequate to meet the need of easy
participating in kernel development.
I will revise my tooling, as soon as I find the time and quietness - most
probably I need to setup from scratch.

For the announced change in rf69.c I will try to equip an SVN-diff with
apropriate headers next week, so Dan can crosscheck with his work - I hope, I
will make it without errors...

Have a nice weekend,

Marcus


> Greg KH <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org> hat am 30. Juli 2017 um 00:21
> geschrieben:
>
>
> On Sat, Jul 29, 2017 at 10:51:15AM +0200, Marcus Wolf wrote:
> > Hi Greg,
> >
> > already had a discussion concerning that patch with Dan yesterday.
> > I really don't know what's going on there. I detached the patch once more
> > from
> > my outbox and had a very close look in an editor and looked at it with a
> > difftool. In my outbox the patch is fine. I really don't knwo why it reaches
> > you
> > crapped.
> >
> > Since there are contsant problems with my patches, I will stop sending
> > patches
> > for a while. As soon as I can find time to deeply confess with the tooling,
> > I
> > will start over with trying.
>
> Just use 'git send-email' for patches if you are having problems with
> your email client. And get a better email client the kernel
> Documentation has a whole file just about that topic and how to do it
> correctly.
>
> > Concerning this patch: You can use Arnds Patch from yesterday instead:
> > [PATCH] staging: pi433: use div_u64 for 64-bit division
> > It's a bit different to my patch, but according to yesterdays discussion, it
> > should also fix the problem.
>
> I already took it into my tree.
>
> thanks,
>
> greg k-h
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2017-07-30 15:21 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-11 16:02 Submit of a driver for Pi433 - a radio module for Raspberry Pi Marcus Wolf
2017-07-12  7:43 ` Greg KH
2017-07-15 11:15   ` Marcus Wolf
2017-07-15 11:24     ` Greg KH
2017-07-15 11:24       ` Greg KH
2017-07-15 12:26       ` Marcus Wolf
2017-07-15 12:59       ` Marcus Wolf
2017-07-15 12:59         ` Marcus Wolf
2017-07-15 13:02         ` Greg KH
2017-07-15 13:02           ` Greg KH
2017-07-15 13:10           ` Marcus Wolf
2017-07-15 13:10             ` Marcus Wolf
2017-07-15 13:16             ` Greg KH
2017-07-15 13:16               ` Greg KH
2017-07-15 13:40               ` Marcus Wolf
2017-07-15 13:47                 ` Greg KH
2017-07-15 13:47                   ` Greg KH
2017-07-15 17:05                   ` Wolf Entwicklungen
2017-07-15 17:05                     ` Wolf Entwicklungen
2017-07-16  6:45                     ` Greg KH
2017-07-16  9:52                       ` [PATCH 1/1] drivers/staging/pi433: New driver Wolf Entwicklungen
2017-07-16  9:52                         ` Wolf Entwicklungen
2017-07-16 10:15                         ` Greg KH
2017-07-16 10:15                           ` Greg KH
2017-07-16 13:53                           ` Marcus Wolf
2017-07-16 13:53                             ` Marcus Wolf
2017-07-16 14:47                             ` Greg KH
2017-07-16 14:47                               ` Greg KH
2017-07-17  6:18                         ` kbuild test robot
2017-07-17 13:26                         ` kbuild test robot
2017-07-17 13:26                           ` kbuild test robot
2017-07-20 11:23                           ` Marcus Wolf
2017-07-20 11:23                             ` Marcus Wolf
2017-07-20 11:31                             ` Greg KH
2017-07-20 11:37                             ` Dan Carpenter
2017-07-20 11:37                               ` Dan Carpenter
2017-07-20 12:27                               ` Geert Uytterhoeven
2017-07-20 12:27                                 ` Geert Uytterhoeven
2017-07-20 15:56                                 ` [PATCH 1/1] staging: pi433: fix problem with division in rf69_set_deviation Marcus Wolf
2017-07-20 15:56                                   ` Marcus Wolf
2017-07-29  0:01                                   ` Greg KH
2017-07-29  0:01                                     ` Greg KH
2017-07-29  8:51                                     ` Marcus Wolf
2017-07-29  8:51                                       ` Marcus Wolf
2017-07-29 22:21                                       ` Greg KH
2017-07-30 15:21                                         ` Marcus Wolf
2017-07-30 15:21                                           ` Marcus Wolf
2017-07-20 15:57                                 ` Test of " Marcus Wolf
2017-07-20 15:57                                   ` Marcus Wolf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.