1874bcba6SMarcus Wolf /* 2874bcba6SMarcus Wolf * userspace interface for pi433 radio module 3874bcba6SMarcus Wolf * 4874bcba6SMarcus Wolf * Pi433 is a 433MHz radio module for the Raspberry Pi. 5874bcba6SMarcus Wolf * It is based on the HopeRf Module RFM69CW. Therefore inside of this 6874bcba6SMarcus Wolf * driver, you'll find an abstraction of the rf69 chip. 7874bcba6SMarcus Wolf * 8874bcba6SMarcus Wolf * If needed, this driver could be extended, to also support other 9874bcba6SMarcus Wolf * devices, basing on HopeRfs rf69. 10874bcba6SMarcus Wolf * 11874bcba6SMarcus Wolf * The driver can also be extended, to support other modules of 12874bcba6SMarcus Wolf * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ... 13874bcba6SMarcus Wolf * 14874bcba6SMarcus Wolf * Copyright (C) 2016 Wolf-Entwicklungen 15874bcba6SMarcus Wolf * Marcus Wolf <linux@wolf-entwicklungen.de> 16874bcba6SMarcus Wolf * 17874bcba6SMarcus Wolf * This program is free software; you can redistribute it and/or modify 18874bcba6SMarcus Wolf * it under the terms of the GNU General Public License as published by 19874bcba6SMarcus Wolf * the Free Software Foundation; either version 2 of the License, or 20874bcba6SMarcus Wolf * (at your option) any later version. 21874bcba6SMarcus Wolf * 22874bcba6SMarcus Wolf * This program is distributed in the hope that it will be useful, 23874bcba6SMarcus Wolf * but WITHOUT ANY WARRANTY; without even the implied warranty of 24874bcba6SMarcus Wolf * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25874bcba6SMarcus Wolf * GNU General Public License for more details. 26874bcba6SMarcus Wolf */ 27874bcba6SMarcus Wolf 28874bcba6SMarcus Wolf #undef DEBUG 29874bcba6SMarcus Wolf 30874bcba6SMarcus Wolf #include <linux/init.h> 31874bcba6SMarcus Wolf #include <linux/module.h> 32874bcba6SMarcus Wolf #include <linux/idr.h> 33874bcba6SMarcus Wolf #include <linux/ioctl.h> 34874bcba6SMarcus Wolf #include <linux/uaccess.h> 35874bcba6SMarcus Wolf #include <linux/fs.h> 36874bcba6SMarcus Wolf #include <linux/device.h> 37874bcba6SMarcus Wolf #include <linux/cdev.h> 38874bcba6SMarcus Wolf #include <linux/err.h> 39874bcba6SMarcus Wolf #include <linux/kfifo.h> 40874bcba6SMarcus Wolf #include <linux/errno.h> 41874bcba6SMarcus Wolf #include <linux/mutex.h> 42874bcba6SMarcus Wolf #include <linux/of.h> 43874bcba6SMarcus Wolf #include <linux/of_device.h> 44874bcba6SMarcus Wolf #include <linux/interrupt.h> 45874bcba6SMarcus Wolf #include <linux/irq.h> 46874bcba6SMarcus Wolf #include <linux/gpio/consumer.h> 47874bcba6SMarcus Wolf #include <linux/kthread.h> 48874bcba6SMarcus Wolf #include <linux/wait.h> 49874bcba6SMarcus Wolf #include <linux/spi/spi.h> 50874bcba6SMarcus Wolf #ifdef CONFIG_COMPAT 51874bcba6SMarcus Wolf #include <asm/compat.h> 52874bcba6SMarcus Wolf #endif 53874bcba6SMarcus Wolf 54874bcba6SMarcus Wolf #include "pi433_if.h" 55874bcba6SMarcus Wolf #include "rf69.h" 56874bcba6SMarcus Wolf 57874bcba6SMarcus Wolf #define N_PI433_MINORS (1U << MINORBITS) /*32*/ /* ... up to 256 */ 58874bcba6SMarcus Wolf #define MAX_MSG_SIZE 900 /* min: FIFO_SIZE! */ 59874bcba6SMarcus Wolf #define MSG_FIFO_SIZE 65536 /* 65536 = 2^16 */ 60874bcba6SMarcus Wolf #define NUM_DIO 2 61874bcba6SMarcus Wolf 62874bcba6SMarcus Wolf static dev_t pi433_dev; 63874bcba6SMarcus Wolf static DEFINE_IDR(pi433_idr); 64874bcba6SMarcus Wolf static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */ 65874bcba6SMarcus Wolf 66874bcba6SMarcus Wolf static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */ 67874bcba6SMarcus Wolf 68874bcba6SMarcus Wolf /* tx config is instance specific 69056eeda2SDerek Robson * so with each open a new tx config struct is needed 70056eeda2SDerek Robson */ 71874bcba6SMarcus Wolf /* rx config is device specific 72056eeda2SDerek Robson * so we have just one rx config, ebedded in device struct 73056eeda2SDerek Robson */ 74874bcba6SMarcus Wolf struct pi433_device { 75874bcba6SMarcus Wolf /* device handling related values */ 76874bcba6SMarcus Wolf dev_t devt; 77874bcba6SMarcus Wolf int minor; 78874bcba6SMarcus Wolf struct device *dev; 79874bcba6SMarcus Wolf struct cdev *cdev; 80874bcba6SMarcus Wolf struct spi_device *spi; 81211c2820SValentin Vidic unsigned int users; 82874bcba6SMarcus Wolf 83874bcba6SMarcus Wolf /* irq related values */ 84874bcba6SMarcus Wolf struct gpio_desc *gpiod[NUM_DIO]; 85874bcba6SMarcus Wolf int irq_num[NUM_DIO]; 86874bcba6SMarcus Wolf u8 irq_state[NUM_DIO]; 87874bcba6SMarcus Wolf 88874bcba6SMarcus Wolf /* tx related values */ 89874bcba6SMarcus Wolf STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo; 90874bcba6SMarcus Wolf struct mutex tx_fifo_lock; // TODO: check, whether necessary or obsolete 91874bcba6SMarcus Wolf struct task_struct *tx_task_struct; 92874bcba6SMarcus Wolf wait_queue_head_t tx_wait_queue; 93874bcba6SMarcus Wolf u8 free_in_fifo; 9462f39d49SArnd Bergmann char buffer[MAX_MSG_SIZE]; 95874bcba6SMarcus Wolf 96874bcba6SMarcus Wolf /* rx related values */ 97874bcba6SMarcus Wolf struct pi433_rx_cfg rx_cfg; 98874bcba6SMarcus Wolf u8 *rx_buffer; 99874bcba6SMarcus Wolf unsigned int rx_buffer_size; 100874bcba6SMarcus Wolf u32 rx_bytes_to_drop; 101874bcba6SMarcus Wolf u32 rx_bytes_dropped; 102874bcba6SMarcus Wolf unsigned int rx_position; 103874bcba6SMarcus Wolf struct mutex rx_lock; 104874bcba6SMarcus Wolf wait_queue_head_t rx_wait_queue; 105874bcba6SMarcus Wolf 106874bcba6SMarcus Wolf /* fifo wait queue */ 107874bcba6SMarcus Wolf struct task_struct *fifo_task_struct; 108874bcba6SMarcus Wolf wait_queue_head_t fifo_wait_queue; 109874bcba6SMarcus Wolf 110874bcba6SMarcus Wolf /* flags */ 111874bcba6SMarcus Wolf bool rx_active; 112874bcba6SMarcus Wolf bool tx_active; 113874bcba6SMarcus Wolf bool interrupt_rx_allowed; 114874bcba6SMarcus Wolf }; 115874bcba6SMarcus Wolf 116874bcba6SMarcus Wolf struct pi433_instance { 117874bcba6SMarcus Wolf struct pi433_device *device; 118874bcba6SMarcus Wolf struct pi433_tx_cfg tx_cfg; 119874bcba6SMarcus Wolf }; 120874bcba6SMarcus Wolf 121874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 122874bcba6SMarcus Wolf 123874bcba6SMarcus Wolf /* GPIO interrupt handlers */ 124ee26e236SCihangir Akturk static irqreturn_t DIO0_irq_handler(int irq, void *dev_id) 125874bcba6SMarcus Wolf { 126874bcba6SMarcus Wolf struct pi433_device *device = dev_id; 127874bcba6SMarcus Wolf 12891086b82SValentin Vidic if (device->irq_state[DIO0] == DIO_PACKET_SENT) { 129874bcba6SMarcus Wolf device->free_in_fifo = FIFO_SIZE; 1305a60d7baSHaneen Mohammed dev_dbg(device->dev, "DIO0 irq: Packet sent\n"); 131874bcba6SMarcus Wolf wake_up_interruptible(&device->fifo_wait_queue); 13291086b82SValentin Vidic } else if (device->irq_state[DIO0] == DIO_RSSI_DIO0) { 1335a60d7baSHaneen Mohammed dev_dbg(device->dev, "DIO0 irq: RSSI level over threshold\n"); 134874bcba6SMarcus Wolf wake_up_interruptible(&device->rx_wait_queue); 13591086b82SValentin Vidic } else if (device->irq_state[DIO0] == DIO_PAYLOAD_READY) { 1363d7f3bf2SSimon Sandström dev_dbg(device->dev, "DIO0 irq: Payload ready\n"); 137874bcba6SMarcus Wolf device->free_in_fifo = 0; 138874bcba6SMarcus Wolf wake_up_interruptible(&device->fifo_wait_queue); 139874bcba6SMarcus Wolf } 140874bcba6SMarcus Wolf 141ee26e236SCihangir Akturk return IRQ_HANDLED; 142874bcba6SMarcus Wolf } 143874bcba6SMarcus Wolf 144ee26e236SCihangir Akturk static irqreturn_t DIO1_irq_handler(int irq, void *dev_id) 145874bcba6SMarcus Wolf { 146874bcba6SMarcus Wolf struct pi433_device *device = dev_id; 147874bcba6SMarcus Wolf 14891086b82SValentin Vidic if (device->irq_state[DIO1] == DIO_FIFO_NOT_EMPTY_DIO1) { 149874bcba6SMarcus Wolf device->free_in_fifo = FIFO_SIZE; 15091086b82SValentin Vidic } else if (device->irq_state[DIO1] == DIO_FIFO_LEVEL) { 1516b167a67SValentin Vidic if (device->rx_active) 1526b167a67SValentin Vidic device->free_in_fifo = FIFO_THRESHOLD - 1; 1536b167a67SValentin Vidic else 1546b167a67SValentin Vidic device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1; 155874bcba6SMarcus Wolf } 1565a60d7baSHaneen Mohammed dev_dbg(device->dev, 1575a60d7baSHaneen Mohammed "DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); 158874bcba6SMarcus Wolf wake_up_interruptible(&device->fifo_wait_queue); 159874bcba6SMarcus Wolf 160ee26e236SCihangir Akturk return IRQ_HANDLED; 161874bcba6SMarcus Wolf } 162874bcba6SMarcus Wolf 163874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 164874bcba6SMarcus Wolf 165874bcba6SMarcus Wolf static int 166874bcba6SMarcus Wolf rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) 167874bcba6SMarcus Wolf { 168125a452cSElia Geretto int ret; 169874bcba6SMarcus Wolf int payload_length; 170874bcba6SMarcus Wolf 171874bcba6SMarcus Wolf /* receiver config */ 172038a5b4eSNguyen Phan Quang Minh ret = rf69_set_frequency(dev->spi, rx_cfg->frequency); 173038a5b4eSNguyen Phan Quang Minh if (ret < 0) 174038a5b4eSNguyen Phan Quang Minh return ret; 175038a5b4eSNguyen Phan Quang Minh ret = rf69_set_bit_rate(dev->spi, rx_cfg->bit_rate); 176038a5b4eSNguyen Phan Quang Minh if (ret < 0) 177038a5b4eSNguyen Phan Quang Minh return ret; 178038a5b4eSNguyen Phan Quang Minh ret = rf69_set_modulation(dev->spi, rx_cfg->modulation); 179038a5b4eSNguyen Phan Quang Minh if (ret < 0) 180038a5b4eSNguyen Phan Quang Minh return ret; 181038a5b4eSNguyen Phan Quang Minh ret = rf69_set_antenna_impedance(dev->spi, rx_cfg->antenna_impedance); 182038a5b4eSNguyen Phan Quang Minh if (ret < 0) 183038a5b4eSNguyen Phan Quang Minh return ret; 184038a5b4eSNguyen Phan Quang Minh ret = rf69_set_rssi_threshold(dev->spi, rx_cfg->rssi_threshold); 185038a5b4eSNguyen Phan Quang Minh if (ret < 0) 186038a5b4eSNguyen Phan Quang Minh return ret; 187038a5b4eSNguyen Phan Quang Minh ret = rf69_set_ook_threshold_dec(dev->spi, rx_cfg->threshold_decrement); 188038a5b4eSNguyen Phan Quang Minh if (ret < 0) 189038a5b4eSNguyen Phan Quang Minh return ret; 190038a5b4eSNguyen Phan Quang Minh ret = rf69_set_bandwidth(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent); 191038a5b4eSNguyen Phan Quang Minh if (ret < 0) 192038a5b4eSNguyen Phan Quang Minh return ret; 193038a5b4eSNguyen Phan Quang Minh ret = rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent); 194038a5b4eSNguyen Phan Quang Minh if (ret < 0) 195038a5b4eSNguyen Phan Quang Minh return ret; 196038a5b4eSNguyen Phan Quang Minh ret = rf69_set_dagc(dev->spi, rx_cfg->dagc); 197038a5b4eSNguyen Phan Quang Minh if (ret < 0) 198038a5b4eSNguyen Phan Quang Minh return ret; 199874bcba6SMarcus Wolf 200874bcba6SMarcus Wolf dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop; 201874bcba6SMarcus Wolf 202874bcba6SMarcus Wolf /* packet config */ 203874bcba6SMarcus Wolf /* enable */ 20491086b82SValentin Vidic if (rx_cfg->enable_sync == OPTION_ON) { 205966debe0SSimon Sandström ret = rf69_enable_sync(dev->spi); 206966debe0SSimon Sandström if (ret < 0) 207966debe0SSimon Sandström return ret; 208966debe0SSimon Sandström 209038a5b4eSNguyen Phan Quang Minh ret = rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt); 210038a5b4eSNguyen Phan Quang Minh if (ret < 0) 211038a5b4eSNguyen Phan Quang Minh return ret; 21291086b82SValentin Vidic } else { 213966debe0SSimon Sandström ret = rf69_disable_sync(dev->spi); 214966debe0SSimon Sandström if (ret < 0) 215966debe0SSimon Sandström return ret; 216966debe0SSimon Sandström 217038a5b4eSNguyen Phan Quang Minh ret = rf69_set_fifo_fill_condition(dev->spi, always); 218038a5b4eSNguyen Phan Quang Minh if (ret < 0) 219038a5b4eSNguyen Phan Quang Minh return ret; 220874bcba6SMarcus Wolf } 221d423c809SSimon Sandström if (rx_cfg->enable_length_byte == OPTION_ON) { 222125a452cSElia Geretto ret = rf69_set_packet_format(dev->spi, packetLengthVar); 223125a452cSElia Geretto if (ret < 0) 224125a452cSElia Geretto return ret; 225125a452cSElia Geretto } else { 226125a452cSElia Geretto ret = rf69_set_packet_format(dev->spi, packetLengthFix); 227125a452cSElia Geretto if (ret < 0) 228125a452cSElia Geretto return ret; 229125a452cSElia Geretto } 230038a5b4eSNguyen Phan Quang Minh ret = rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering); 231038a5b4eSNguyen Phan Quang Minh if (ret < 0) 232038a5b4eSNguyen Phan Quang Minh return ret; 23339252a4bSSimon Sandström 23439252a4bSSimon Sandström if (rx_cfg->enable_crc == OPTION_ON) { 23539252a4bSSimon Sandström ret = rf69_enable_crc(dev->spi); 23639252a4bSSimon Sandström if (ret < 0) 23739252a4bSSimon Sandström return ret; 23839252a4bSSimon Sandström } else { 23939252a4bSSimon Sandström ret = rf69_disable_crc(dev->spi); 24039252a4bSSimon Sandström if (ret < 0) 24139252a4bSSimon Sandström return ret; 24239252a4bSSimon Sandström } 243874bcba6SMarcus Wolf 244874bcba6SMarcus Wolf /* lengths */ 245038a5b4eSNguyen Phan Quang Minh ret = rf69_set_sync_size(dev->spi, rx_cfg->sync_length); 246038a5b4eSNguyen Phan Quang Minh if (ret < 0) 247038a5b4eSNguyen Phan Quang Minh return ret; 24891086b82SValentin Vidic if (rx_cfg->enable_length_byte == OPTION_ON) { 249038a5b4eSNguyen Phan Quang Minh ret = rf69_set_payload_length(dev->spi, 0xff); 250038a5b4eSNguyen Phan Quang Minh if (ret < 0) 251038a5b4eSNguyen Phan Quang Minh return ret; 25291086b82SValentin Vidic } else if (rx_cfg->fixed_message_length != 0) { 253874bcba6SMarcus Wolf payload_length = rx_cfg->fixed_message_length; 2546b167a67SValentin Vidic if (rx_cfg->enable_length_byte == OPTION_ON) 2556b167a67SValentin Vidic payload_length++; 2566b167a67SValentin Vidic if (rx_cfg->enable_address_filtering != filteringOff) 2576b167a67SValentin Vidic payload_length++; 258038a5b4eSNguyen Phan Quang Minh ret = rf69_set_payload_length(dev->spi, payload_length); 259038a5b4eSNguyen Phan Quang Minh if (ret < 0) 260038a5b4eSNguyen Phan Quang Minh return ret; 26191086b82SValentin Vidic } else { 262038a5b4eSNguyen Phan Quang Minh ret = rf69_set_payload_length(dev->spi, 0); 263038a5b4eSNguyen Phan Quang Minh if (ret < 0) 264038a5b4eSNguyen Phan Quang Minh return ret; 265874bcba6SMarcus Wolf } 266874bcba6SMarcus Wolf 267874bcba6SMarcus Wolf /* values */ 26891086b82SValentin Vidic if (rx_cfg->enable_sync == OPTION_ON) { 269038a5b4eSNguyen Phan Quang Minh ret = rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern); 270038a5b4eSNguyen Phan Quang Minh if (ret < 0) 271038a5b4eSNguyen Phan Quang Minh return ret; 272874bcba6SMarcus Wolf } 27391086b82SValentin Vidic if (rx_cfg->enable_address_filtering != filteringOff) { 274038a5b4eSNguyen Phan Quang Minh ret = rf69_set_node_address(dev->spi, rx_cfg->node_address); 275038a5b4eSNguyen Phan Quang Minh if (ret < 0) 276038a5b4eSNguyen Phan Quang Minh return ret; 277038a5b4eSNguyen Phan Quang Minh ret = rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address); 278038a5b4eSNguyen Phan Quang Minh if (ret < 0) 279038a5b4eSNguyen Phan Quang Minh return ret; 280874bcba6SMarcus Wolf } 281874bcba6SMarcus Wolf 282874bcba6SMarcus Wolf return 0; 283874bcba6SMarcus Wolf } 284874bcba6SMarcus Wolf 285874bcba6SMarcus Wolf static int 286874bcba6SMarcus Wolf rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg) 287874bcba6SMarcus Wolf { 288125a452cSElia Geretto int ret; 289125a452cSElia Geretto 290038a5b4eSNguyen Phan Quang Minh ret = rf69_set_frequency(dev->spi, tx_cfg->frequency); 291038a5b4eSNguyen Phan Quang Minh if (ret < 0) 292038a5b4eSNguyen Phan Quang Minh return ret; 293038a5b4eSNguyen Phan Quang Minh ret = rf69_set_bit_rate(dev->spi, tx_cfg->bit_rate); 294038a5b4eSNguyen Phan Quang Minh if (ret < 0) 295038a5b4eSNguyen Phan Quang Minh return ret; 296038a5b4eSNguyen Phan Quang Minh ret = rf69_set_modulation(dev->spi, tx_cfg->modulation); 297038a5b4eSNguyen Phan Quang Minh if (ret < 0) 298038a5b4eSNguyen Phan Quang Minh return ret; 299038a5b4eSNguyen Phan Quang Minh ret = rf69_set_deviation(dev->spi, tx_cfg->dev_frequency); 300038a5b4eSNguyen Phan Quang Minh if (ret < 0) 301038a5b4eSNguyen Phan Quang Minh return ret; 302038a5b4eSNguyen Phan Quang Minh ret = rf69_set_pa_ramp(dev->spi, tx_cfg->pa_ramp); 303038a5b4eSNguyen Phan Quang Minh if (ret < 0) 304038a5b4eSNguyen Phan Quang Minh return ret; 305038a5b4eSNguyen Phan Quang Minh ret = rf69_set_modulation_shaping(dev->spi, tx_cfg->mod_shaping); 306038a5b4eSNguyen Phan Quang Minh if (ret < 0) 307038a5b4eSNguyen Phan Quang Minh return ret; 308038a5b4eSNguyen Phan Quang Minh ret = rf69_set_tx_start_condition(dev->spi, tx_cfg->tx_start_condition); 309038a5b4eSNguyen Phan Quang Minh if (ret < 0) 310038a5b4eSNguyen Phan Quang Minh return ret; 311874bcba6SMarcus Wolf 312874bcba6SMarcus Wolf /* packet format enable */ 31391086b82SValentin Vidic if (tx_cfg->enable_preamble == OPTION_ON) { 314038a5b4eSNguyen Phan Quang Minh ret = rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length); 315038a5b4eSNguyen Phan Quang Minh if (ret < 0) 316038a5b4eSNguyen Phan Quang Minh return ret; 31791086b82SValentin Vidic } else { 318038a5b4eSNguyen Phan Quang Minh ret = rf69_set_preamble_length(dev->spi, 0); 319038a5b4eSNguyen Phan Quang Minh if (ret < 0) 320038a5b4eSNguyen Phan Quang Minh return ret; 321874bcba6SMarcus Wolf } 322966debe0SSimon Sandström 323966debe0SSimon Sandström if (tx_cfg->enable_sync == OPTION_ON) { 324966debe0SSimon Sandström ret = rf69_enable_sync(dev->spi); 325966debe0SSimon Sandström if (ret < 0) 326966debe0SSimon Sandström return ret; 327966debe0SSimon Sandström } else { 328966debe0SSimon Sandström ret = rf69_disable_sync(dev->spi); 329966debe0SSimon Sandström if (ret < 0) 330966debe0SSimon Sandström return ret; 331966debe0SSimon Sandström } 332966debe0SSimon Sandström 333d423c809SSimon Sandström if (tx_cfg->enable_length_byte == OPTION_ON) { 334125a452cSElia Geretto ret = rf69_set_packet_format(dev->spi, packetLengthVar); 335125a452cSElia Geretto if (ret < 0) 336125a452cSElia Geretto return ret; 337125a452cSElia Geretto } else { 338125a452cSElia Geretto ret = rf69_set_packet_format(dev->spi, packetLengthFix); 339125a452cSElia Geretto if (ret < 0) 340125a452cSElia Geretto return ret; 341125a452cSElia Geretto } 34239252a4bSSimon Sandström 34339252a4bSSimon Sandström if (tx_cfg->enable_crc == OPTION_ON) { 34439252a4bSSimon Sandström ret = rf69_enable_crc(dev->spi); 34539252a4bSSimon Sandström if (ret < 0) 34639252a4bSSimon Sandström return ret; 34739252a4bSSimon Sandström } else { 34839252a4bSSimon Sandström ret = rf69_disable_crc(dev->spi); 34939252a4bSSimon Sandström if (ret < 0) 35039252a4bSSimon Sandström return ret; 35139252a4bSSimon Sandström } 352874bcba6SMarcus Wolf 353874bcba6SMarcus Wolf /* configure sync, if enabled */ 354d423c809SSimon Sandström if (tx_cfg->enable_sync == OPTION_ON) { 355038a5b4eSNguyen Phan Quang Minh ret = rf69_set_sync_size(dev->spi, tx_cfg->sync_length); 356038a5b4eSNguyen Phan Quang Minh if (ret < 0) 357038a5b4eSNguyen Phan Quang Minh return ret; 358038a5b4eSNguyen Phan Quang Minh ret = rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern); 359038a5b4eSNguyen Phan Quang Minh if (ret < 0) 360038a5b4eSNguyen Phan Quang Minh return ret; 361874bcba6SMarcus Wolf } 362874bcba6SMarcus Wolf 363874bcba6SMarcus Wolf return 0; 364874bcba6SMarcus Wolf } 365874bcba6SMarcus Wolf 366874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 367874bcba6SMarcus Wolf 368874bcba6SMarcus Wolf static int 369874bcba6SMarcus Wolf pi433_start_rx(struct pi433_device *dev) 370874bcba6SMarcus Wolf { 371874bcba6SMarcus Wolf int retval; 372874bcba6SMarcus Wolf 373874bcba6SMarcus Wolf /* return without action, if no pending read request */ 374874bcba6SMarcus Wolf if (!dev->rx_active) 375874bcba6SMarcus Wolf return 0; 376874bcba6SMarcus Wolf 377874bcba6SMarcus Wolf /* setup for receiving */ 378874bcba6SMarcus Wolf retval = rf69_set_rx_cfg(dev, &dev->rx_cfg); 3796b167a67SValentin Vidic if (retval) 3806b167a67SValentin Vidic return retval; 381874bcba6SMarcus Wolf 382874bcba6SMarcus Wolf /* setup rssi irq */ 383038a5b4eSNguyen Phan Quang Minh retval = rf69_set_dio_mapping(dev->spi, DIO0, DIO_RSSI_DIO0); 384038a5b4eSNguyen Phan Quang Minh if (retval < 0) 385038a5b4eSNguyen Phan Quang Minh return retval; 3863d7f3bf2SSimon Sandström dev->irq_state[DIO0] = DIO_RSSI_DIO0; 387874bcba6SMarcus Wolf irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); 388874bcba6SMarcus Wolf 389874bcba6SMarcus Wolf /* setup fifo level interrupt */ 390038a5b4eSNguyen Phan Quang Minh retval = rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD); 391038a5b4eSNguyen Phan Quang Minh if (retval < 0) 392038a5b4eSNguyen Phan Quang Minh return retval; 393038a5b4eSNguyen Phan Quang Minh retval = rf69_set_dio_mapping(dev->spi, DIO1, DIO_FIFO_LEVEL); 394038a5b4eSNguyen Phan Quang Minh if (retval < 0) 395038a5b4eSNguyen Phan Quang Minh return retval; 3963d7f3bf2SSimon Sandström dev->irq_state[DIO1] = DIO_FIFO_LEVEL; 397874bcba6SMarcus Wolf irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING); 398874bcba6SMarcus Wolf 399874bcba6SMarcus Wolf /* set module to receiving mode */ 400038a5b4eSNguyen Phan Quang Minh retval = rf69_set_mode(dev->spi, receive); 401038a5b4eSNguyen Phan Quang Minh if (retval < 0) 402038a5b4eSNguyen Phan Quang Minh return retval; 403874bcba6SMarcus Wolf 404874bcba6SMarcus Wolf return 0; 405874bcba6SMarcus Wolf } 406874bcba6SMarcus Wolf 407874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 408874bcba6SMarcus Wolf 4097de77a39SJoseph Wright static int 410874bcba6SMarcus Wolf pi433_receive(void *data) 411874bcba6SMarcus Wolf { 412874bcba6SMarcus Wolf struct pi433_device *dev = data; 413038a5b4eSNguyen Phan Quang Minh struct spi_device *spi = dev->spi; 414874bcba6SMarcus Wolf int bytes_to_read, bytes_total; 415874bcba6SMarcus Wolf int retval; 416874bcba6SMarcus Wolf 417874bcba6SMarcus Wolf dev->interrupt_rx_allowed = false; 418874bcba6SMarcus Wolf 419874bcba6SMarcus Wolf /* wait for any tx to finish */ 420874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: going to wait for any tx to finish"); 421874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active); 42291086b82SValentin Vidic if (retval) { 42391086b82SValentin Vidic /* wait was interrupted */ 424874bcba6SMarcus Wolf dev->interrupt_rx_allowed = true; 425874bcba6SMarcus Wolf wake_up_interruptible(&dev->tx_wait_queue); 426874bcba6SMarcus Wolf return retval; 427874bcba6SMarcus Wolf } 428874bcba6SMarcus Wolf 429874bcba6SMarcus Wolf /* prepare status vars */ 430874bcba6SMarcus Wolf dev->free_in_fifo = FIFO_SIZE; 431874bcba6SMarcus Wolf dev->rx_position = 0; 432874bcba6SMarcus Wolf dev->rx_bytes_dropped = 0; 433874bcba6SMarcus Wolf 434874bcba6SMarcus Wolf /* setup radio module to listen for something "in the air" */ 435874bcba6SMarcus Wolf retval = pi433_start_rx(dev); 436874bcba6SMarcus Wolf if (retval) 437874bcba6SMarcus Wolf return retval; 438874bcba6SMarcus Wolf 439874bcba6SMarcus Wolf /* now check RSSI, if low wait for getting high (RSSI interrupt) */ 44091086b82SValentin Vidic while (!rf69_get_flag(dev->spi, rssiExceededThreshold)) { 441874bcba6SMarcus Wolf /* allow tx to interrupt us while waiting for high RSSI */ 442874bcba6SMarcus Wolf dev->interrupt_rx_allowed = true; 443874bcba6SMarcus Wolf wake_up_interruptible(&dev->tx_wait_queue); 444874bcba6SMarcus Wolf 445874bcba6SMarcus Wolf /* wait for RSSI level to become high */ 446874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: going to wait for high RSSI level"); 447874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->rx_wait_queue, 448874bcba6SMarcus Wolf rf69_get_flag(dev->spi, 449874bcba6SMarcus Wolf rssiExceededThreshold)); 4506b167a67SValentin Vidic if (retval) /* wait was interrupted */ 4516b167a67SValentin Vidic goto abort; 452874bcba6SMarcus Wolf dev->interrupt_rx_allowed = false; 453874bcba6SMarcus Wolf 454874bcba6SMarcus Wolf /* cross check for ongoing tx */ 4556b167a67SValentin Vidic if (!dev->tx_active) 4566b167a67SValentin Vidic break; 457874bcba6SMarcus Wolf } 458874bcba6SMarcus Wolf 459874bcba6SMarcus Wolf /* configure payload ready irq */ 460038a5b4eSNguyen Phan Quang Minh retval = rf69_set_dio_mapping(spi, DIO0, DIO_PAYLOAD_READY); 461038a5b4eSNguyen Phan Quang Minh if (retval < 0) 462038a5b4eSNguyen Phan Quang Minh goto abort; 4633d7f3bf2SSimon Sandström dev->irq_state[DIO0] = DIO_PAYLOAD_READY; 464874bcba6SMarcus Wolf irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); 465874bcba6SMarcus Wolf 466874bcba6SMarcus Wolf /* fixed or unlimited length? */ 46791086b82SValentin Vidic if (dev->rx_cfg.fixed_message_length != 0) { 46891086b82SValentin Vidic if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size) { 469874bcba6SMarcus Wolf retval = -1; 470874bcba6SMarcus Wolf goto abort; 471874bcba6SMarcus Wolf } 472874bcba6SMarcus Wolf bytes_total = dev->rx_cfg.fixed_message_length; 473874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: msg len set to %d by fixed length", bytes_total); 47491086b82SValentin Vidic } else { 475874bcba6SMarcus Wolf bytes_total = dev->rx_buffer_size; 476874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total); 477874bcba6SMarcus Wolf } 478874bcba6SMarcus Wolf 479874bcba6SMarcus Wolf /* length byte enabled? */ 48091086b82SValentin Vidic if (dev->rx_cfg.enable_length_byte == OPTION_ON) { 481874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->fifo_wait_queue, 482874bcba6SMarcus Wolf dev->free_in_fifo < FIFO_SIZE); 4836b167a67SValentin Vidic if (retval) /* wait was interrupted */ 4846b167a67SValentin Vidic goto abort; 485874bcba6SMarcus Wolf 486874bcba6SMarcus Wolf rf69_read_fifo(spi, (u8 *)&bytes_total, 1); 48769af5d92SSrishti Sharma if (bytes_total > dev->rx_buffer_size) { 488874bcba6SMarcus Wolf retval = -1; 489874bcba6SMarcus Wolf goto abort; 490874bcba6SMarcus Wolf } 491874bcba6SMarcus Wolf dev->free_in_fifo++; 492874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total); 493874bcba6SMarcus Wolf } 494874bcba6SMarcus Wolf 495874bcba6SMarcus Wolf /* address byte enabled? */ 49691086b82SValentin Vidic if (dev->rx_cfg.enable_address_filtering != filteringOff) { 497874bcba6SMarcus Wolf u8 dummy; 498874bcba6SMarcus Wolf 499874bcba6SMarcus Wolf bytes_total--; 500874bcba6SMarcus Wolf 501874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->fifo_wait_queue, 502874bcba6SMarcus Wolf dev->free_in_fifo < FIFO_SIZE); 5036b167a67SValentin Vidic if (retval) /* wait was interrupted */ 5046b167a67SValentin Vidic goto abort; 505874bcba6SMarcus Wolf 506874bcba6SMarcus Wolf rf69_read_fifo(spi, &dummy, 1); 507874bcba6SMarcus Wolf dev->free_in_fifo++; 508874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: address byte stripped off"); 509874bcba6SMarcus Wolf } 510874bcba6SMarcus Wolf 511874bcba6SMarcus Wolf /* get payload */ 51291086b82SValentin Vidic while (dev->rx_position < bytes_total) { 51391086b82SValentin Vidic if (!rf69_get_flag(dev->spi, payloadReady)) { 514874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->fifo_wait_queue, 515874bcba6SMarcus Wolf dev->free_in_fifo < FIFO_SIZE); 5166b167a67SValentin Vidic if (retval) /* wait was interrupted */ 5176b167a67SValentin Vidic goto abort; 518874bcba6SMarcus Wolf } 519874bcba6SMarcus Wolf 520874bcba6SMarcus Wolf /* need to drop bytes or acquire? */ 521874bcba6SMarcus Wolf if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) 522874bcba6SMarcus Wolf bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped; 523874bcba6SMarcus Wolf else 524874bcba6SMarcus Wolf bytes_to_read = bytes_total - dev->rx_position; 525874bcba6SMarcus Wolf 526874bcba6SMarcus Wolf /* access the fifo */ 527874bcba6SMarcus Wolf if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo) 528874bcba6SMarcus Wolf bytes_to_read = FIFO_SIZE - dev->free_in_fifo; 529874bcba6SMarcus Wolf retval = rf69_read_fifo(spi, 530874bcba6SMarcus Wolf &dev->rx_buffer[dev->rx_position], 531874bcba6SMarcus Wolf bytes_to_read); 5326b167a67SValentin Vidic if (retval) /* read failed */ 5336b167a67SValentin Vidic goto abort; 5346b167a67SValentin Vidic 535874bcba6SMarcus Wolf dev->free_in_fifo += bytes_to_read; 536874bcba6SMarcus Wolf 537874bcba6SMarcus Wolf /* adjust status vars */ 538874bcba6SMarcus Wolf if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) 539874bcba6SMarcus Wolf dev->rx_bytes_dropped += bytes_to_read; 540874bcba6SMarcus Wolf else 541874bcba6SMarcus Wolf dev->rx_position += bytes_to_read; 542874bcba6SMarcus Wolf } 543874bcba6SMarcus Wolf 5442ebd34caSHarsha Sharma /* rx done, wait was interrupted or error occurred */ 545874bcba6SMarcus Wolf abort: 546874bcba6SMarcus Wolf dev->interrupt_rx_allowed = true; 547038a5b4eSNguyen Phan Quang Minh if (rf69_set_mode(dev->spi, standby)) 548038a5b4eSNguyen Phan Quang Minh pr_err("rf69_set_mode(): radio module failed to go standby\n"); 549874bcba6SMarcus Wolf wake_up_interruptible(&dev->tx_wait_queue); 550874bcba6SMarcus Wolf 551874bcba6SMarcus Wolf if (retval) 552874bcba6SMarcus Wolf return retval; 553874bcba6SMarcus Wolf else 554874bcba6SMarcus Wolf return bytes_total; 555874bcba6SMarcus Wolf } 556874bcba6SMarcus Wolf 5577de77a39SJoseph Wright static int 558874bcba6SMarcus Wolf pi433_tx_thread(void *data) 559874bcba6SMarcus Wolf { 560874bcba6SMarcus Wolf struct pi433_device *device = data; 561038a5b4eSNguyen Phan Quang Minh struct spi_device *spi = device->spi; 562874bcba6SMarcus Wolf struct pi433_tx_cfg tx_cfg; 563874bcba6SMarcus Wolf size_t size; 564874bcba6SMarcus Wolf bool rx_interrupted = false; 565874bcba6SMarcus Wolf int position, repetitions; 566874bcba6SMarcus Wolf int retval; 567874bcba6SMarcus Wolf 56891086b82SValentin Vidic while (1) { 569874bcba6SMarcus Wolf /* wait for fifo to be populated or for request to terminate*/ 570874bcba6SMarcus Wolf dev_dbg(device->dev, "thread: going to wait for new messages"); 571874bcba6SMarcus Wolf wait_event_interruptible(device->tx_wait_queue, 572874bcba6SMarcus Wolf (!kfifo_is_empty(&device->tx_fifo) || 573874bcba6SMarcus Wolf kthread_should_stop())); 574874bcba6SMarcus Wolf if (kthread_should_stop()) 575874bcba6SMarcus Wolf return 0; 576874bcba6SMarcus Wolf 577874bcba6SMarcus Wolf /* get data from fifo in the following order: 578056eeda2SDerek Robson * - tx_cfg 579056eeda2SDerek Robson * - size of message 580056eeda2SDerek Robson * - message 581056eeda2SDerek Robson */ 582874bcba6SMarcus Wolf mutex_lock(&device->tx_fifo_lock); 583874bcba6SMarcus Wolf 584874bcba6SMarcus Wolf retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg)); 58569af5d92SSrishti Sharma if (retval != sizeof(tx_cfg)) { 586874bcba6SMarcus Wolf dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg)); 587874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 588874bcba6SMarcus Wolf continue; 589874bcba6SMarcus Wolf } 590874bcba6SMarcus Wolf 591874bcba6SMarcus Wolf retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t)); 59269af5d92SSrishti Sharma if (retval != sizeof(size_t)) { 593874bcba6SMarcus Wolf dev_dbg(device->dev, "reading msg size from fifo failed: got %d, expected %d", retval, (unsigned int)sizeof(size_t)); 594874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 595874bcba6SMarcus Wolf continue; 596874bcba6SMarcus Wolf } 597874bcba6SMarcus Wolf 598874bcba6SMarcus Wolf /* use fixed message length, if requested */ 599874bcba6SMarcus Wolf if (tx_cfg.fixed_message_length != 0) 600874bcba6SMarcus Wolf size = tx_cfg.fixed_message_length; 601874bcba6SMarcus Wolf 602874bcba6SMarcus Wolf /* increase size, if len byte is requested */ 603d423c809SSimon Sandström if (tx_cfg.enable_length_byte == OPTION_ON) 604874bcba6SMarcus Wolf size++; 605874bcba6SMarcus Wolf 606874bcba6SMarcus Wolf /* increase size, if adr byte is requested */ 607d423c809SSimon Sandström if (tx_cfg.enable_address_byte == OPTION_ON) 608874bcba6SMarcus Wolf size++; 609874bcba6SMarcus Wolf 610874bcba6SMarcus Wolf /* prime buffer */ 611da3761feSMarcus Wolf memset(device->buffer, 0, size); 612874bcba6SMarcus Wolf position = 0; 613874bcba6SMarcus Wolf 614874bcba6SMarcus Wolf /* add length byte, if requested */ 615d423c809SSimon Sandström if (tx_cfg.enable_length_byte == OPTION_ON) 616da3761feSMarcus Wolf device->buffer[position++] = size - 1; /* according to spec length byte itself must be excluded from the length calculation */ 617874bcba6SMarcus Wolf 618874bcba6SMarcus Wolf /* add adr byte, if requested */ 619d423c809SSimon Sandström if (tx_cfg.enable_address_byte == OPTION_ON) 620da3761feSMarcus Wolf device->buffer[position++] = tx_cfg.address_byte; 621874bcba6SMarcus Wolf 622874bcba6SMarcus Wolf /* finally get message data from fifo */ 623da3761feSMarcus Wolf retval = kfifo_out(&device->tx_fifo, &device->buffer[position], sizeof(device->buffer) - position); 624874bcba6SMarcus Wolf dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval); 625874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 626874bcba6SMarcus Wolf 627874bcba6SMarcus Wolf /* if rx is active, we need to interrupt the waiting for 628056eeda2SDerek Robson * incoming telegrams, to be able to send something. 629056eeda2SDerek Robson * We are only allowed, if currently no reception takes 630056eeda2SDerek Robson * place otherwise we need to wait for the incoming telegram 631056eeda2SDerek Robson * to finish 632056eeda2SDerek Robson */ 633874bcba6SMarcus Wolf wait_event_interruptible(device->tx_wait_queue, 634874bcba6SMarcus Wolf !device->rx_active || 6352b3943b3SValentin Vidic device->interrupt_rx_allowed); 636874bcba6SMarcus Wolf 637874bcba6SMarcus Wolf /* prevent race conditions 638056eeda2SDerek Robson * irq will be reenabled after tx config is set 639056eeda2SDerek Robson */ 640874bcba6SMarcus Wolf disable_irq(device->irq_num[DIO0]); 641874bcba6SMarcus Wolf device->tx_active = true; 642874bcba6SMarcus Wolf 643de71b5bdSValentin Vidic if (device->rx_active && !rx_interrupted) { 644874bcba6SMarcus Wolf /* rx is currently waiting for a telegram; 645056eeda2SDerek Robson * we need to set the radio module to standby 646056eeda2SDerek Robson */ 647038a5b4eSNguyen Phan Quang Minh retval = rf69_set_mode(device->spi, standby); 648038a5b4eSNguyen Phan Quang Minh if (retval < 0) 649038a5b4eSNguyen Phan Quang Minh return retval; 650874bcba6SMarcus Wolf rx_interrupted = true; 651874bcba6SMarcus Wolf } 652874bcba6SMarcus Wolf 653874bcba6SMarcus Wolf /* clear fifo, set fifo threshold, set payload length */ 654038a5b4eSNguyen Phan Quang Minh retval = rf69_set_mode(spi, standby); /* this clears the fifo */ 655038a5b4eSNguyen Phan Quang Minh if (retval < 0) 656038a5b4eSNguyen Phan Quang Minh return retval; 657038a5b4eSNguyen Phan Quang Minh retval = rf69_set_fifo_threshold(spi, FIFO_THRESHOLD); 658038a5b4eSNguyen Phan Quang Minh if (retval < 0) 659038a5b4eSNguyen Phan Quang Minh return retval; 66091086b82SValentin Vidic if (tx_cfg.enable_length_byte == OPTION_ON) { 661038a5b4eSNguyen Phan Quang Minh retval = rf69_set_payload_length(spi, size * tx_cfg.repetitions); 662038a5b4eSNguyen Phan Quang Minh if (retval < 0) 663038a5b4eSNguyen Phan Quang Minh return retval; 66491086b82SValentin Vidic } else { 665038a5b4eSNguyen Phan Quang Minh retval = rf69_set_payload_length(spi, 0); 666038a5b4eSNguyen Phan Quang Minh if (retval < 0) 667038a5b4eSNguyen Phan Quang Minh return retval; 668874bcba6SMarcus Wolf } 669874bcba6SMarcus Wolf 670874bcba6SMarcus Wolf /* configure the rf chip */ 671038a5b4eSNguyen Phan Quang Minh retval = rf69_set_tx_cfg(device, &tx_cfg); 672038a5b4eSNguyen Phan Quang Minh if (retval < 0) 673038a5b4eSNguyen Phan Quang Minh return retval; 674874bcba6SMarcus Wolf 675874bcba6SMarcus Wolf /* enable fifo level interrupt */ 676038a5b4eSNguyen Phan Quang Minh retval = rf69_set_dio_mapping(spi, DIO1, DIO_FIFO_LEVEL); 677038a5b4eSNguyen Phan Quang Minh if (retval < 0) 678038a5b4eSNguyen Phan Quang Minh return retval; 6793d7f3bf2SSimon Sandström device->irq_state[DIO1] = DIO_FIFO_LEVEL; 680874bcba6SMarcus Wolf irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING); 681874bcba6SMarcus Wolf 682874bcba6SMarcus Wolf /* enable packet sent interrupt */ 683038a5b4eSNguyen Phan Quang Minh retval = rf69_set_dio_mapping(spi, DIO0, DIO_PACKET_SENT); 684038a5b4eSNguyen Phan Quang Minh if (retval < 0) 685038a5b4eSNguyen Phan Quang Minh return retval; 6863d7f3bf2SSimon Sandström device->irq_state[DIO0] = DIO_PACKET_SENT; 687874bcba6SMarcus Wolf irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); 688874bcba6SMarcus Wolf enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check */ 689874bcba6SMarcus Wolf 690874bcba6SMarcus Wolf /* enable transmission */ 691038a5b4eSNguyen Phan Quang Minh retval = rf69_set_mode(spi, transmit); 692038a5b4eSNguyen Phan Quang Minh if (retval < 0) 693038a5b4eSNguyen Phan Quang Minh return retval; 694874bcba6SMarcus Wolf 695874bcba6SMarcus Wolf /* transfer this msg (and repetitions) to chip fifo */ 696874bcba6SMarcus Wolf device->free_in_fifo = FIFO_SIZE; 697874bcba6SMarcus Wolf position = 0; 698874bcba6SMarcus Wolf repetitions = tx_cfg.repetitions; 69991086b82SValentin Vidic while ((repetitions > 0) && (size > position)) { 70091086b82SValentin Vidic if ((size - position) > device->free_in_fifo) { 70191086b82SValentin Vidic /* msg to big for fifo - take a part */ 702874bcba6SMarcus Wolf int temp = device->free_in_fifo; 703874bcba6SMarcus Wolf device->free_in_fifo = 0; 704874bcba6SMarcus Wolf rf69_write_fifo(spi, 705da3761feSMarcus Wolf &device->buffer[position], 706874bcba6SMarcus Wolf temp); 707874bcba6SMarcus Wolf position += temp; 70891086b82SValentin Vidic } else { 70991086b82SValentin Vidic /* msg fits into fifo - take all */ 710874bcba6SMarcus Wolf device->free_in_fifo -= size; 711874bcba6SMarcus Wolf repetitions--; 712874bcba6SMarcus Wolf rf69_write_fifo(spi, 713da3761feSMarcus Wolf &device->buffer[position], 714874bcba6SMarcus Wolf (size - position)); 715874bcba6SMarcus Wolf position = 0; /* reset for next repetition */ 716874bcba6SMarcus Wolf } 717874bcba6SMarcus Wolf 718874bcba6SMarcus Wolf retval = wait_event_interruptible(device->fifo_wait_queue, 719874bcba6SMarcus Wolf device->free_in_fifo > 0); 7206b167a67SValentin Vidic if (retval) { 7216b167a67SValentin Vidic printk("ABORT\n"); 7226b167a67SValentin Vidic goto abort; 7236b167a67SValentin Vidic } 724874bcba6SMarcus Wolf } 725874bcba6SMarcus Wolf 726874bcba6SMarcus Wolf /* we are done. Wait for packet to get sent */ 72728eb8555SColin Ian King dev_dbg(device->dev, "thread: wait for packet to get sent/fifo to be empty"); 728874bcba6SMarcus Wolf wait_event_interruptible(device->fifo_wait_queue, 729874bcba6SMarcus Wolf device->free_in_fifo == FIFO_SIZE || 730874bcba6SMarcus Wolf kthread_should_stop()); 7316b167a67SValentin Vidic if (kthread_should_stop()) 7326b167a67SValentin Vidic printk("ABORT\n"); 733874bcba6SMarcus Wolf 734874bcba6SMarcus Wolf /* STOP_TRANSMISSION */ 735874bcba6SMarcus Wolf dev_dbg(device->dev, "thread: Packet sent. Set mode to stby."); 736038a5b4eSNguyen Phan Quang Minh retval = rf69_set_mode(spi, standby); 737038a5b4eSNguyen Phan Quang Minh if (retval < 0) 738038a5b4eSNguyen Phan Quang Minh return retval; 739874bcba6SMarcus Wolf 740874bcba6SMarcus Wolf /* everything sent? */ 74169af5d92SSrishti Sharma if (kfifo_is_empty(&device->tx_fifo)) { 742874bcba6SMarcus Wolf abort: 74391086b82SValentin Vidic if (rx_interrupted) { 744874bcba6SMarcus Wolf rx_interrupted = false; 745874bcba6SMarcus Wolf pi433_start_rx(device); 746874bcba6SMarcus Wolf } 747874bcba6SMarcus Wolf device->tx_active = false; 748874bcba6SMarcus Wolf wake_up_interruptible(&device->rx_wait_queue); 749874bcba6SMarcus Wolf } 750874bcba6SMarcus Wolf } 751874bcba6SMarcus Wolf } 752874bcba6SMarcus Wolf 753874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 754874bcba6SMarcus Wolf 755874bcba6SMarcus Wolf static ssize_t 756874bcba6SMarcus Wolf pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos) 757874bcba6SMarcus Wolf { 758874bcba6SMarcus Wolf struct pi433_instance *instance; 759874bcba6SMarcus Wolf struct pi433_device *device; 760874bcba6SMarcus Wolf int bytes_received; 761874bcba6SMarcus Wolf ssize_t retval; 762874bcba6SMarcus Wolf 763874bcba6SMarcus Wolf /* check, whether internal buffer is big enough for requested size */ 764874bcba6SMarcus Wolf if (size > MAX_MSG_SIZE) 765874bcba6SMarcus Wolf return -EMSGSIZE; 766874bcba6SMarcus Wolf 767874bcba6SMarcus Wolf instance = filp->private_data; 768874bcba6SMarcus Wolf device = instance->device; 769874bcba6SMarcus Wolf 770874bcba6SMarcus Wolf /* just one read request at a time */ 771874bcba6SMarcus Wolf mutex_lock(&device->rx_lock); 77291086b82SValentin Vidic if (device->rx_active) { 773874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 774874bcba6SMarcus Wolf return -EAGAIN; 77583e3e2efSValentin Vidic } 77683e3e2efSValentin Vidic 777874bcba6SMarcus Wolf device->rx_active = true; 778874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 779874bcba6SMarcus Wolf 780874bcba6SMarcus Wolf /* start receiving */ 781874bcba6SMarcus Wolf /* will block until something was received*/ 782874bcba6SMarcus Wolf device->rx_buffer_size = size; 783874bcba6SMarcus Wolf bytes_received = pi433_receive(device); 784874bcba6SMarcus Wolf 785874bcba6SMarcus Wolf /* release rx */ 786874bcba6SMarcus Wolf mutex_lock(&device->rx_lock); 787874bcba6SMarcus Wolf device->rx_active = false; 788874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 789874bcba6SMarcus Wolf 790874bcba6SMarcus Wolf /* if read was successful copy to user space*/ 79169af5d92SSrishti Sharma if (bytes_received > 0) { 792874bcba6SMarcus Wolf retval = copy_to_user(buf, device->rx_buffer, bytes_received); 793874bcba6SMarcus Wolf if (retval) 79439ae5f1eSdan.carpenter@oracle.com return -EFAULT; 795874bcba6SMarcus Wolf } 796874bcba6SMarcus Wolf 797874bcba6SMarcus Wolf return bytes_received; 798874bcba6SMarcus Wolf } 799874bcba6SMarcus Wolf 800874bcba6SMarcus Wolf static ssize_t 801874bcba6SMarcus Wolf pi433_write(struct file *filp, const char __user *buf, 802874bcba6SMarcus Wolf size_t count, loff_t *f_pos) 803874bcba6SMarcus Wolf { 804874bcba6SMarcus Wolf struct pi433_instance *instance; 805874bcba6SMarcus Wolf struct pi433_device *device; 80657f8965aSStefano Manni int retval; 80757f8965aSStefano Manni unsigned int copied; 808874bcba6SMarcus Wolf 809874bcba6SMarcus Wolf instance = filp->private_data; 810874bcba6SMarcus Wolf device = instance->device; 811874bcba6SMarcus Wolf 812874bcba6SMarcus Wolf /* check, whether internal buffer (tx thread) is big enough for requested size */ 813874bcba6SMarcus Wolf if (count > MAX_MSG_SIZE) 814874bcba6SMarcus Wolf return -EMSGSIZE; 815874bcba6SMarcus Wolf 816874bcba6SMarcus Wolf /* write the following sequence into fifo: 817056eeda2SDerek Robson * - tx_cfg 818056eeda2SDerek Robson * - size of message 819056eeda2SDerek Robson * - message 820056eeda2SDerek Robson */ 821874bcba6SMarcus Wolf mutex_lock(&device->tx_fifo_lock); 822874bcba6SMarcus Wolf retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg)); 823874bcba6SMarcus Wolf if (retval != sizeof(instance->tx_cfg)) 824874bcba6SMarcus Wolf goto abort; 825874bcba6SMarcus Wolf 826874bcba6SMarcus Wolf retval = kfifo_in(&device->tx_fifo, &count, sizeof(size_t)); 827874bcba6SMarcus Wolf if (retval != sizeof(size_t)) 828874bcba6SMarcus Wolf goto abort; 829874bcba6SMarcus Wolf 830874bcba6SMarcus Wolf retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied); 831874bcba6SMarcus Wolf if (retval || copied != count) 832874bcba6SMarcus Wolf goto abort; 833874bcba6SMarcus Wolf 834874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 835874bcba6SMarcus Wolf 836874bcba6SMarcus Wolf /* start transfer */ 837874bcba6SMarcus Wolf wake_up_interruptible(&device->tx_wait_queue); 838874bcba6SMarcus Wolf dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied); 839874bcba6SMarcus Wolf 840874bcba6SMarcus Wolf return 0; 841874bcba6SMarcus Wolf 842874bcba6SMarcus Wolf abort: 843874bcba6SMarcus Wolf dev_dbg(device->dev, "write to fifo failed: 0x%x", retval); 844874bcba6SMarcus Wolf kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to discard already stored, valid entries 845874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 846874bcba6SMarcus Wolf return -EAGAIN; 847874bcba6SMarcus Wolf } 848874bcba6SMarcus Wolf 849874bcba6SMarcus Wolf static long 850874bcba6SMarcus Wolf pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 851874bcba6SMarcus Wolf { 852874bcba6SMarcus Wolf int retval = 0; 853874bcba6SMarcus Wolf struct pi433_instance *instance; 854874bcba6SMarcus Wolf struct pi433_device *device; 85550271d38SAl Viro void __user *argp = (void __user *)arg; 856874bcba6SMarcus Wolf 857874bcba6SMarcus Wolf /* Check type and command number */ 858874bcba6SMarcus Wolf if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC) 859874bcba6SMarcus Wolf return -ENOTTY; 860874bcba6SMarcus Wolf 861874bcba6SMarcus Wolf /* TODO? guard against device removal before, or while, 862874bcba6SMarcus Wolf * we issue this ioctl. --> device_get() 863874bcba6SMarcus Wolf */ 864874bcba6SMarcus Wolf instance = filp->private_data; 865874bcba6SMarcus Wolf device = instance->device; 866874bcba6SMarcus Wolf 86716fdcc7bSValentin Vidic if (!device) 868874bcba6SMarcus Wolf return -ESHUTDOWN; 869874bcba6SMarcus Wolf 870874bcba6SMarcus Wolf switch (cmd) { 871874bcba6SMarcus Wolf case PI433_IOC_RD_TX_CFG: 87250271d38SAl Viro if (copy_to_user(argp, &instance->tx_cfg, 87350271d38SAl Viro sizeof(struct pi433_tx_cfg))) 87450271d38SAl Viro return -EFAULT; 875874bcba6SMarcus Wolf break; 876874bcba6SMarcus Wolf case PI433_IOC_WR_TX_CFG: 87750271d38SAl Viro if (copy_from_user(&instance->tx_cfg, argp, 87850271d38SAl Viro sizeof(struct pi433_tx_cfg))) 87950271d38SAl Viro return -EFAULT; 880874bcba6SMarcus Wolf break; 881874bcba6SMarcus Wolf case PI433_IOC_RD_RX_CFG: 88250271d38SAl Viro if (copy_to_user(argp, &device->rx_cfg, 88350271d38SAl Viro sizeof(struct pi433_rx_cfg))) 88450271d38SAl Viro return -EFAULT; 885874bcba6SMarcus Wolf break; 886874bcba6SMarcus Wolf case PI433_IOC_WR_RX_CFG: 887874bcba6SMarcus Wolf mutex_lock(&device->rx_lock); 888874bcba6SMarcus Wolf 889874bcba6SMarcus Wolf /* during pendig read request, change of config not allowed */ 890874bcba6SMarcus Wolf if (device->rx_active) { 891874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 89250271d38SAl Viro return -EAGAIN; 893874bcba6SMarcus Wolf } 894874bcba6SMarcus Wolf 89550271d38SAl Viro if (copy_from_user(&device->rx_cfg, argp, 89650271d38SAl Viro sizeof(struct pi433_rx_cfg))) { 897874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 89850271d38SAl Viro return -EFAULT; 899874bcba6SMarcus Wolf } 900874bcba6SMarcus Wolf 901874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 902874bcba6SMarcus Wolf break; 903874bcba6SMarcus Wolf default: 904874bcba6SMarcus Wolf retval = -EINVAL; 905874bcba6SMarcus Wolf } 906874bcba6SMarcus Wolf 907874bcba6SMarcus Wolf return retval; 908874bcba6SMarcus Wolf } 909874bcba6SMarcus Wolf 910874bcba6SMarcus Wolf #ifdef CONFIG_COMPAT 911874bcba6SMarcus Wolf static long 912874bcba6SMarcus Wolf pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 913874bcba6SMarcus Wolf { 914874bcba6SMarcus Wolf return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); 915874bcba6SMarcus Wolf } 916874bcba6SMarcus Wolf #else 917874bcba6SMarcus Wolf #define pi433_compat_ioctl NULL 918874bcba6SMarcus Wolf #endif /* CONFIG_COMPAT */ 919874bcba6SMarcus Wolf 920874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 921874bcba6SMarcus Wolf 922874bcba6SMarcus Wolf static int pi433_open(struct inode *inode, struct file *filp) 923874bcba6SMarcus Wolf { 924874bcba6SMarcus Wolf struct pi433_device *device; 925874bcba6SMarcus Wolf struct pi433_instance *instance; 926874bcba6SMarcus Wolf 927874bcba6SMarcus Wolf mutex_lock(&minor_lock); 928874bcba6SMarcus Wolf device = idr_find(&pi433_idr, iminor(inode)); 929874bcba6SMarcus Wolf mutex_unlock(&minor_lock); 930874bcba6SMarcus Wolf if (!device) { 931874bcba6SMarcus Wolf pr_debug("device: minor %d unknown.\n", iminor(inode)); 932874bcba6SMarcus Wolf return -ENODEV; 933874bcba6SMarcus Wolf } 934874bcba6SMarcus Wolf 935874bcba6SMarcus Wolf if (!device->rx_buffer) { 936874bcba6SMarcus Wolf device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL); 93757fa80f5SValentin Vidic if (!device->rx_buffer) 938874bcba6SMarcus Wolf return -ENOMEM; 939874bcba6SMarcus Wolf } 940874bcba6SMarcus Wolf 941874bcba6SMarcus Wolf device->users++; 942874bcba6SMarcus Wolf instance = kzalloc(sizeof(*instance), GFP_KERNEL); 94369af5d92SSrishti Sharma if (!instance) { 944874bcba6SMarcus Wolf kfree(device->rx_buffer); 945874bcba6SMarcus Wolf device->rx_buffer = NULL; 946874bcba6SMarcus Wolf return -ENOMEM; 947874bcba6SMarcus Wolf } 948874bcba6SMarcus Wolf 949874bcba6SMarcus Wolf /* setup instance data*/ 950874bcba6SMarcus Wolf instance->device = device; 951874bcba6SMarcus Wolf instance->tx_cfg.bit_rate = 4711; 952874bcba6SMarcus Wolf // TODO: fill instance->tx_cfg; 953874bcba6SMarcus Wolf 954874bcba6SMarcus Wolf /* instance data as context */ 955874bcba6SMarcus Wolf filp->private_data = instance; 956874bcba6SMarcus Wolf nonseekable_open(inode, filp); 957874bcba6SMarcus Wolf 958874bcba6SMarcus Wolf return 0; 959874bcba6SMarcus Wolf } 960874bcba6SMarcus Wolf 961874bcba6SMarcus Wolf static int pi433_release(struct inode *inode, struct file *filp) 962874bcba6SMarcus Wolf { 963874bcba6SMarcus Wolf struct pi433_instance *instance; 964874bcba6SMarcus Wolf struct pi433_device *device; 965874bcba6SMarcus Wolf 966874bcba6SMarcus Wolf instance = filp->private_data; 967874bcba6SMarcus Wolf device = instance->device; 968874bcba6SMarcus Wolf kfree(instance); 969874bcba6SMarcus Wolf filp->private_data = NULL; 970874bcba6SMarcus Wolf 971874bcba6SMarcus Wolf /* last close? */ 972874bcba6SMarcus Wolf device->users--; 973874bcba6SMarcus Wolf 974874bcba6SMarcus Wolf if (!device->users) { 975874bcba6SMarcus Wolf kfree(device->rx_buffer); 976874bcba6SMarcus Wolf device->rx_buffer = NULL; 97716fdcc7bSValentin Vidic if (!device->spi) 978874bcba6SMarcus Wolf kfree(device); 979874bcba6SMarcus Wolf } 980874bcba6SMarcus Wolf 981874bcba6SMarcus Wolf return 0; 982874bcba6SMarcus Wolf } 983874bcba6SMarcus Wolf 984874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 985874bcba6SMarcus Wolf 986874bcba6SMarcus Wolf static int setup_GPIOs(struct pi433_device *device) 987874bcba6SMarcus Wolf { 988874bcba6SMarcus Wolf char name[5]; 989874bcba6SMarcus Wolf int retval; 990874bcba6SMarcus Wolf int i; 991ee26e236SCihangir Akturk const irq_handler_t DIO_irq_handler[NUM_DIO] = { 992ee26e236SCihangir Akturk DIO0_irq_handler, 993ee26e236SCihangir Akturk DIO1_irq_handler 994ee26e236SCihangir Akturk }; 995874bcba6SMarcus Wolf 996e27de55dSValentin Vidic for (i = 0; i < NUM_DIO; i++) { 997874bcba6SMarcus Wolf /* "construct" name and get the gpio descriptor */ 998874bcba6SMarcus Wolf snprintf(name, sizeof(name), "DIO%d", i); 999874bcba6SMarcus Wolf device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/); 1000874bcba6SMarcus Wolf 100169af5d92SSrishti Sharma if (device->gpiod[i] == ERR_PTR(-ENOENT)) { 1002874bcba6SMarcus Wolf dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name); 1003874bcba6SMarcus Wolf continue; 1004874bcba6SMarcus Wolf } 1005874bcba6SMarcus Wolf 1006874bcba6SMarcus Wolf if (device->gpiod[i] == ERR_PTR(-EBUSY)) 1007874bcba6SMarcus Wolf dev_dbg(&device->spi->dev, "%s is busy.", name); 1008874bcba6SMarcus Wolf 100991086b82SValentin Vidic if (IS_ERR(device->gpiod[i])) { 1010874bcba6SMarcus Wolf retval = PTR_ERR(device->gpiod[i]); 1011874bcba6SMarcus Wolf /* release already allocated gpios */ 1012c976752eSOliver Graute for (i--; i >= 0; i--) { 1013874bcba6SMarcus Wolf free_irq(device->irq_num[i], device); 1014874bcba6SMarcus Wolf gpiod_put(device->gpiod[i]); 1015874bcba6SMarcus Wolf } 1016874bcba6SMarcus Wolf return retval; 1017874bcba6SMarcus Wolf } 1018874bcba6SMarcus Wolf 1019874bcba6SMarcus Wolf /* configure the pin */ 1020874bcba6SMarcus Wolf gpiod_unexport(device->gpiod[i]); 1021874bcba6SMarcus Wolf retval = gpiod_direction_input(device->gpiod[i]); 10226b167a67SValentin Vidic if (retval) 10236b167a67SValentin Vidic return retval; 1024874bcba6SMarcus Wolf 1025874bcba6SMarcus Wolf /* configure irq */ 1026874bcba6SMarcus Wolf device->irq_num[i] = gpiod_to_irq(device->gpiod[i]); 102769af5d92SSrishti Sharma if (device->irq_num[i] < 0) { 1028874bcba6SMarcus Wolf device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc *)device->irq_num[i]; 1029874bcba6SMarcus Wolf return device->irq_num[i]; 1030874bcba6SMarcus Wolf } 1031874bcba6SMarcus Wolf retval = request_irq(device->irq_num[i], 1032874bcba6SMarcus Wolf DIO_irq_handler[i], 1033874bcba6SMarcus Wolf 0, /* flags */ 1034874bcba6SMarcus Wolf name, 1035874bcba6SMarcus Wolf device); 1036874bcba6SMarcus Wolf 1037874bcba6SMarcus Wolf if (retval) 1038874bcba6SMarcus Wolf return retval; 1039874bcba6SMarcus Wolf 10402ebd34caSHarsha Sharma dev_dbg(&device->spi->dev, "%s successfully configured", name); 1041874bcba6SMarcus Wolf } 1042874bcba6SMarcus Wolf 1043874bcba6SMarcus Wolf return 0; 1044874bcba6SMarcus Wolf } 1045874bcba6SMarcus Wolf 1046874bcba6SMarcus Wolf static void free_GPIOs(struct pi433_device *device) 1047874bcba6SMarcus Wolf { 1048874bcba6SMarcus Wolf int i; 1049874bcba6SMarcus Wolf 105091086b82SValentin Vidic for (i = 0; i < NUM_DIO; i++) { 1051874bcba6SMarcus Wolf /* check if gpiod is valid */ 1052874bcba6SMarcus Wolf if (IS_ERR(device->gpiod[i])) 1053874bcba6SMarcus Wolf continue; 1054874bcba6SMarcus Wolf 1055874bcba6SMarcus Wolf free_irq(device->irq_num[i], device); 1056874bcba6SMarcus Wolf gpiod_put(device->gpiod[i]); 1057874bcba6SMarcus Wolf } 1058874bcba6SMarcus Wolf } 1059874bcba6SMarcus Wolf 1060874bcba6SMarcus Wolf static int pi433_get_minor(struct pi433_device *device) 1061874bcba6SMarcus Wolf { 1062874bcba6SMarcus Wolf int retval = -ENOMEM; 1063874bcba6SMarcus Wolf 1064874bcba6SMarcus Wolf mutex_lock(&minor_lock); 1065874bcba6SMarcus Wolf retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL); 1066874bcba6SMarcus Wolf if (retval >= 0) { 1067874bcba6SMarcus Wolf device->minor = retval; 1068874bcba6SMarcus Wolf retval = 0; 1069874bcba6SMarcus Wolf } else if (retval == -ENOSPC) { 1070d2cb4845SMarcin Ciupak dev_err(&device->spi->dev, "too many pi433 devices\n"); 1071874bcba6SMarcus Wolf retval = -EINVAL; 1072874bcba6SMarcus Wolf } 1073874bcba6SMarcus Wolf mutex_unlock(&minor_lock); 1074874bcba6SMarcus Wolf return retval; 1075874bcba6SMarcus Wolf } 1076874bcba6SMarcus Wolf 1077874bcba6SMarcus Wolf static void pi433_free_minor(struct pi433_device *dev) 1078874bcba6SMarcus Wolf { 1079874bcba6SMarcus Wolf mutex_lock(&minor_lock); 1080874bcba6SMarcus Wolf idr_remove(&pi433_idr, dev->minor); 1081874bcba6SMarcus Wolf mutex_unlock(&minor_lock); 1082874bcba6SMarcus Wolf } 1083c144df8dSValentin Vidic 1084874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 1085874bcba6SMarcus Wolf 1086874bcba6SMarcus Wolf static const struct file_operations pi433_fops = { 1087874bcba6SMarcus Wolf .owner = THIS_MODULE, 1088874bcba6SMarcus Wolf /* REVISIT switch to aio primitives, so that userspace 1089874bcba6SMarcus Wolf * gets more complete API coverage. It'll simplify things 1090874bcba6SMarcus Wolf * too, except for the locking. 1091874bcba6SMarcus Wolf */ 1092874bcba6SMarcus Wolf .write = pi433_write, 1093874bcba6SMarcus Wolf .read = pi433_read, 1094874bcba6SMarcus Wolf .unlocked_ioctl = pi433_ioctl, 1095874bcba6SMarcus Wolf .compat_ioctl = pi433_compat_ioctl, 1096874bcba6SMarcus Wolf .open = pi433_open, 1097874bcba6SMarcus Wolf .release = pi433_release, 1098874bcba6SMarcus Wolf .llseek = no_llseek, 1099874bcba6SMarcus Wolf }; 1100874bcba6SMarcus Wolf 1101874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 1102874bcba6SMarcus Wolf 1103874bcba6SMarcus Wolf static int pi433_probe(struct spi_device *spi) 1104874bcba6SMarcus Wolf { 1105874bcba6SMarcus Wolf struct pi433_device *device; 1106874bcba6SMarcus Wolf int retval; 1107874bcba6SMarcus Wolf 1108874bcba6SMarcus Wolf /* setup spi parameters */ 1109874bcba6SMarcus Wolf spi->mode = 0x00; 1110874bcba6SMarcus Wolf spi->bits_per_word = 8; 1111874bcba6SMarcus Wolf /* spi->max_speed_hz = 10000000; 1MHz already set by device tree overlay */ 1112874bcba6SMarcus Wolf 1113874bcba6SMarcus Wolf retval = spi_setup(spi); 111491086b82SValentin Vidic if (retval) { 1115874bcba6SMarcus Wolf dev_dbg(&spi->dev, "configuration of SPI interface failed!\n"); 1116874bcba6SMarcus Wolf return retval; 111783e3e2efSValentin Vidic } 111883e3e2efSValentin Vidic 1119874bcba6SMarcus Wolf dev_dbg(&spi->dev, 1120874bcba6SMarcus Wolf "spi interface setup: mode 0x%2x, %d bits per word, %dhz max speed", 1121874bcba6SMarcus Wolf spi->mode, spi->bits_per_word, spi->max_speed_hz); 1122874bcba6SMarcus Wolf 1123874bcba6SMarcus Wolf /* Ping the chip by reading the version register */ 1124874bcba6SMarcus Wolf retval = spi_w8r8(spi, 0x10); 1125874bcba6SMarcus Wolf if (retval < 0) 1126874bcba6SMarcus Wolf return retval; 1127874bcba6SMarcus Wolf 11286feb5c82SXiangyang Zhang switch (retval) { 1129874bcba6SMarcus Wolf case 0x24: 113028eb8555SColin Ian King dev_dbg(&spi->dev, "found pi433 (ver. 0x%x)", retval); 1131874bcba6SMarcus Wolf break; 1132874bcba6SMarcus Wolf default: 1133874bcba6SMarcus Wolf dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval); 1134874bcba6SMarcus Wolf return -ENODEV; 1135874bcba6SMarcus Wolf } 1136874bcba6SMarcus Wolf 1137874bcba6SMarcus Wolf /* Allocate driver data */ 1138874bcba6SMarcus Wolf device = kzalloc(sizeof(*device), GFP_KERNEL); 1139874bcba6SMarcus Wolf if (!device) 1140874bcba6SMarcus Wolf return -ENOMEM; 1141874bcba6SMarcus Wolf 1142874bcba6SMarcus Wolf /* Initialize the driver data */ 1143874bcba6SMarcus Wolf device->spi = spi; 1144874bcba6SMarcus Wolf device->rx_active = false; 1145874bcba6SMarcus Wolf device->tx_active = false; 1146874bcba6SMarcus Wolf device->interrupt_rx_allowed = false; 1147874bcba6SMarcus Wolf 1148874bcba6SMarcus Wolf /* init wait queues */ 1149874bcba6SMarcus Wolf init_waitqueue_head(&device->tx_wait_queue); 1150874bcba6SMarcus Wolf init_waitqueue_head(&device->rx_wait_queue); 1151874bcba6SMarcus Wolf init_waitqueue_head(&device->fifo_wait_queue); 1152874bcba6SMarcus Wolf 1153874bcba6SMarcus Wolf /* init fifo */ 1154874bcba6SMarcus Wolf INIT_KFIFO(device->tx_fifo); 1155874bcba6SMarcus Wolf 1156874bcba6SMarcus Wolf /* init mutexes and locks */ 1157874bcba6SMarcus Wolf mutex_init(&device->tx_fifo_lock); 1158874bcba6SMarcus Wolf mutex_init(&device->rx_lock); 1159874bcba6SMarcus Wolf 1160874bcba6SMarcus Wolf /* setup GPIO (including irq_handler) for the different DIOs */ 1161874bcba6SMarcus Wolf retval = setup_GPIOs(device); 116269af5d92SSrishti Sharma if (retval) { 1163874bcba6SMarcus Wolf dev_dbg(&spi->dev, "setup of GPIOs failed"); 1164874bcba6SMarcus Wolf goto GPIO_failed; 1165874bcba6SMarcus Wolf } 1166874bcba6SMarcus Wolf 1167874bcba6SMarcus Wolf /* setup the radio module */ 116854fc95a7SSimon Sandström retval = rf69_set_mode(spi, standby); 116954fc95a7SSimon Sandström if (retval < 0) 117054fc95a7SSimon Sandström goto minor_failed; 117154fc95a7SSimon Sandström retval = rf69_set_data_mode(spi, DATAMODUL_MODE_PACKET); 117254fc95a7SSimon Sandström if (retval < 0) 117354fc95a7SSimon Sandström goto minor_failed; 117454fc95a7SSimon Sandström retval = rf69_enable_amplifier(spi, MASK_PALEVEL_PA0); 117554fc95a7SSimon Sandström if (retval < 0) 117654fc95a7SSimon Sandström goto minor_failed; 117754fc95a7SSimon Sandström retval = rf69_disable_amplifier(spi, MASK_PALEVEL_PA1); 117854fc95a7SSimon Sandström if (retval < 0) 117954fc95a7SSimon Sandström goto minor_failed; 118054fc95a7SSimon Sandström retval = rf69_disable_amplifier(spi, MASK_PALEVEL_PA2); 118154fc95a7SSimon Sandström if (retval < 0) 118254fc95a7SSimon Sandström goto minor_failed; 118354fc95a7SSimon Sandström retval = rf69_set_output_power_level(spi, 13); 118454fc95a7SSimon Sandström if (retval < 0) 118554fc95a7SSimon Sandström goto minor_failed; 118654fc95a7SSimon Sandström retval = rf69_set_antenna_impedance(spi, fiftyOhm); 118754fc95a7SSimon Sandström if (retval < 0) 118854fc95a7SSimon Sandström goto minor_failed; 1189874bcba6SMarcus Wolf 1190874bcba6SMarcus Wolf /* determ minor number */ 1191874bcba6SMarcus Wolf retval = pi433_get_minor(device); 119269af5d92SSrishti Sharma if (retval) { 1193d2cb4845SMarcin Ciupak dev_dbg(&spi->dev, "get of minor number failed"); 1194874bcba6SMarcus Wolf goto minor_failed; 1195874bcba6SMarcus Wolf } 1196874bcba6SMarcus Wolf 1197874bcba6SMarcus Wolf /* create device */ 1198874bcba6SMarcus Wolf device->devt = MKDEV(MAJOR(pi433_dev), device->minor); 1199874bcba6SMarcus Wolf device->dev = device_create(pi433_class, 1200874bcba6SMarcus Wolf &spi->dev, 1201874bcba6SMarcus Wolf device->devt, 1202874bcba6SMarcus Wolf device, 120399ee4774SMarcin Ciupak "pi433.%d", 120499ee4774SMarcin Ciupak device->minor); 1205874bcba6SMarcus Wolf if (IS_ERR(device->dev)) { 1206874bcba6SMarcus Wolf pr_err("pi433: device register failed\n"); 1207874bcba6SMarcus Wolf retval = PTR_ERR(device->dev); 1208874bcba6SMarcus Wolf goto device_create_failed; 120991086b82SValentin Vidic } else { 1210874bcba6SMarcus Wolf dev_dbg(device->dev, 1211874bcba6SMarcus Wolf "created device for major %d, minor %d\n", 1212874bcba6SMarcus Wolf MAJOR(pi433_dev), 1213874bcba6SMarcus Wolf device->minor); 1214874bcba6SMarcus Wolf } 1215874bcba6SMarcus Wolf 1216d2cb4845SMarcin Ciupak /* start tx thread */ 1217d2cb4845SMarcin Ciupak device->tx_task_struct = kthread_run(pi433_tx_thread, 1218d2cb4845SMarcin Ciupak device, 121999ee4774SMarcin Ciupak "pi433.%d_tx_task", 122099ee4774SMarcin Ciupak device->minor); 1221d2cb4845SMarcin Ciupak if (IS_ERR(device->tx_task_struct)) { 1222d2cb4845SMarcin Ciupak dev_dbg(device->dev, "start of send thread failed"); 1223d2cb4845SMarcin Ciupak goto send_thread_failed; 1224d2cb4845SMarcin Ciupak } 1225d2cb4845SMarcin Ciupak 1226874bcba6SMarcus Wolf /* create cdev */ 1227874bcba6SMarcus Wolf device->cdev = cdev_alloc(); 1228874bcba6SMarcus Wolf device->cdev->owner = THIS_MODULE; 1229874bcba6SMarcus Wolf cdev_init(device->cdev, &pi433_fops); 1230874bcba6SMarcus Wolf retval = cdev_add(device->cdev, device->devt, 1); 123169af5d92SSrishti Sharma if (retval) { 1232874bcba6SMarcus Wolf dev_dbg(device->dev, "register of cdev failed"); 1233874bcba6SMarcus Wolf goto cdev_failed; 1234874bcba6SMarcus Wolf } 1235874bcba6SMarcus Wolf 1236874bcba6SMarcus Wolf /* spi setup */ 1237874bcba6SMarcus Wolf spi_set_drvdata(spi, device); 1238874bcba6SMarcus Wolf 1239874bcba6SMarcus Wolf return 0; 1240874bcba6SMarcus Wolf 1241874bcba6SMarcus Wolf cdev_failed: 1242d2cb4845SMarcin Ciupak kthread_stop(device->tx_task_struct); 1243d2cb4845SMarcin Ciupak send_thread_failed: 1244874bcba6SMarcus Wolf device_destroy(pi433_class, device->devt); 1245874bcba6SMarcus Wolf device_create_failed: 1246874bcba6SMarcus Wolf pi433_free_minor(device); 1247874bcba6SMarcus Wolf minor_failed: 1248874bcba6SMarcus Wolf free_GPIOs(device); 1249874bcba6SMarcus Wolf GPIO_failed: 1250874bcba6SMarcus Wolf kfree(device); 1251874bcba6SMarcus Wolf 1252874bcba6SMarcus Wolf return retval; 1253874bcba6SMarcus Wolf } 1254874bcba6SMarcus Wolf 1255874bcba6SMarcus Wolf static int pi433_remove(struct spi_device *spi) 1256874bcba6SMarcus Wolf { 1257874bcba6SMarcus Wolf struct pi433_device *device = spi_get_drvdata(spi); 1258874bcba6SMarcus Wolf 1259874bcba6SMarcus Wolf /* free GPIOs */ 1260874bcba6SMarcus Wolf free_GPIOs(device); 1261874bcba6SMarcus Wolf 1262874bcba6SMarcus Wolf /* make sure ops on existing fds can abort cleanly */ 1263874bcba6SMarcus Wolf device->spi = NULL; 1264874bcba6SMarcus Wolf 1265874bcba6SMarcus Wolf kthread_stop(device->tx_task_struct); 1266874bcba6SMarcus Wolf 1267874bcba6SMarcus Wolf device_destroy(pi433_class, device->devt); 1268874bcba6SMarcus Wolf 1269874bcba6SMarcus Wolf cdev_del(device->cdev); 1270874bcba6SMarcus Wolf 1271874bcba6SMarcus Wolf pi433_free_minor(device); 1272874bcba6SMarcus Wolf 1273874bcba6SMarcus Wolf if (device->users == 0) 1274874bcba6SMarcus Wolf kfree(device); 1275874bcba6SMarcus Wolf 1276874bcba6SMarcus Wolf return 0; 1277874bcba6SMarcus Wolf } 1278874bcba6SMarcus Wolf 1279874bcba6SMarcus Wolf static const struct of_device_id pi433_dt_ids[] = { 1280874bcba6SMarcus Wolf { .compatible = "Smarthome-Wolf,pi433" }, 1281874bcba6SMarcus Wolf {}, 1282874bcba6SMarcus Wolf }; 1283874bcba6SMarcus Wolf 1284874bcba6SMarcus Wolf MODULE_DEVICE_TABLE(of, pi433_dt_ids); 1285874bcba6SMarcus Wolf 1286874bcba6SMarcus Wolf static struct spi_driver pi433_spi_driver = { 1287874bcba6SMarcus Wolf .driver = { 1288874bcba6SMarcus Wolf .name = "pi433", 1289874bcba6SMarcus Wolf .owner = THIS_MODULE, 1290874bcba6SMarcus Wolf .of_match_table = of_match_ptr(pi433_dt_ids), 1291874bcba6SMarcus Wolf }, 1292874bcba6SMarcus Wolf .probe = pi433_probe, 1293874bcba6SMarcus Wolf .remove = pi433_remove, 1294874bcba6SMarcus Wolf 1295874bcba6SMarcus Wolf /* NOTE: suspend/resume methods are not necessary here. 1296874bcba6SMarcus Wolf * We don't do anything except pass the requests to/from 1297874bcba6SMarcus Wolf * the underlying controller. The refrigerator handles 1298874bcba6SMarcus Wolf * most issues; the controller driver handles the rest. 1299874bcba6SMarcus Wolf */ 1300874bcba6SMarcus Wolf }; 1301874bcba6SMarcus Wolf 1302874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 1303874bcba6SMarcus Wolf 1304874bcba6SMarcus Wolf static int __init pi433_init(void) 1305874bcba6SMarcus Wolf { 1306874bcba6SMarcus Wolf int status; 1307874bcba6SMarcus Wolf 1308874bcba6SMarcus Wolf /* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't 1309056eeda2SDerek Robson * work stable - risk of buffer overflow 1310056eeda2SDerek Robson */ 1311874bcba6SMarcus Wolf if (MAX_MSG_SIZE < FIFO_SIZE) 1312874bcba6SMarcus Wolf return -EINVAL; 1313874bcba6SMarcus Wolf 1314874bcba6SMarcus Wolf /* Claim device numbers. Then register a class 1315874bcba6SMarcus Wolf * that will key udev/mdev to add/remove /dev nodes. Last, register 1316874bcba6SMarcus Wolf * Last, register the driver which manages those device numbers. 1317874bcba6SMarcus Wolf */ 1318874bcba6SMarcus Wolf status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/); 1319874bcba6SMarcus Wolf if (status < 0) 1320874bcba6SMarcus Wolf return status; 1321874bcba6SMarcus Wolf 1322874bcba6SMarcus Wolf pi433_class = class_create(THIS_MODULE, "pi433"); 132369af5d92SSrishti Sharma if (IS_ERR(pi433_class)) { 13249be5755cSOliver Graute unregister_chrdev(MAJOR(pi433_dev), 13259be5755cSOliver Graute pi433_spi_driver.driver.name); 1326874bcba6SMarcus Wolf return PTR_ERR(pi433_class); 1327874bcba6SMarcus Wolf } 1328874bcba6SMarcus Wolf 1329874bcba6SMarcus Wolf status = spi_register_driver(&pi433_spi_driver); 133069af5d92SSrishti Sharma if (status < 0) { 1331874bcba6SMarcus Wolf class_destroy(pi433_class); 13329be5755cSOliver Graute unregister_chrdev(MAJOR(pi433_dev), 13339be5755cSOliver Graute pi433_spi_driver.driver.name); 1334874bcba6SMarcus Wolf } 1335874bcba6SMarcus Wolf 1336874bcba6SMarcus Wolf return status; 1337874bcba6SMarcus Wolf } 1338874bcba6SMarcus Wolf 1339874bcba6SMarcus Wolf module_init(pi433_init); 1340874bcba6SMarcus Wolf 1341874bcba6SMarcus Wolf static void __exit pi433_exit(void) 1342874bcba6SMarcus Wolf { 1343874bcba6SMarcus Wolf spi_unregister_driver(&pi433_spi_driver); 1344874bcba6SMarcus Wolf class_destroy(pi433_class); 1345874bcba6SMarcus Wolf unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); 1346874bcba6SMarcus Wolf } 1347874bcba6SMarcus Wolf module_exit(pi433_exit); 1348874bcba6SMarcus Wolf 1349874bcba6SMarcus Wolf MODULE_AUTHOR("Marcus Wolf, <linux@wolf-entwicklungen.de>"); 1350874bcba6SMarcus Wolf MODULE_DESCRIPTION("Driver for Pi433"); 1351874bcba6SMarcus Wolf MODULE_LICENSE("GPL"); 1352874bcba6SMarcus Wolf MODULE_ALIAS("spi:pi433"); 1353