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 58874bcba6SMarcus Wolf #define N_PI433_MINORS (1U << MINORBITS) /*32*/ /* ... up to 256 */ 59874bcba6SMarcus Wolf #define MAX_MSG_SIZE 900 /* min: FIFO_SIZE! */ 60874bcba6SMarcus Wolf #define MSG_FIFO_SIZE 65536 /* 65536 = 2^16 */ 61874bcba6SMarcus Wolf #define NUM_DIO 2 62874bcba6SMarcus Wolf 63874bcba6SMarcus Wolf static dev_t pi433_dev; 64874bcba6SMarcus Wolf static DEFINE_IDR(pi433_idr); 65874bcba6SMarcus Wolf static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */ 66874bcba6SMarcus Wolf 67874bcba6SMarcus Wolf static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */ 68874bcba6SMarcus Wolf 69874bcba6SMarcus Wolf /* tx config is instance specific 70056eeda2SDerek Robson * so with each open a new tx config struct is needed 71056eeda2SDerek Robson */ 72874bcba6SMarcus Wolf /* rx config is device specific 73056eeda2SDerek Robson * so we have just one rx config, ebedded in device struct 74056eeda2SDerek Robson */ 75874bcba6SMarcus Wolf struct pi433_device { 76874bcba6SMarcus Wolf /* device handling related values */ 77874bcba6SMarcus Wolf dev_t devt; 78874bcba6SMarcus Wolf int minor; 79874bcba6SMarcus Wolf struct device *dev; 80874bcba6SMarcus Wolf struct cdev *cdev; 81874bcba6SMarcus Wolf struct spi_device *spi; 82874bcba6SMarcus Wolf unsigned users; 83874bcba6SMarcus Wolf 84874bcba6SMarcus Wolf /* irq related values */ 85874bcba6SMarcus Wolf struct gpio_desc *gpiod[NUM_DIO]; 86874bcba6SMarcus Wolf int irq_num[NUM_DIO]; 87874bcba6SMarcus Wolf u8 irq_state[NUM_DIO]; 88874bcba6SMarcus Wolf 89874bcba6SMarcus Wolf /* tx related values */ 90874bcba6SMarcus Wolf STRUCT_KFIFO_REC_1(MSG_FIFO_SIZE) tx_fifo; 91874bcba6SMarcus Wolf struct mutex tx_fifo_lock; // TODO: check, whether necessary or obsolete 92874bcba6SMarcus Wolf struct task_struct *tx_task_struct; 93874bcba6SMarcus Wolf wait_queue_head_t tx_wait_queue; 94874bcba6SMarcus Wolf u8 free_in_fifo; 9562f39d49SArnd Bergmann char buffer[MAX_MSG_SIZE]; 96874bcba6SMarcus Wolf 97874bcba6SMarcus Wolf /* rx related values */ 98874bcba6SMarcus Wolf struct pi433_rx_cfg rx_cfg; 99874bcba6SMarcus Wolf u8 *rx_buffer; 100874bcba6SMarcus Wolf unsigned int rx_buffer_size; 101874bcba6SMarcus Wolf u32 rx_bytes_to_drop; 102874bcba6SMarcus Wolf u32 rx_bytes_dropped; 103874bcba6SMarcus Wolf unsigned int rx_position; 104874bcba6SMarcus Wolf struct mutex rx_lock; 105874bcba6SMarcus Wolf wait_queue_head_t rx_wait_queue; 106874bcba6SMarcus Wolf 107874bcba6SMarcus Wolf /* fifo wait queue */ 108874bcba6SMarcus Wolf struct task_struct *fifo_task_struct; 109874bcba6SMarcus Wolf wait_queue_head_t fifo_wait_queue; 110874bcba6SMarcus Wolf 111874bcba6SMarcus Wolf /* flags */ 112874bcba6SMarcus Wolf bool rx_active; 113874bcba6SMarcus Wolf bool tx_active; 114874bcba6SMarcus Wolf bool interrupt_rx_allowed; 115874bcba6SMarcus Wolf }; 116874bcba6SMarcus Wolf 117874bcba6SMarcus Wolf struct pi433_instance { 118874bcba6SMarcus Wolf struct pi433_device *device; 119874bcba6SMarcus Wolf struct pi433_tx_cfg tx_cfg; 120874bcba6SMarcus Wolf }; 121874bcba6SMarcus Wolf 122874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 123874bcba6SMarcus Wolf 124874bcba6SMarcus Wolf /* macro for checked access of registers of radio module */ 125874bcba6SMarcus Wolf #define SET_CHECKED(retval) \ 126874bcba6SMarcus Wolf if (retval < 0) \ 127874bcba6SMarcus Wolf return retval; 128874bcba6SMarcus Wolf 129874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 130874bcba6SMarcus Wolf 131874bcba6SMarcus Wolf /* GPIO interrupt handlers */ 132ee26e236SCihangir Akturk static irqreturn_t DIO0_irq_handler(int irq, void *dev_id) 133874bcba6SMarcus Wolf { 134874bcba6SMarcus Wolf struct pi433_device *device = dev_id; 135874bcba6SMarcus Wolf 136874bcba6SMarcus Wolf if (device->irq_state[DIO0] == DIO_PacketSent) 137874bcba6SMarcus Wolf { 138874bcba6SMarcus Wolf device->free_in_fifo = FIFO_SIZE; 1395a60d7baSHaneen Mohammed dev_dbg(device->dev, "DIO0 irq: Packet sent\n"); 140874bcba6SMarcus Wolf wake_up_interruptible(&device->fifo_wait_queue); 141874bcba6SMarcus Wolf } 142874bcba6SMarcus Wolf else if (device->irq_state[DIO0] == DIO_Rssi_DIO0) 143874bcba6SMarcus Wolf { 1445a60d7baSHaneen Mohammed dev_dbg(device->dev, "DIO0 irq: RSSI level over threshold\n"); 145874bcba6SMarcus Wolf wake_up_interruptible(&device->rx_wait_queue); 146874bcba6SMarcus Wolf } 147874bcba6SMarcus Wolf else if (device->irq_state[DIO0] == DIO_PayloadReady) 148874bcba6SMarcus Wolf { 1495a60d7baSHaneen Mohammed dev_dbg(device->dev, "DIO0 irq: PayloadReady\n"); 150874bcba6SMarcus Wolf device->free_in_fifo = 0; 151874bcba6SMarcus Wolf wake_up_interruptible(&device->fifo_wait_queue); 152874bcba6SMarcus Wolf } 153874bcba6SMarcus Wolf 154ee26e236SCihangir Akturk return IRQ_HANDLED; 155874bcba6SMarcus Wolf } 156874bcba6SMarcus Wolf 157ee26e236SCihangir Akturk static irqreturn_t DIO1_irq_handler(int irq, void *dev_id) 158874bcba6SMarcus Wolf { 159874bcba6SMarcus Wolf struct pi433_device *device = dev_id; 160874bcba6SMarcus Wolf 161874bcba6SMarcus Wolf if (device->irq_state[DIO1] == DIO_FifoNotEmpty_DIO1) 162874bcba6SMarcus Wolf { 163874bcba6SMarcus Wolf device->free_in_fifo = FIFO_SIZE; 164874bcba6SMarcus Wolf } 165874bcba6SMarcus Wolf else if (device->irq_state[DIO1] == DIO_FifoLevel) 166874bcba6SMarcus Wolf { 167874bcba6SMarcus Wolf if (device->rx_active) device->free_in_fifo = FIFO_THRESHOLD - 1; 168874bcba6SMarcus Wolf else device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1; 169874bcba6SMarcus Wolf } 1705a60d7baSHaneen Mohammed dev_dbg(device->dev, 1715a60d7baSHaneen Mohammed "DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); 172874bcba6SMarcus Wolf wake_up_interruptible(&device->fifo_wait_queue); 173874bcba6SMarcus Wolf 174ee26e236SCihangir Akturk return IRQ_HANDLED; 175874bcba6SMarcus Wolf } 176874bcba6SMarcus Wolf 177874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 178874bcba6SMarcus Wolf 179874bcba6SMarcus Wolf static int 180874bcba6SMarcus Wolf rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) 181874bcba6SMarcus Wolf { 182125a452cSElia Geretto int ret; 183874bcba6SMarcus Wolf int payload_length; 184874bcba6SMarcus Wolf 185874bcba6SMarcus Wolf /* receiver config */ 186874bcba6SMarcus Wolf SET_CHECKED(rf69_set_frequency (dev->spi, rx_cfg->frequency)); 187874bcba6SMarcus Wolf SET_CHECKED(rf69_set_bit_rate (dev->spi, rx_cfg->bit_rate)); 188874bcba6SMarcus Wolf SET_CHECKED(rf69_set_modulation (dev->spi, rx_cfg->modulation)); 189874bcba6SMarcus Wolf SET_CHECKED(rf69_set_antenna_impedance (dev->spi, rx_cfg->antenna_impedance)); 190874bcba6SMarcus Wolf SET_CHECKED(rf69_set_rssi_threshold (dev->spi, rx_cfg->rssi_threshold)); 191874bcba6SMarcus Wolf SET_CHECKED(rf69_set_ook_threshold_dec (dev->spi, rx_cfg->thresholdDecrement)); 192874bcba6SMarcus Wolf SET_CHECKED(rf69_set_bandwidth (dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent)); 193874bcba6SMarcus Wolf SET_CHECKED(rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent)); 194874bcba6SMarcus Wolf SET_CHECKED(rf69_set_dagc (dev->spi, rx_cfg->dagc)); 195874bcba6SMarcus Wolf 196874bcba6SMarcus Wolf dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop; 197874bcba6SMarcus Wolf 198874bcba6SMarcus Wolf /* packet config */ 199874bcba6SMarcus Wolf /* enable */ 200874bcba6SMarcus Wolf SET_CHECKED(rf69_set_sync_enable(dev->spi, rx_cfg->enable_sync)); 201874bcba6SMarcus Wolf if (rx_cfg->enable_sync == optionOn) 202874bcba6SMarcus Wolf { 203874bcba6SMarcus Wolf SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt)); 204874bcba6SMarcus Wolf } 205874bcba6SMarcus Wolf else 206874bcba6SMarcus Wolf { 207874bcba6SMarcus Wolf SET_CHECKED(rf69_set_fifo_fill_condition(dev->spi, always)); 208874bcba6SMarcus Wolf } 209125a452cSElia Geretto if (rx_cfg->enable_length_byte == optionOn) { 210125a452cSElia Geretto ret = rf69_set_packet_format(dev->spi, packetLengthVar); 211125a452cSElia Geretto if (ret < 0) 212125a452cSElia Geretto return ret; 213125a452cSElia Geretto } else { 214125a452cSElia Geretto ret = rf69_set_packet_format(dev->spi, packetLengthFix); 215125a452cSElia Geretto if (ret < 0) 216125a452cSElia Geretto return ret; 217125a452cSElia Geretto } 218874bcba6SMarcus Wolf SET_CHECKED(rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering)); 219874bcba6SMarcus Wolf SET_CHECKED(rf69_set_crc_enable (dev->spi, rx_cfg->enable_crc)); 220874bcba6SMarcus Wolf 221874bcba6SMarcus Wolf /* lengths */ 222874bcba6SMarcus Wolf SET_CHECKED(rf69_set_sync_size(dev->spi, rx_cfg->sync_length)); 223874bcba6SMarcus Wolf if (rx_cfg->enable_length_byte == optionOn) 224874bcba6SMarcus Wolf { 225874bcba6SMarcus Wolf SET_CHECKED(rf69_set_payload_length(dev->spi, 0xff)); 226874bcba6SMarcus Wolf } 227874bcba6SMarcus Wolf else if (rx_cfg->fixed_message_length != 0) 228874bcba6SMarcus Wolf { 229874bcba6SMarcus Wolf payload_length = rx_cfg->fixed_message_length; 230874bcba6SMarcus Wolf if (rx_cfg->enable_length_byte == optionOn) payload_length++; 231874bcba6SMarcus Wolf if (rx_cfg->enable_address_filtering != filteringOff) payload_length++; 232874bcba6SMarcus Wolf SET_CHECKED(rf69_set_payload_length(dev->spi, payload_length)); 233874bcba6SMarcus Wolf } 234874bcba6SMarcus Wolf else 235874bcba6SMarcus Wolf { 236874bcba6SMarcus Wolf SET_CHECKED(rf69_set_payload_length(dev->spi, 0)); 237874bcba6SMarcus Wolf } 238874bcba6SMarcus Wolf 239874bcba6SMarcus Wolf /* values */ 240874bcba6SMarcus Wolf if (rx_cfg->enable_sync == optionOn) 241874bcba6SMarcus Wolf { 242874bcba6SMarcus Wolf SET_CHECKED(rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern)); 243874bcba6SMarcus Wolf } 244874bcba6SMarcus Wolf if (rx_cfg->enable_address_filtering != filteringOff) 245874bcba6SMarcus Wolf { 246874bcba6SMarcus Wolf SET_CHECKED(rf69_set_node_address (dev->spi, rx_cfg->node_address)); 247874bcba6SMarcus Wolf SET_CHECKED(rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address)); 248874bcba6SMarcus Wolf } 249874bcba6SMarcus Wolf 250874bcba6SMarcus Wolf return 0; 251874bcba6SMarcus Wolf } 252874bcba6SMarcus Wolf 253874bcba6SMarcus Wolf static int 254874bcba6SMarcus Wolf rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg) 255874bcba6SMarcus Wolf { 256125a452cSElia Geretto int ret; 257125a452cSElia Geretto 258874bcba6SMarcus Wolf SET_CHECKED(rf69_set_frequency (dev->spi, tx_cfg->frequency)); 259874bcba6SMarcus Wolf SET_CHECKED(rf69_set_bit_rate (dev->spi, tx_cfg->bit_rate)); 260874bcba6SMarcus Wolf SET_CHECKED(rf69_set_modulation (dev->spi, tx_cfg->modulation)); 261874bcba6SMarcus Wolf SET_CHECKED(rf69_set_deviation (dev->spi, tx_cfg->dev_frequency)); 262874bcba6SMarcus Wolf SET_CHECKED(rf69_set_pa_ramp (dev->spi, tx_cfg->pa_ramp)); 263874bcba6SMarcus Wolf SET_CHECKED(rf69_set_modulation_shaping(dev->spi, tx_cfg->modShaping)); 264874bcba6SMarcus Wolf SET_CHECKED(rf69_set_tx_start_condition(dev->spi, tx_cfg->tx_start_condition)); 265874bcba6SMarcus Wolf 266874bcba6SMarcus Wolf /* packet format enable */ 267874bcba6SMarcus Wolf if (tx_cfg->enable_preamble == optionOn) 268874bcba6SMarcus Wolf { 269874bcba6SMarcus Wolf SET_CHECKED(rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length)); 270874bcba6SMarcus Wolf } 271874bcba6SMarcus Wolf else 272874bcba6SMarcus Wolf { 273874bcba6SMarcus Wolf SET_CHECKED(rf69_set_preamble_length(dev->spi, 0)); 274874bcba6SMarcus Wolf } 275874bcba6SMarcus Wolf SET_CHECKED(rf69_set_sync_enable (dev->spi, tx_cfg->enable_sync)); 276125a452cSElia Geretto if (tx_cfg->enable_length_byte == optionOn) { 277125a452cSElia Geretto ret = rf69_set_packet_format(dev->spi, packetLengthVar); 278125a452cSElia Geretto if (ret < 0) 279125a452cSElia Geretto return ret; 280125a452cSElia Geretto } else { 281125a452cSElia Geretto ret = rf69_set_packet_format(dev->spi, packetLengthFix); 282125a452cSElia Geretto if (ret < 0) 283125a452cSElia Geretto return ret; 284125a452cSElia Geretto } 285874bcba6SMarcus Wolf SET_CHECKED(rf69_set_crc_enable (dev->spi, tx_cfg->enable_crc)); 286874bcba6SMarcus Wolf 287874bcba6SMarcus Wolf /* configure sync, if enabled */ 28869af5d92SSrishti Sharma if (tx_cfg->enable_sync == optionOn) { 289874bcba6SMarcus Wolf SET_CHECKED(rf69_set_sync_size(dev->spi, tx_cfg->sync_length)); 290874bcba6SMarcus Wolf SET_CHECKED(rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern)); 291874bcba6SMarcus Wolf } 292874bcba6SMarcus Wolf 293874bcba6SMarcus Wolf return 0; 294874bcba6SMarcus Wolf } 295874bcba6SMarcus Wolf 296874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 297874bcba6SMarcus Wolf 298874bcba6SMarcus Wolf static int 299874bcba6SMarcus Wolf pi433_start_rx(struct pi433_device *dev) 300874bcba6SMarcus Wolf { 301874bcba6SMarcus Wolf int retval; 302874bcba6SMarcus Wolf 303874bcba6SMarcus Wolf /* return without action, if no pending read request */ 304874bcba6SMarcus Wolf if (!dev->rx_active) 305874bcba6SMarcus Wolf return 0; 306874bcba6SMarcus Wolf 307874bcba6SMarcus Wolf /* setup for receiving */ 308874bcba6SMarcus Wolf retval = rf69_set_rx_cfg(dev, &dev->rx_cfg); 309874bcba6SMarcus Wolf if (retval) return retval; 310874bcba6SMarcus Wolf 311874bcba6SMarcus Wolf /* setup rssi irq */ 312874bcba6SMarcus Wolf SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO0, DIO_Rssi_DIO0)); 313874bcba6SMarcus Wolf dev->irq_state[DIO0] = DIO_Rssi_DIO0; 314874bcba6SMarcus Wolf irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); 315874bcba6SMarcus Wolf 316874bcba6SMarcus Wolf /* setup fifo level interrupt */ 317874bcba6SMarcus Wolf SET_CHECKED(rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD)); 318874bcba6SMarcus Wolf SET_CHECKED(rf69_set_dio_mapping(dev->spi, DIO1, DIO_FifoLevel)); 319874bcba6SMarcus Wolf dev->irq_state[DIO1] = DIO_FifoLevel; 320874bcba6SMarcus Wolf irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING); 321874bcba6SMarcus Wolf 322874bcba6SMarcus Wolf /* set module to receiving mode */ 323874bcba6SMarcus Wolf SET_CHECKED(rf69_set_mode(dev->spi, receive)); 324874bcba6SMarcus Wolf 325874bcba6SMarcus Wolf return 0; 326874bcba6SMarcus Wolf } 327874bcba6SMarcus Wolf 328874bcba6SMarcus Wolf 329874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 330874bcba6SMarcus Wolf 3317de77a39SJoseph Wright static int 332874bcba6SMarcus Wolf pi433_receive(void *data) 333874bcba6SMarcus Wolf { 334874bcba6SMarcus Wolf struct pi433_device *dev = data; 335874bcba6SMarcus Wolf struct spi_device *spi = dev->spi; /* needed for SET_CHECKED */ 336874bcba6SMarcus Wolf int bytes_to_read, bytes_total; 337874bcba6SMarcus Wolf int retval; 338874bcba6SMarcus Wolf 339874bcba6SMarcus Wolf dev->interrupt_rx_allowed = false; 340874bcba6SMarcus Wolf 341874bcba6SMarcus Wolf /* wait for any tx to finish */ 342874bcba6SMarcus Wolf dev_dbg(dev->dev,"rx: going to wait for any tx to finish"); 343874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active); 344874bcba6SMarcus Wolf if(retval) /* wait was interrupted */ 345874bcba6SMarcus Wolf { 346874bcba6SMarcus Wolf dev->interrupt_rx_allowed = true; 347874bcba6SMarcus Wolf wake_up_interruptible(&dev->tx_wait_queue); 348874bcba6SMarcus Wolf return retval; 349874bcba6SMarcus Wolf } 350874bcba6SMarcus Wolf 351874bcba6SMarcus Wolf /* prepare status vars */ 352874bcba6SMarcus Wolf dev->free_in_fifo = FIFO_SIZE; 353874bcba6SMarcus Wolf dev->rx_position = 0; 354874bcba6SMarcus Wolf dev->rx_bytes_dropped = 0; 355874bcba6SMarcus Wolf 356874bcba6SMarcus Wolf /* setup radio module to listen for something "in the air" */ 357874bcba6SMarcus Wolf retval = pi433_start_rx(dev); 358874bcba6SMarcus Wolf if (retval) 359874bcba6SMarcus Wolf return retval; 360874bcba6SMarcus Wolf 361874bcba6SMarcus Wolf /* now check RSSI, if low wait for getting high (RSSI interrupt) */ 362874bcba6SMarcus Wolf while ( !rf69_get_flag(dev->spi, rssiExceededThreshold) ) 363874bcba6SMarcus Wolf { 364874bcba6SMarcus Wolf /* allow tx to interrupt us while waiting for high RSSI */ 365874bcba6SMarcus Wolf dev->interrupt_rx_allowed = true; 366874bcba6SMarcus Wolf wake_up_interruptible(&dev->tx_wait_queue); 367874bcba6SMarcus Wolf 368874bcba6SMarcus Wolf /* wait for RSSI level to become high */ 369874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: going to wait for high RSSI level"); 370874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->rx_wait_queue, 371874bcba6SMarcus Wolf rf69_get_flag(dev->spi, 372874bcba6SMarcus Wolf rssiExceededThreshold)); 373874bcba6SMarcus Wolf if (retval) goto abort; /* wait was interrupted */ 374874bcba6SMarcus Wolf dev->interrupt_rx_allowed = false; 375874bcba6SMarcus Wolf 376874bcba6SMarcus Wolf /* cross check for ongoing tx */ 377874bcba6SMarcus Wolf if (!dev->tx_active) break; 378874bcba6SMarcus Wolf } 379874bcba6SMarcus Wolf 380874bcba6SMarcus Wolf /* configure payload ready irq */ 381874bcba6SMarcus Wolf SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PayloadReady)); 382874bcba6SMarcus Wolf dev->irq_state[DIO0] = DIO_PayloadReady; 383874bcba6SMarcus Wolf irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); 384874bcba6SMarcus Wolf 385874bcba6SMarcus Wolf /* fixed or unlimited length? */ 386874bcba6SMarcus Wolf if (dev->rx_cfg.fixed_message_length != 0) 387874bcba6SMarcus Wolf { 388874bcba6SMarcus Wolf if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size) 389874bcba6SMarcus Wolf { 390874bcba6SMarcus Wolf retval = -1; 391874bcba6SMarcus Wolf goto abort; 392874bcba6SMarcus Wolf } 393874bcba6SMarcus Wolf bytes_total = dev->rx_cfg.fixed_message_length; 394874bcba6SMarcus Wolf dev_dbg(dev->dev,"rx: msg len set to %d by fixed length", bytes_total); 395874bcba6SMarcus Wolf } 396874bcba6SMarcus Wolf else 397874bcba6SMarcus Wolf { 398874bcba6SMarcus Wolf bytes_total = dev->rx_buffer_size; 399874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total); 400874bcba6SMarcus Wolf } 401874bcba6SMarcus Wolf 402874bcba6SMarcus Wolf /* length byte enabled? */ 403874bcba6SMarcus Wolf if (dev->rx_cfg.enable_length_byte == optionOn) 404874bcba6SMarcus Wolf { 405874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->fifo_wait_queue, 406874bcba6SMarcus Wolf dev->free_in_fifo < FIFO_SIZE); 407874bcba6SMarcus Wolf if (retval) goto abort; /* wait was interrupted */ 408874bcba6SMarcus Wolf 409874bcba6SMarcus Wolf rf69_read_fifo(spi, (u8 *)&bytes_total, 1); 41069af5d92SSrishti Sharma if (bytes_total > dev->rx_buffer_size) { 411874bcba6SMarcus Wolf retval = -1; 412874bcba6SMarcus Wolf goto abort; 413874bcba6SMarcus Wolf } 414874bcba6SMarcus Wolf dev->free_in_fifo++; 415874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total); 416874bcba6SMarcus Wolf } 417874bcba6SMarcus Wolf 418874bcba6SMarcus Wolf /* address byte enabled? */ 419874bcba6SMarcus Wolf if (dev->rx_cfg.enable_address_filtering != filteringOff) 420874bcba6SMarcus Wolf { 421874bcba6SMarcus Wolf u8 dummy; 422874bcba6SMarcus Wolf 423874bcba6SMarcus Wolf bytes_total--; 424874bcba6SMarcus Wolf 425874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->fifo_wait_queue, 426874bcba6SMarcus Wolf dev->free_in_fifo < FIFO_SIZE); 427874bcba6SMarcus Wolf if (retval) goto abort; /* wait was interrupted */ 428874bcba6SMarcus Wolf 429874bcba6SMarcus Wolf rf69_read_fifo(spi, &dummy, 1); 430874bcba6SMarcus Wolf dev->free_in_fifo++; 431874bcba6SMarcus Wolf dev_dbg(dev->dev, "rx: address byte stripped off"); 432874bcba6SMarcus Wolf } 433874bcba6SMarcus Wolf 434874bcba6SMarcus Wolf /* get payload */ 435874bcba6SMarcus Wolf while (dev->rx_position < bytes_total) 436874bcba6SMarcus Wolf { 437874bcba6SMarcus Wolf if ( !rf69_get_flag(dev->spi, payloadReady) ) 438874bcba6SMarcus Wolf { 439874bcba6SMarcus Wolf retval = wait_event_interruptible(dev->fifo_wait_queue, 440874bcba6SMarcus Wolf dev->free_in_fifo < FIFO_SIZE); 441874bcba6SMarcus Wolf if (retval) goto abort; /* wait was interrupted */ 442874bcba6SMarcus Wolf } 443874bcba6SMarcus Wolf 444874bcba6SMarcus Wolf /* need to drop bytes or acquire? */ 445874bcba6SMarcus Wolf if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) 446874bcba6SMarcus Wolf bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped; 447874bcba6SMarcus Wolf else 448874bcba6SMarcus Wolf bytes_to_read = bytes_total - dev->rx_position; 449874bcba6SMarcus Wolf 450874bcba6SMarcus Wolf 451874bcba6SMarcus Wolf /* access the fifo */ 452874bcba6SMarcus Wolf if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo) 453874bcba6SMarcus Wolf bytes_to_read = FIFO_SIZE - dev->free_in_fifo; 454874bcba6SMarcus Wolf retval = rf69_read_fifo(spi, 455874bcba6SMarcus Wolf &dev->rx_buffer[dev->rx_position], 456874bcba6SMarcus Wolf bytes_to_read); 457874bcba6SMarcus Wolf if (retval) goto abort; /* read failed */ 458874bcba6SMarcus Wolf dev->free_in_fifo += bytes_to_read; 459874bcba6SMarcus Wolf 460874bcba6SMarcus Wolf /* adjust status vars */ 461874bcba6SMarcus Wolf if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) 462874bcba6SMarcus Wolf dev->rx_bytes_dropped += bytes_to_read; 463874bcba6SMarcus Wolf else 464874bcba6SMarcus Wolf dev->rx_position += bytes_to_read; 465874bcba6SMarcus Wolf } 466874bcba6SMarcus Wolf 467874bcba6SMarcus Wolf 4682ebd34caSHarsha Sharma /* rx done, wait was interrupted or error occurred */ 469874bcba6SMarcus Wolf abort: 470874bcba6SMarcus Wolf dev->interrupt_rx_allowed = true; 471874bcba6SMarcus Wolf SET_CHECKED(rf69_set_mode(dev->spi, standby)); 472874bcba6SMarcus Wolf wake_up_interruptible(&dev->tx_wait_queue); 473874bcba6SMarcus Wolf 474874bcba6SMarcus Wolf if (retval) 475874bcba6SMarcus Wolf return retval; 476874bcba6SMarcus Wolf else 477874bcba6SMarcus Wolf return bytes_total; 478874bcba6SMarcus Wolf } 479874bcba6SMarcus Wolf 4807de77a39SJoseph Wright static int 481874bcba6SMarcus Wolf pi433_tx_thread(void *data) 482874bcba6SMarcus Wolf { 483874bcba6SMarcus Wolf struct pi433_device *device = data; 484874bcba6SMarcus Wolf struct spi_device *spi = device->spi; /* needed for SET_CHECKED */ 485874bcba6SMarcus Wolf struct pi433_tx_cfg tx_cfg; 48662f39d49SArnd Bergmann u8 *buffer = device->buffer; 487874bcba6SMarcus Wolf size_t size; 488874bcba6SMarcus Wolf bool rx_interrupted = false; 489874bcba6SMarcus Wolf int position, repetitions; 490874bcba6SMarcus Wolf int retval; 491874bcba6SMarcus Wolf 492874bcba6SMarcus Wolf while (1) 493874bcba6SMarcus Wolf { 494874bcba6SMarcus Wolf /* wait for fifo to be populated or for request to terminate*/ 495874bcba6SMarcus Wolf dev_dbg(device->dev, "thread: going to wait for new messages"); 496874bcba6SMarcus Wolf wait_event_interruptible(device->tx_wait_queue, 497874bcba6SMarcus Wolf ( !kfifo_is_empty(&device->tx_fifo) || 498874bcba6SMarcus Wolf kthread_should_stop() )); 499874bcba6SMarcus Wolf if ( kthread_should_stop() ) 500874bcba6SMarcus Wolf return 0; 501874bcba6SMarcus Wolf 502874bcba6SMarcus Wolf /* get data from fifo in the following order: 503056eeda2SDerek Robson * - tx_cfg 504056eeda2SDerek Robson * - size of message 505056eeda2SDerek Robson * - message 506056eeda2SDerek Robson */ 507874bcba6SMarcus Wolf mutex_lock(&device->tx_fifo_lock); 508874bcba6SMarcus Wolf 509874bcba6SMarcus Wolf retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg)); 51069af5d92SSrishti Sharma if (retval != sizeof(tx_cfg)) { 511874bcba6SMarcus Wolf dev_dbg(device->dev, "reading tx_cfg from fifo failed: got %d byte(s), expected %d", retval, (unsigned int)sizeof(tx_cfg) ); 512874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 513874bcba6SMarcus Wolf continue; 514874bcba6SMarcus Wolf } 515874bcba6SMarcus Wolf 516874bcba6SMarcus Wolf retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t)); 51769af5d92SSrishti Sharma if (retval != sizeof(size_t)) { 518874bcba6SMarcus Wolf dev_dbg(device->dev, "reading msg size from fifo failed: got %d, expected %d", retval, (unsigned int)sizeof(size_t) ); 519874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 520874bcba6SMarcus Wolf continue; 521874bcba6SMarcus Wolf } 522874bcba6SMarcus Wolf 523874bcba6SMarcus Wolf /* use fixed message length, if requested */ 524874bcba6SMarcus Wolf if (tx_cfg.fixed_message_length != 0) 525874bcba6SMarcus Wolf size = tx_cfg.fixed_message_length; 526874bcba6SMarcus Wolf 527874bcba6SMarcus Wolf /* increase size, if len byte is requested */ 528874bcba6SMarcus Wolf if (tx_cfg.enable_length_byte == optionOn) 529874bcba6SMarcus Wolf size++; 530874bcba6SMarcus Wolf 531874bcba6SMarcus Wolf /* increase size, if adr byte is requested */ 532874bcba6SMarcus Wolf if (tx_cfg.enable_address_byte == optionOn) 533874bcba6SMarcus Wolf size++; 534874bcba6SMarcus Wolf 535874bcba6SMarcus Wolf /* prime buffer */ 536874bcba6SMarcus Wolf memset(buffer, 0, size); 537874bcba6SMarcus Wolf position = 0; 538874bcba6SMarcus Wolf 539874bcba6SMarcus Wolf /* add length byte, if requested */ 540874bcba6SMarcus Wolf if (tx_cfg.enable_length_byte == optionOn) 541874bcba6SMarcus Wolf buffer[position++] = size-1; /* according to spec length byte itself must be excluded from the length calculation */ 542874bcba6SMarcus Wolf 543874bcba6SMarcus Wolf /* add adr byte, if requested */ 544874bcba6SMarcus Wolf if (tx_cfg.enable_address_byte == optionOn) 545874bcba6SMarcus Wolf buffer[position++] = tx_cfg.address_byte; 546874bcba6SMarcus Wolf 547874bcba6SMarcus Wolf /* finally get message data from fifo */ 548874bcba6SMarcus Wolf retval = kfifo_out(&device->tx_fifo, &buffer[position], sizeof(buffer)-position ); 549874bcba6SMarcus Wolf dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval); 550874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 551874bcba6SMarcus Wolf 552874bcba6SMarcus Wolf /* if rx is active, we need to interrupt the waiting for 553056eeda2SDerek Robson * incoming telegrams, to be able to send something. 554056eeda2SDerek Robson * We are only allowed, if currently no reception takes 555056eeda2SDerek Robson * place otherwise we need to wait for the incoming telegram 556056eeda2SDerek Robson * to finish 557056eeda2SDerek Robson */ 558874bcba6SMarcus Wolf wait_event_interruptible(device->tx_wait_queue, 559874bcba6SMarcus Wolf !device->rx_active || 560874bcba6SMarcus Wolf device->interrupt_rx_allowed == true); 561874bcba6SMarcus Wolf 562874bcba6SMarcus Wolf /* prevent race conditions 563056eeda2SDerek Robson * irq will be reenabled after tx config is set 564056eeda2SDerek Robson */ 565874bcba6SMarcus Wolf disable_irq(device->irq_num[DIO0]); 566874bcba6SMarcus Wolf device->tx_active = true; 567874bcba6SMarcus Wolf 568874bcba6SMarcus Wolf if (device->rx_active && rx_interrupted == false) 569874bcba6SMarcus Wolf { 570874bcba6SMarcus Wolf /* rx is currently waiting for a telegram; 571056eeda2SDerek Robson * we need to set the radio module to standby 572056eeda2SDerek Robson */ 573874bcba6SMarcus Wolf SET_CHECKED(rf69_set_mode(device->spi, standby)); 574874bcba6SMarcus Wolf rx_interrupted = true; 575874bcba6SMarcus Wolf } 576874bcba6SMarcus Wolf 577874bcba6SMarcus Wolf /* clear fifo, set fifo threshold, set payload length */ 578874bcba6SMarcus Wolf SET_CHECKED(rf69_set_mode(spi, standby)); /* this clears the fifo */ 579874bcba6SMarcus Wolf SET_CHECKED(rf69_set_fifo_threshold(spi, FIFO_THRESHOLD)); 580874bcba6SMarcus Wolf if (tx_cfg.enable_length_byte == optionOn) 581874bcba6SMarcus Wolf { 582874bcba6SMarcus Wolf SET_CHECKED(rf69_set_payload_length(spi, size * tx_cfg.repetitions)); 583874bcba6SMarcus Wolf } 584874bcba6SMarcus Wolf else 585874bcba6SMarcus Wolf { 586874bcba6SMarcus Wolf SET_CHECKED(rf69_set_payload_length(spi, 0)); 587874bcba6SMarcus Wolf } 588874bcba6SMarcus Wolf 589874bcba6SMarcus Wolf /* configure the rf chip */ 590874bcba6SMarcus Wolf rf69_set_tx_cfg(device, &tx_cfg); 591874bcba6SMarcus Wolf 592874bcba6SMarcus Wolf /* enable fifo level interrupt */ 593874bcba6SMarcus Wolf SET_CHECKED(rf69_set_dio_mapping(spi, DIO1, DIO_FifoLevel)); 594874bcba6SMarcus Wolf device->irq_state[DIO1] = DIO_FifoLevel; 595874bcba6SMarcus Wolf irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING); 596874bcba6SMarcus Wolf 597874bcba6SMarcus Wolf /* enable packet sent interrupt */ 598874bcba6SMarcus Wolf SET_CHECKED(rf69_set_dio_mapping(spi, DIO0, DIO_PacketSent)); 599874bcba6SMarcus Wolf device->irq_state[DIO0] = DIO_PacketSent; 600874bcba6SMarcus Wolf irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); 601874bcba6SMarcus Wolf enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check */ 602874bcba6SMarcus Wolf 603874bcba6SMarcus Wolf /* enable transmission */ 604874bcba6SMarcus Wolf SET_CHECKED(rf69_set_mode(spi, transmit)); 605874bcba6SMarcus Wolf 606874bcba6SMarcus Wolf /* transfer this msg (and repetitions) to chip fifo */ 607874bcba6SMarcus Wolf device->free_in_fifo = FIFO_SIZE; 608874bcba6SMarcus Wolf position = 0; 609874bcba6SMarcus Wolf repetitions = tx_cfg.repetitions; 610874bcba6SMarcus Wolf while( (repetitions > 0) && (size > position) ) 611874bcba6SMarcus Wolf { 612874bcba6SMarcus Wolf if ( (size - position) > device->free_in_fifo) 613874bcba6SMarcus Wolf { /* msg to big for fifo - take a part */ 614874bcba6SMarcus Wolf int temp = device->free_in_fifo; 615874bcba6SMarcus Wolf device->free_in_fifo = 0; 616874bcba6SMarcus Wolf rf69_write_fifo(spi, 617874bcba6SMarcus Wolf &buffer[position], 618874bcba6SMarcus Wolf temp); 619874bcba6SMarcus Wolf position +=temp; 620874bcba6SMarcus Wolf } 621874bcba6SMarcus Wolf else 622874bcba6SMarcus Wolf { /* msg fits into fifo - take all */ 623874bcba6SMarcus Wolf device->free_in_fifo -= size; 624874bcba6SMarcus Wolf repetitions--; 625874bcba6SMarcus Wolf rf69_write_fifo(spi, 626874bcba6SMarcus Wolf &buffer[position], 627874bcba6SMarcus Wolf (size - position) ); 628874bcba6SMarcus Wolf position = 0; /* reset for next repetition */ 629874bcba6SMarcus Wolf } 630874bcba6SMarcus Wolf 631874bcba6SMarcus Wolf retval = wait_event_interruptible(device->fifo_wait_queue, 632874bcba6SMarcus Wolf device->free_in_fifo > 0); 633874bcba6SMarcus Wolf if (retval) { printk("ABORT\n"); goto abort; } 634874bcba6SMarcus Wolf } 635874bcba6SMarcus Wolf 636874bcba6SMarcus Wolf /* we are done. Wait for packet to get sent */ 63728eb8555SColin Ian King dev_dbg(device->dev, "thread: wait for packet to get sent/fifo to be empty"); 638874bcba6SMarcus Wolf wait_event_interruptible(device->fifo_wait_queue, 639874bcba6SMarcus Wolf device->free_in_fifo == FIFO_SIZE || 640874bcba6SMarcus Wolf kthread_should_stop() ); 641874bcba6SMarcus Wolf if ( kthread_should_stop() ) printk("ABORT\n"); 642874bcba6SMarcus Wolf 643874bcba6SMarcus Wolf 644874bcba6SMarcus Wolf /* STOP_TRANSMISSION */ 645874bcba6SMarcus Wolf dev_dbg(device->dev, "thread: Packet sent. Set mode to stby."); 646874bcba6SMarcus Wolf SET_CHECKED(rf69_set_mode(spi, standby)); 647874bcba6SMarcus Wolf 648874bcba6SMarcus Wolf /* everything sent? */ 64969af5d92SSrishti Sharma if (kfifo_is_empty(&device->tx_fifo)) { 650874bcba6SMarcus Wolf abort: 651874bcba6SMarcus Wolf if (rx_interrupted) 652874bcba6SMarcus Wolf { 653874bcba6SMarcus Wolf rx_interrupted = false; 654874bcba6SMarcus Wolf pi433_start_rx(device); 655874bcba6SMarcus Wolf } 656874bcba6SMarcus Wolf device->tx_active = false; 657874bcba6SMarcus Wolf wake_up_interruptible(&device->rx_wait_queue); 658874bcba6SMarcus Wolf } 659874bcba6SMarcus Wolf } 660874bcba6SMarcus Wolf } 661874bcba6SMarcus Wolf 662874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 663874bcba6SMarcus Wolf 664874bcba6SMarcus Wolf static ssize_t 665874bcba6SMarcus Wolf pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos) 666874bcba6SMarcus Wolf { 667874bcba6SMarcus Wolf struct pi433_instance *instance; 668874bcba6SMarcus Wolf struct pi433_device *device; 669874bcba6SMarcus Wolf int bytes_received; 670874bcba6SMarcus Wolf ssize_t retval; 671874bcba6SMarcus Wolf 672874bcba6SMarcus Wolf /* check, whether internal buffer is big enough for requested size */ 673874bcba6SMarcus Wolf if (size > MAX_MSG_SIZE) 674874bcba6SMarcus Wolf return -EMSGSIZE; 675874bcba6SMarcus Wolf 676874bcba6SMarcus Wolf instance = filp->private_data; 677874bcba6SMarcus Wolf device = instance->device; 678874bcba6SMarcus Wolf 679874bcba6SMarcus Wolf /* just one read request at a time */ 680874bcba6SMarcus Wolf mutex_lock(&device->rx_lock); 681874bcba6SMarcus Wolf if (device->rx_active) 682874bcba6SMarcus Wolf { 683874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 684874bcba6SMarcus Wolf return -EAGAIN; 685874bcba6SMarcus Wolf } 686874bcba6SMarcus Wolf else 687874bcba6SMarcus Wolf { 688874bcba6SMarcus Wolf device->rx_active = true; 689874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 690874bcba6SMarcus Wolf } 691874bcba6SMarcus Wolf 692874bcba6SMarcus Wolf /* start receiving */ 693874bcba6SMarcus Wolf /* will block until something was received*/ 694874bcba6SMarcus Wolf device->rx_buffer_size = size; 695874bcba6SMarcus Wolf bytes_received = pi433_receive(device); 696874bcba6SMarcus Wolf 697874bcba6SMarcus Wolf /* release rx */ 698874bcba6SMarcus Wolf mutex_lock(&device->rx_lock); 699874bcba6SMarcus Wolf device->rx_active = false; 700874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 701874bcba6SMarcus Wolf 702874bcba6SMarcus Wolf /* if read was successful copy to user space*/ 70369af5d92SSrishti Sharma if (bytes_received > 0) { 704874bcba6SMarcus Wolf retval = copy_to_user(buf, device->rx_buffer, bytes_received); 705874bcba6SMarcus Wolf if (retval) 70639ae5f1eSdan.carpenter@oracle.com return -EFAULT; 707874bcba6SMarcus Wolf } 708874bcba6SMarcus Wolf 709874bcba6SMarcus Wolf return bytes_received; 710874bcba6SMarcus Wolf } 711874bcba6SMarcus Wolf 712874bcba6SMarcus Wolf 713874bcba6SMarcus Wolf static ssize_t 714874bcba6SMarcus Wolf pi433_write(struct file *filp, const char __user *buf, 715874bcba6SMarcus Wolf size_t count, loff_t *f_pos) 716874bcba6SMarcus Wolf { 717874bcba6SMarcus Wolf struct pi433_instance *instance; 718874bcba6SMarcus Wolf struct pi433_device *device; 71957f8965aSStefano Manni int retval; 72057f8965aSStefano Manni unsigned int copied; 721874bcba6SMarcus Wolf 722874bcba6SMarcus Wolf instance = filp->private_data; 723874bcba6SMarcus Wolf device = instance->device; 724874bcba6SMarcus Wolf 725874bcba6SMarcus Wolf /* check, whether internal buffer (tx thread) is big enough for requested size */ 726874bcba6SMarcus Wolf if (count > MAX_MSG_SIZE) 727874bcba6SMarcus Wolf return -EMSGSIZE; 728874bcba6SMarcus Wolf 729874bcba6SMarcus Wolf /* write the following sequence into fifo: 730056eeda2SDerek Robson * - tx_cfg 731056eeda2SDerek Robson * - size of message 732056eeda2SDerek Robson * - message 733056eeda2SDerek Robson */ 734874bcba6SMarcus Wolf mutex_lock(&device->tx_fifo_lock); 735874bcba6SMarcus Wolf retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg)); 736874bcba6SMarcus Wolf if ( retval != sizeof(instance->tx_cfg) ) 737874bcba6SMarcus Wolf goto abort; 738874bcba6SMarcus Wolf 739874bcba6SMarcus Wolf retval = kfifo_in (&device->tx_fifo, &count, sizeof(size_t)); 740874bcba6SMarcus Wolf if ( retval != sizeof(size_t) ) 741874bcba6SMarcus Wolf goto abort; 742874bcba6SMarcus Wolf 743874bcba6SMarcus Wolf retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied); 744874bcba6SMarcus Wolf if (retval || copied != count) 745874bcba6SMarcus Wolf goto abort; 746874bcba6SMarcus Wolf 747874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 748874bcba6SMarcus Wolf 749874bcba6SMarcus Wolf /* start transfer */ 750874bcba6SMarcus Wolf wake_up_interruptible(&device->tx_wait_queue); 751874bcba6SMarcus Wolf dev_dbg(device->dev, "write: generated new msg with %d bytes.", copied); 752874bcba6SMarcus Wolf 753874bcba6SMarcus Wolf return 0; 754874bcba6SMarcus Wolf 755874bcba6SMarcus Wolf abort: 756874bcba6SMarcus Wolf dev_dbg(device->dev, "write to fifo failed: 0x%x", retval); 757874bcba6SMarcus Wolf kfifo_reset(&device->tx_fifo); // TODO: maybe find a solution, not to discard already stored, valid entries 758874bcba6SMarcus Wolf mutex_unlock(&device->tx_fifo_lock); 759874bcba6SMarcus Wolf return -EAGAIN; 760874bcba6SMarcus Wolf } 761874bcba6SMarcus Wolf 762874bcba6SMarcus Wolf 763874bcba6SMarcus Wolf static long 764874bcba6SMarcus Wolf pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 765874bcba6SMarcus Wolf { 766874bcba6SMarcus Wolf int retval = 0; 767874bcba6SMarcus Wolf struct pi433_instance *instance; 768874bcba6SMarcus Wolf struct pi433_device *device; 76950271d38SAl Viro void __user *argp = (void __user *)arg; 770874bcba6SMarcus Wolf 771874bcba6SMarcus Wolf /* Check type and command number */ 772874bcba6SMarcus Wolf if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC) 773874bcba6SMarcus Wolf return -ENOTTY; 774874bcba6SMarcus Wolf 775874bcba6SMarcus Wolf /* TODO? guard against device removal before, or while, 776874bcba6SMarcus Wolf * we issue this ioctl. --> device_get() 777874bcba6SMarcus Wolf */ 778874bcba6SMarcus Wolf instance = filp->private_data; 779874bcba6SMarcus Wolf device = instance->device; 780874bcba6SMarcus Wolf 781874bcba6SMarcus Wolf if (device == NULL) 782874bcba6SMarcus Wolf return -ESHUTDOWN; 783874bcba6SMarcus Wolf 784874bcba6SMarcus Wolf switch (cmd) { 785874bcba6SMarcus Wolf case PI433_IOC_RD_TX_CFG: 78650271d38SAl Viro if (copy_to_user(argp, &instance->tx_cfg, 78750271d38SAl Viro sizeof(struct pi433_tx_cfg))) 78850271d38SAl Viro return -EFAULT; 789874bcba6SMarcus Wolf break; 790874bcba6SMarcus Wolf case PI433_IOC_WR_TX_CFG: 79150271d38SAl Viro if (copy_from_user(&instance->tx_cfg, argp, 79250271d38SAl Viro sizeof(struct pi433_tx_cfg))) 79350271d38SAl Viro return -EFAULT; 794874bcba6SMarcus Wolf break; 795874bcba6SMarcus Wolf case PI433_IOC_RD_RX_CFG: 79650271d38SAl Viro if (copy_to_user(argp, &device->rx_cfg, 79750271d38SAl Viro sizeof(struct pi433_rx_cfg))) 79850271d38SAl Viro return -EFAULT; 799874bcba6SMarcus Wolf break; 800874bcba6SMarcus Wolf case PI433_IOC_WR_RX_CFG: 801874bcba6SMarcus Wolf mutex_lock(&device->rx_lock); 802874bcba6SMarcus Wolf 803874bcba6SMarcus Wolf /* during pendig read request, change of config not allowed */ 804874bcba6SMarcus Wolf if (device->rx_active) { 805874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 80650271d38SAl Viro return -EAGAIN; 807874bcba6SMarcus Wolf } 808874bcba6SMarcus Wolf 80950271d38SAl Viro if (copy_from_user(&device->rx_cfg, argp, 81050271d38SAl Viro sizeof(struct pi433_rx_cfg))) { 811874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 81250271d38SAl Viro return -EFAULT; 813874bcba6SMarcus Wolf } 814874bcba6SMarcus Wolf 815874bcba6SMarcus Wolf mutex_unlock(&device->rx_lock); 816874bcba6SMarcus Wolf break; 817874bcba6SMarcus Wolf default: 818874bcba6SMarcus Wolf retval = -EINVAL; 819874bcba6SMarcus Wolf } 820874bcba6SMarcus Wolf 821874bcba6SMarcus Wolf return retval; 822874bcba6SMarcus Wolf } 823874bcba6SMarcus Wolf 824874bcba6SMarcus Wolf #ifdef CONFIG_COMPAT 825874bcba6SMarcus Wolf static long 826874bcba6SMarcus Wolf pi433_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 827874bcba6SMarcus Wolf { 828874bcba6SMarcus Wolf return pi433_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); 829874bcba6SMarcus Wolf } 830874bcba6SMarcus Wolf #else 831874bcba6SMarcus Wolf #define pi433_compat_ioctl NULL 832874bcba6SMarcus Wolf #endif /* CONFIG_COMPAT */ 833874bcba6SMarcus Wolf 834874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 835874bcba6SMarcus Wolf 836874bcba6SMarcus Wolf static int pi433_open(struct inode *inode, struct file *filp) 837874bcba6SMarcus Wolf { 838874bcba6SMarcus Wolf struct pi433_device *device; 839874bcba6SMarcus Wolf struct pi433_instance *instance; 840874bcba6SMarcus Wolf 841874bcba6SMarcus Wolf mutex_lock(&minor_lock); 842874bcba6SMarcus Wolf device = idr_find(&pi433_idr, iminor(inode)); 843874bcba6SMarcus Wolf mutex_unlock(&minor_lock); 844874bcba6SMarcus Wolf if (!device) { 845874bcba6SMarcus Wolf pr_debug("device: minor %d unknown.\n", iminor(inode)); 846874bcba6SMarcus Wolf return -ENODEV; 847874bcba6SMarcus Wolf } 848874bcba6SMarcus Wolf 849874bcba6SMarcus Wolf if (!device->rx_buffer) { 850874bcba6SMarcus Wolf device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL); 85169af5d92SSrishti Sharma if (!device->rx_buffer) { 852874bcba6SMarcus Wolf dev_dbg(device->dev, "open/ENOMEM\n"); 853874bcba6SMarcus Wolf return -ENOMEM; 854874bcba6SMarcus Wolf } 855874bcba6SMarcus Wolf } 856874bcba6SMarcus Wolf 857874bcba6SMarcus Wolf device->users++; 858874bcba6SMarcus Wolf instance = kzalloc(sizeof(*instance), GFP_KERNEL); 85969af5d92SSrishti Sharma if (!instance) { 860874bcba6SMarcus Wolf kfree(device->rx_buffer); 861874bcba6SMarcus Wolf device->rx_buffer = NULL; 862874bcba6SMarcus Wolf return -ENOMEM; 863874bcba6SMarcus Wolf } 864874bcba6SMarcus Wolf 865874bcba6SMarcus Wolf /* setup instance data*/ 866874bcba6SMarcus Wolf instance->device = device; 867874bcba6SMarcus Wolf instance->tx_cfg.bit_rate = 4711; 868874bcba6SMarcus Wolf // TODO: fill instance->tx_cfg; 869874bcba6SMarcus Wolf 870874bcba6SMarcus Wolf /* instance data as context */ 871874bcba6SMarcus Wolf filp->private_data = instance; 872874bcba6SMarcus Wolf nonseekable_open(inode, filp); 873874bcba6SMarcus Wolf 874874bcba6SMarcus Wolf return 0; 875874bcba6SMarcus Wolf } 876874bcba6SMarcus Wolf 877874bcba6SMarcus Wolf static int pi433_release(struct inode *inode, struct file *filp) 878874bcba6SMarcus Wolf { 879874bcba6SMarcus Wolf struct pi433_instance *instance; 880874bcba6SMarcus Wolf struct pi433_device *device; 881874bcba6SMarcus Wolf 882874bcba6SMarcus Wolf instance = filp->private_data; 883874bcba6SMarcus Wolf device = instance->device; 884874bcba6SMarcus Wolf kfree(instance); 885874bcba6SMarcus Wolf filp->private_data = NULL; 886874bcba6SMarcus Wolf 887874bcba6SMarcus Wolf /* last close? */ 888874bcba6SMarcus Wolf device->users--; 889874bcba6SMarcus Wolf 890874bcba6SMarcus Wolf if (!device->users) { 891874bcba6SMarcus Wolf kfree(device->rx_buffer); 892874bcba6SMarcus Wolf device->rx_buffer = NULL; 893874bcba6SMarcus Wolf if (device->spi == NULL) 894874bcba6SMarcus Wolf kfree(device); 895874bcba6SMarcus Wolf } 896874bcba6SMarcus Wolf 897874bcba6SMarcus Wolf return 0; 898874bcba6SMarcus Wolf } 899874bcba6SMarcus Wolf 900874bcba6SMarcus Wolf 901874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 902874bcba6SMarcus Wolf 903874bcba6SMarcus Wolf static int setup_GPIOs(struct pi433_device *device) 904874bcba6SMarcus Wolf { 905874bcba6SMarcus Wolf char name[5]; 906874bcba6SMarcus Wolf int retval; 907874bcba6SMarcus Wolf int i; 908ee26e236SCihangir Akturk const irq_handler_t DIO_irq_handler[NUM_DIO] = { 909ee26e236SCihangir Akturk DIO0_irq_handler, 910ee26e236SCihangir Akturk DIO1_irq_handler 911ee26e236SCihangir Akturk }; 912874bcba6SMarcus Wolf 913874bcba6SMarcus Wolf for (i=0; i<NUM_DIO; i++) 914874bcba6SMarcus Wolf { 915874bcba6SMarcus Wolf /* "construct" name and get the gpio descriptor */ 916874bcba6SMarcus Wolf snprintf(name, sizeof(name), "DIO%d", i); 917874bcba6SMarcus Wolf device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/); 918874bcba6SMarcus Wolf 91969af5d92SSrishti Sharma if (device->gpiod[i] == ERR_PTR(-ENOENT)) { 920874bcba6SMarcus Wolf dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name); 921874bcba6SMarcus Wolf continue; 922874bcba6SMarcus Wolf } 923874bcba6SMarcus Wolf 924874bcba6SMarcus Wolf if (device->gpiod[i] == ERR_PTR(-EBUSY)) 925874bcba6SMarcus Wolf dev_dbg(&device->spi->dev, "%s is busy.", name); 926874bcba6SMarcus Wolf 927874bcba6SMarcus Wolf if ( IS_ERR(device->gpiod[i]) ) 928874bcba6SMarcus Wolf { 929874bcba6SMarcus Wolf retval = PTR_ERR(device->gpiod[i]); 930874bcba6SMarcus Wolf /* release already allocated gpios */ 931874bcba6SMarcus Wolf for (i--; i>=0; i--) 932874bcba6SMarcus Wolf { 933874bcba6SMarcus Wolf free_irq(device->irq_num[i], device); 934874bcba6SMarcus Wolf gpiod_put(device->gpiod[i]); 935874bcba6SMarcus Wolf } 936874bcba6SMarcus Wolf return retval; 937874bcba6SMarcus Wolf } 938874bcba6SMarcus Wolf 939874bcba6SMarcus Wolf 940874bcba6SMarcus Wolf /* configure the pin */ 941874bcba6SMarcus Wolf gpiod_unexport(device->gpiod[i]); 942874bcba6SMarcus Wolf retval = gpiod_direction_input(device->gpiod[i]); 943874bcba6SMarcus Wolf if (retval) return retval; 944874bcba6SMarcus Wolf 945874bcba6SMarcus Wolf 946874bcba6SMarcus Wolf /* configure irq */ 947874bcba6SMarcus Wolf device->irq_num[i] = gpiod_to_irq(device->gpiod[i]); 94869af5d92SSrishti Sharma if (device->irq_num[i] < 0) { 949874bcba6SMarcus Wolf device->gpiod[i] = ERR_PTR(-EINVAL);//(struct gpio_desc *)device->irq_num[i]; 950874bcba6SMarcus Wolf return device->irq_num[i]; 951874bcba6SMarcus Wolf } 952874bcba6SMarcus Wolf retval = request_irq(device->irq_num[i], 953874bcba6SMarcus Wolf DIO_irq_handler[i], 954874bcba6SMarcus Wolf 0, /* flags */ 955874bcba6SMarcus Wolf name, 956874bcba6SMarcus Wolf device); 957874bcba6SMarcus Wolf 958874bcba6SMarcus Wolf if (retval) 959874bcba6SMarcus Wolf return retval; 960874bcba6SMarcus Wolf 9612ebd34caSHarsha Sharma dev_dbg(&device->spi->dev, "%s successfully configured", name); 962874bcba6SMarcus Wolf } 963874bcba6SMarcus Wolf 964874bcba6SMarcus Wolf return 0; 965874bcba6SMarcus Wolf } 966874bcba6SMarcus Wolf 967874bcba6SMarcus Wolf static void free_GPIOs(struct pi433_device *device) 968874bcba6SMarcus Wolf { 969874bcba6SMarcus Wolf int i; 970874bcba6SMarcus Wolf 971874bcba6SMarcus Wolf for (i=0; i<NUM_DIO; i++) 972874bcba6SMarcus Wolf { 973874bcba6SMarcus Wolf /* check if gpiod is valid */ 974874bcba6SMarcus Wolf if ( IS_ERR(device->gpiod[i]) ) 975874bcba6SMarcus Wolf continue; 976874bcba6SMarcus Wolf 977874bcba6SMarcus Wolf free_irq(device->irq_num[i], device); 978874bcba6SMarcus Wolf gpiod_put(device->gpiod[i]); 979874bcba6SMarcus Wolf } 980874bcba6SMarcus Wolf return; 981874bcba6SMarcus Wolf } 982874bcba6SMarcus Wolf 983874bcba6SMarcus Wolf static int pi433_get_minor(struct pi433_device *device) 984874bcba6SMarcus Wolf { 985874bcba6SMarcus Wolf int retval = -ENOMEM; 986874bcba6SMarcus Wolf 987874bcba6SMarcus Wolf mutex_lock(&minor_lock); 988874bcba6SMarcus Wolf retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL); 989874bcba6SMarcus Wolf if (retval >= 0) { 990874bcba6SMarcus Wolf device->minor = retval; 991874bcba6SMarcus Wolf retval = 0; 992874bcba6SMarcus Wolf } else if (retval == -ENOSPC) { 993d2cb4845SMarcin Ciupak dev_err(&device->spi->dev, "too many pi433 devices\n"); 994874bcba6SMarcus Wolf retval = -EINVAL; 995874bcba6SMarcus Wolf } 996874bcba6SMarcus Wolf mutex_unlock(&minor_lock); 997874bcba6SMarcus Wolf return retval; 998874bcba6SMarcus Wolf } 999874bcba6SMarcus Wolf 1000874bcba6SMarcus Wolf static void pi433_free_minor(struct pi433_device *dev) 1001874bcba6SMarcus Wolf { 1002874bcba6SMarcus Wolf mutex_lock(&minor_lock); 1003874bcba6SMarcus Wolf idr_remove(&pi433_idr, dev->minor); 1004874bcba6SMarcus Wolf mutex_unlock(&minor_lock); 1005874bcba6SMarcus Wolf } 1006874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 1007874bcba6SMarcus Wolf 1008874bcba6SMarcus Wolf static const struct file_operations pi433_fops = { 1009874bcba6SMarcus Wolf .owner = THIS_MODULE, 1010874bcba6SMarcus Wolf /* REVISIT switch to aio primitives, so that userspace 1011874bcba6SMarcus Wolf * gets more complete API coverage. It'll simplify things 1012874bcba6SMarcus Wolf * too, except for the locking. 1013874bcba6SMarcus Wolf */ 1014874bcba6SMarcus Wolf .write = pi433_write, 1015874bcba6SMarcus Wolf .read = pi433_read, 1016874bcba6SMarcus Wolf .unlocked_ioctl = pi433_ioctl, 1017874bcba6SMarcus Wolf .compat_ioctl = pi433_compat_ioctl, 1018874bcba6SMarcus Wolf .open = pi433_open, 1019874bcba6SMarcus Wolf .release = pi433_release, 1020874bcba6SMarcus Wolf .llseek = no_llseek, 1021874bcba6SMarcus Wolf }; 1022874bcba6SMarcus Wolf 1023874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 1024874bcba6SMarcus Wolf 1025874bcba6SMarcus Wolf static int pi433_probe(struct spi_device *spi) 1026874bcba6SMarcus Wolf { 1027874bcba6SMarcus Wolf struct pi433_device *device; 1028874bcba6SMarcus Wolf int retval; 1029874bcba6SMarcus Wolf 1030874bcba6SMarcus Wolf /* setup spi parameters */ 1031874bcba6SMarcus Wolf spi->mode = 0x00; 1032874bcba6SMarcus Wolf spi->bits_per_word = 8; 1033874bcba6SMarcus Wolf /* spi->max_speed_hz = 10000000; 1MHz already set by device tree overlay */ 1034874bcba6SMarcus Wolf 1035874bcba6SMarcus Wolf retval = spi_setup(spi); 1036874bcba6SMarcus Wolf if (retval) 1037874bcba6SMarcus Wolf { 1038874bcba6SMarcus Wolf dev_dbg(&spi->dev, "configuration of SPI interface failed!\n"); 1039874bcba6SMarcus Wolf return retval; 1040874bcba6SMarcus Wolf } 1041874bcba6SMarcus Wolf else 1042874bcba6SMarcus Wolf { 1043874bcba6SMarcus Wolf dev_dbg(&spi->dev, 1044874bcba6SMarcus Wolf "spi interface setup: mode 0x%2x, %d bits per word, %dhz max speed", 1045874bcba6SMarcus Wolf spi->mode, spi->bits_per_word, spi->max_speed_hz); 1046874bcba6SMarcus Wolf } 1047874bcba6SMarcus Wolf 1048874bcba6SMarcus Wolf /* Ping the chip by reading the version register */ 1049874bcba6SMarcus Wolf retval = spi_w8r8(spi, 0x10); 1050874bcba6SMarcus Wolf if (retval < 0) 1051874bcba6SMarcus Wolf return retval; 1052874bcba6SMarcus Wolf 10536feb5c82SXiangyang Zhang switch (retval) { 1054874bcba6SMarcus Wolf case 0x24: 105528eb8555SColin Ian King dev_dbg(&spi->dev, "found pi433 (ver. 0x%x)", retval); 1056874bcba6SMarcus Wolf break; 1057874bcba6SMarcus Wolf default: 1058874bcba6SMarcus Wolf dev_dbg(&spi->dev, "unknown chip version: 0x%x", retval); 1059874bcba6SMarcus Wolf return -ENODEV; 1060874bcba6SMarcus Wolf } 1061874bcba6SMarcus Wolf 1062874bcba6SMarcus Wolf /* Allocate driver data */ 1063874bcba6SMarcus Wolf device = kzalloc(sizeof(*device), GFP_KERNEL); 1064874bcba6SMarcus Wolf if (!device) 1065874bcba6SMarcus Wolf return -ENOMEM; 1066874bcba6SMarcus Wolf 1067874bcba6SMarcus Wolf /* Initialize the driver data */ 1068874bcba6SMarcus Wolf device->spi = spi; 1069874bcba6SMarcus Wolf device->rx_active = false; 1070874bcba6SMarcus Wolf device->tx_active = false; 1071874bcba6SMarcus Wolf device->interrupt_rx_allowed = false; 1072874bcba6SMarcus Wolf 1073874bcba6SMarcus Wolf /* init wait queues */ 1074874bcba6SMarcus Wolf init_waitqueue_head(&device->tx_wait_queue); 1075874bcba6SMarcus Wolf init_waitqueue_head(&device->rx_wait_queue); 1076874bcba6SMarcus Wolf init_waitqueue_head(&device->fifo_wait_queue); 1077874bcba6SMarcus Wolf 1078874bcba6SMarcus Wolf /* init fifo */ 1079874bcba6SMarcus Wolf INIT_KFIFO(device->tx_fifo); 1080874bcba6SMarcus Wolf 1081874bcba6SMarcus Wolf /* init mutexes and locks */ 1082874bcba6SMarcus Wolf mutex_init(&device->tx_fifo_lock); 1083874bcba6SMarcus Wolf mutex_init(&device->rx_lock); 1084874bcba6SMarcus Wolf 1085874bcba6SMarcus Wolf /* setup GPIO (including irq_handler) for the different DIOs */ 1086874bcba6SMarcus Wolf retval = setup_GPIOs(device); 108769af5d92SSrishti Sharma if (retval) { 1088874bcba6SMarcus Wolf dev_dbg(&spi->dev, "setup of GPIOs failed"); 1089874bcba6SMarcus Wolf goto GPIO_failed; 1090874bcba6SMarcus Wolf } 1091874bcba6SMarcus Wolf 1092874bcba6SMarcus Wolf /* setup the radio module */ 1093874bcba6SMarcus Wolf SET_CHECKED(rf69_set_mode (spi, standby)); 1094874bcba6SMarcus Wolf SET_CHECKED(rf69_set_data_mode (spi, packet)); 1095874bcba6SMarcus Wolf SET_CHECKED(rf69_set_amplifier_0 (spi, optionOn)); 1096874bcba6SMarcus Wolf SET_CHECKED(rf69_set_amplifier_1 (spi, optionOff)); 1097874bcba6SMarcus Wolf SET_CHECKED(rf69_set_amplifier_2 (spi, optionOff)); 1098874bcba6SMarcus Wolf SET_CHECKED(rf69_set_output_power_level (spi, 13)); 1099874bcba6SMarcus Wolf SET_CHECKED(rf69_set_antenna_impedance (spi, fiftyOhm)); 1100874bcba6SMarcus Wolf 1101874bcba6SMarcus Wolf /* determ minor number */ 1102874bcba6SMarcus Wolf retval = pi433_get_minor(device); 110369af5d92SSrishti Sharma if (retval) { 1104d2cb4845SMarcin Ciupak dev_dbg(&spi->dev, "get of minor number failed"); 1105874bcba6SMarcus Wolf goto minor_failed; 1106874bcba6SMarcus Wolf } 1107874bcba6SMarcus Wolf 1108874bcba6SMarcus Wolf /* create device */ 1109874bcba6SMarcus Wolf device->devt = MKDEV(MAJOR(pi433_dev), device->minor); 1110874bcba6SMarcus Wolf device->dev = device_create(pi433_class, 1111874bcba6SMarcus Wolf &spi->dev, 1112874bcba6SMarcus Wolf device->devt, 1113874bcba6SMarcus Wolf device, 111499ee4774SMarcin Ciupak "pi433.%d", 111599ee4774SMarcin Ciupak device->minor); 1116874bcba6SMarcus Wolf if (IS_ERR(device->dev)) { 1117874bcba6SMarcus Wolf pr_err("pi433: device register failed\n"); 1118874bcba6SMarcus Wolf retval = PTR_ERR(device->dev); 1119874bcba6SMarcus Wolf goto device_create_failed; 1120874bcba6SMarcus Wolf } 1121874bcba6SMarcus Wolf else { 1122874bcba6SMarcus Wolf dev_dbg(device->dev, 1123874bcba6SMarcus Wolf "created device for major %d, minor %d\n", 1124874bcba6SMarcus Wolf MAJOR(pi433_dev), 1125874bcba6SMarcus Wolf device->minor); 1126874bcba6SMarcus Wolf } 1127874bcba6SMarcus Wolf 1128d2cb4845SMarcin Ciupak /* start tx thread */ 1129d2cb4845SMarcin Ciupak device->tx_task_struct = kthread_run(pi433_tx_thread, 1130d2cb4845SMarcin Ciupak device, 113199ee4774SMarcin Ciupak "pi433.%d_tx_task", 113299ee4774SMarcin Ciupak device->minor); 1133d2cb4845SMarcin Ciupak if (IS_ERR(device->tx_task_struct)) { 1134d2cb4845SMarcin Ciupak dev_dbg(device->dev, "start of send thread failed"); 1135d2cb4845SMarcin Ciupak goto send_thread_failed; 1136d2cb4845SMarcin Ciupak } 1137d2cb4845SMarcin Ciupak 1138874bcba6SMarcus Wolf /* create cdev */ 1139874bcba6SMarcus Wolf device->cdev = cdev_alloc(); 1140874bcba6SMarcus Wolf device->cdev->owner = THIS_MODULE; 1141874bcba6SMarcus Wolf cdev_init(device->cdev, &pi433_fops); 1142874bcba6SMarcus Wolf retval = cdev_add(device->cdev, device->devt, 1); 114369af5d92SSrishti Sharma if (retval) { 1144874bcba6SMarcus Wolf dev_dbg(device->dev, "register of cdev failed"); 1145874bcba6SMarcus Wolf goto cdev_failed; 1146874bcba6SMarcus Wolf } 1147874bcba6SMarcus Wolf 1148874bcba6SMarcus Wolf /* spi setup */ 1149874bcba6SMarcus Wolf spi_set_drvdata(spi, device); 1150874bcba6SMarcus Wolf 1151874bcba6SMarcus Wolf return 0; 1152874bcba6SMarcus Wolf 1153874bcba6SMarcus Wolf cdev_failed: 1154d2cb4845SMarcin Ciupak kthread_stop(device->tx_task_struct); 1155d2cb4845SMarcin Ciupak send_thread_failed: 1156874bcba6SMarcus Wolf device_destroy(pi433_class, device->devt); 1157874bcba6SMarcus Wolf device_create_failed: 1158874bcba6SMarcus Wolf pi433_free_minor(device); 1159874bcba6SMarcus Wolf minor_failed: 1160874bcba6SMarcus Wolf free_GPIOs(device); 1161874bcba6SMarcus Wolf GPIO_failed: 1162874bcba6SMarcus Wolf kfree(device); 1163874bcba6SMarcus Wolf 1164874bcba6SMarcus Wolf return retval; 1165874bcba6SMarcus Wolf } 1166874bcba6SMarcus Wolf 1167874bcba6SMarcus Wolf static int pi433_remove(struct spi_device *spi) 1168874bcba6SMarcus Wolf { 1169874bcba6SMarcus Wolf struct pi433_device *device = spi_get_drvdata(spi); 1170874bcba6SMarcus Wolf 1171874bcba6SMarcus Wolf /* free GPIOs */ 1172874bcba6SMarcus Wolf free_GPIOs(device); 1173874bcba6SMarcus Wolf 1174874bcba6SMarcus Wolf /* make sure ops on existing fds can abort cleanly */ 1175874bcba6SMarcus Wolf device->spi = NULL; 1176874bcba6SMarcus Wolf 1177874bcba6SMarcus Wolf kthread_stop(device->tx_task_struct); 1178874bcba6SMarcus Wolf 1179874bcba6SMarcus Wolf device_destroy(pi433_class, device->devt); 1180874bcba6SMarcus Wolf 1181874bcba6SMarcus Wolf cdev_del(device->cdev); 1182874bcba6SMarcus Wolf 1183874bcba6SMarcus Wolf pi433_free_minor(device); 1184874bcba6SMarcus Wolf 1185874bcba6SMarcus Wolf if (device->users == 0) 1186874bcba6SMarcus Wolf kfree(device); 1187874bcba6SMarcus Wolf 1188874bcba6SMarcus Wolf return 0; 1189874bcba6SMarcus Wolf } 1190874bcba6SMarcus Wolf 1191874bcba6SMarcus Wolf static const struct of_device_id pi433_dt_ids[] = { 1192874bcba6SMarcus Wolf { .compatible = "Smarthome-Wolf,pi433" }, 1193874bcba6SMarcus Wolf {}, 1194874bcba6SMarcus Wolf }; 1195874bcba6SMarcus Wolf 1196874bcba6SMarcus Wolf MODULE_DEVICE_TABLE(of, pi433_dt_ids); 1197874bcba6SMarcus Wolf 1198874bcba6SMarcus Wolf static struct spi_driver pi433_spi_driver = { 1199874bcba6SMarcus Wolf .driver = { 1200874bcba6SMarcus Wolf .name = "pi433", 1201874bcba6SMarcus Wolf .owner = THIS_MODULE, 1202874bcba6SMarcus Wolf .of_match_table = of_match_ptr(pi433_dt_ids), 1203874bcba6SMarcus Wolf }, 1204874bcba6SMarcus Wolf .probe = pi433_probe, 1205874bcba6SMarcus Wolf .remove = pi433_remove, 1206874bcba6SMarcus Wolf 1207874bcba6SMarcus Wolf /* NOTE: suspend/resume methods are not necessary here. 1208874bcba6SMarcus Wolf * We don't do anything except pass the requests to/from 1209874bcba6SMarcus Wolf * the underlying controller. The refrigerator handles 1210874bcba6SMarcus Wolf * most issues; the controller driver handles the rest. 1211874bcba6SMarcus Wolf */ 1212874bcba6SMarcus Wolf }; 1213874bcba6SMarcus Wolf 1214874bcba6SMarcus Wolf /*-------------------------------------------------------------------------*/ 1215874bcba6SMarcus Wolf 1216874bcba6SMarcus Wolf static int __init pi433_init(void) 1217874bcba6SMarcus Wolf { 1218874bcba6SMarcus Wolf int status; 1219874bcba6SMarcus Wolf 1220874bcba6SMarcus Wolf /* If MAX_MSG_SIZE is smaller then FIFO_SIZE, the driver won't 1221056eeda2SDerek Robson * work stable - risk of buffer overflow 1222056eeda2SDerek Robson */ 1223874bcba6SMarcus Wolf if (MAX_MSG_SIZE < FIFO_SIZE) 1224874bcba6SMarcus Wolf return -EINVAL; 1225874bcba6SMarcus Wolf 1226874bcba6SMarcus Wolf /* Claim device numbers. Then register a class 1227874bcba6SMarcus Wolf * that will key udev/mdev to add/remove /dev nodes. Last, register 1228874bcba6SMarcus Wolf * Last, register the driver which manages those device numbers. 1229874bcba6SMarcus Wolf */ 1230874bcba6SMarcus Wolf status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/); 1231874bcba6SMarcus Wolf if (status < 0) 1232874bcba6SMarcus Wolf return status; 1233874bcba6SMarcus Wolf 1234874bcba6SMarcus Wolf pi433_class = class_create(THIS_MODULE, "pi433"); 123569af5d92SSrishti Sharma if (IS_ERR(pi433_class)) { 1236874bcba6SMarcus Wolf unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); 1237874bcba6SMarcus Wolf return PTR_ERR(pi433_class); 1238874bcba6SMarcus Wolf } 1239874bcba6SMarcus Wolf 1240874bcba6SMarcus Wolf status = spi_register_driver(&pi433_spi_driver); 124169af5d92SSrishti Sharma if (status < 0) { 1242874bcba6SMarcus Wolf class_destroy(pi433_class); 1243874bcba6SMarcus Wolf unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); 1244874bcba6SMarcus Wolf } 1245874bcba6SMarcus Wolf 1246874bcba6SMarcus Wolf return status; 1247874bcba6SMarcus Wolf } 1248874bcba6SMarcus Wolf 1249874bcba6SMarcus Wolf module_init(pi433_init); 1250874bcba6SMarcus Wolf 1251874bcba6SMarcus Wolf static void __exit pi433_exit(void) 1252874bcba6SMarcus Wolf { 1253874bcba6SMarcus Wolf spi_unregister_driver(&pi433_spi_driver); 1254874bcba6SMarcus Wolf class_destroy(pi433_class); 1255874bcba6SMarcus Wolf unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); 1256874bcba6SMarcus Wolf } 1257874bcba6SMarcus Wolf module_exit(pi433_exit); 1258874bcba6SMarcus Wolf 1259874bcba6SMarcus Wolf MODULE_AUTHOR("Marcus Wolf, <linux@wolf-entwicklungen.de>"); 1260874bcba6SMarcus Wolf MODULE_DESCRIPTION("Driver for Pi433"); 1261874bcba6SMarcus Wolf MODULE_LICENSE("GPL"); 1262874bcba6SMarcus Wolf MODULE_ALIAS("spi:pi433"); 1263