linux 驱动cc1101
cc110x.h
/*
* File: cc110x.h
* Author: elinux
*
* Created on 2015年4月7日, 上午10:32
*/
#ifndef CC110X_H
#define CC110X_H
#ifdef __cplusplus
extern "C" {
#endif
#define WRITE_BURST 0x40 //连续写入
#define READ_SINGLE 0x80 //读
#define READ_BURST 0xC0 //连续读
#define BYTES_IN_RXFIFO 0x7F //接收缓冲区的有效字节数
#define CRC_OK 0x80 //CRC校验通过位标志
#define CCxxx0_IOCFG2 0x00 // GDO2 output pin configuration
#define CCxxx0_IOCFG1 0x01 // GDO1 output pin configuration
#define CCxxx0_IOCFG0 0x02 // GDO0 output pin configuration
#define CCxxx0_FIFOTHR 0x03 // RX FIFO and TX FIFO thresholds
#define CCxxx0_SYNC1 0x04 // Sync word, high u8
#define CCxxx0_SYNC0 0x05 // Sync word, low u8
#define CCxxx0_PKTLEN 0x06 // Packet length
#define CCxxx0_PKTCTRL1 0x07 // Packet automation control
#define CCxxx0_PKTCTRL0 0x08 // Packet automation control
#define CCxxx0_ADDR 0x09 // Device address
#define CCxxx0_CHANNR 0x0A // Channel number
#define CCxxx0_FSCTRL1 0x0B // Frequency synthesizer control
#define CCxxx0_FSCTRL0 0x0C // Frequency synthesizer control
#define CCxxx0_FREQ2 0x0D // Frequency control word, high u8
#define CCxxx0_FREQ1 0x0E // Frequency control word, middle u8
#define CCxxx0_FREQ0 0x0F // Frequency control word, low u8
#define CCxxx0_MDMCFG4 0x10 // Modem configuration
#define CCxxx0_MDMCFG3 0x11 // Modem configuration
#define CCxxx0_MDMCFG2 0x12 // Modem configuration
#define CCxxx0_MDMCFG1 0x13 // Modem configuration
#define CCxxx0_MDMCFG0 0x14 // Modem configuration
#define CCxxx0_DEVIATN 0x15 // Modem deviation setting
#define CCxxx0_MCSM2 0x16 // Main Radio Control State Machine configuration
#define CCxxx0_MCSM1 0x17 // Main Radio Control State Machine configuration
#define CCxxx0_MCSM0 0x18 // Main Radio Control State Machine configuration
#define CCxxx0_FOCCFG 0x19 // Frequency Offset Compensation configuration
#define CCxxx0_BSCFG 0x1A // Bit Synchronization configuration
#define CCxxx0_AGCCTRL2 0x1B // AGC control
#define CCxxx0_AGCCTRL1 0x1C // AGC control
#define CCxxx0_AGCCTRL0 0x1D // AGC control
#define CCxxx0_WOREVT1 0x1E // High u8 Event 0 timeout
#define CCxxx0_WOREVT0 0x1F // Low u8 Event 0 timeout
#define CCxxx0_WORCTRL 0x20 // Wake On Radio control
#define CCxxx0_FREND1 0x21 // Front end RX configuration
#define CCxxx0_FREND0 0x22 // Front end TX configuration
#define CCxxx0_FSCAL3 0x23 // Frequency synthesizer calibration
#define CCxxx0_FSCAL2 0x24 // Frequency synthesizer calibration
#define CCxxx0_FSCAL1 0x25 // Frequency synthesizer calibration
#define CCxxx0_FSCAL0 0x26 // Frequency synthesizer calibration
#define CCxxx0_RCCTRL1 0x27 // RC oscillator configuration
#define CCxxx0_RCCTRL0 0x28 // RC oscillator configuration
#define CCxxx0_FSTEST 0x29 // Frequency synthesizer calibration control
#define CCxxx0_PTEST 0x2A // Production test
#define CCxxx0_AGCTEST 0x2B // AGC test
#define CCxxx0_TEST2 0x2C // Various test settings
#define CCxxx0_TEST1 0x2D // Various test settings
#define CCxxx0_TEST0 0x2E // Various test settings
// Strobe commands
#define CCxxx0_SRES 0x30 // Reset chip.
#define CCxxx0_SFSTXON 0x31 // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
// If in RX/TX: Go to a wait state where only the synthesizer is
// running (for quick RX / TX turnaround).
#define CCxxx0_SXOFF 0x32 // Turn off crystal oscillator.
#define CCxxx0_SCAL 0x33 // Calibrate frequency synthesizer and turn it off
// (enables quick start).
#define CCxxx0_SRX 0x34 // Enable RX. Perform calibration first if coming from IDLE and
// MCSM0.FS_AUTOCAL=1.
#define CCxxx0_STX 0x35 // In IDLE state: Enable TX. Perform calibration first if
// MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
// Only go to TX if channel is clear.
#define CCxxx0_SIDLE 0x36 // Exit RX / TX, turn off frequency synthesizer and exit
// Wake-On-Radio mode if applicable.
#define CCxxx0_SAFC 0x37 // Perform AFC adjustment of the frequency synthesizer
#define CCxxx0_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio)
#define CCxxx0_SPWD 0x39 // Enter power down mode when CSn goes high.
#define CCxxx0_SFRX 0x3A // Flush the RX FIFO buffer.
#define CCxxx0_SFTX 0x3B // Flush the TX FIFO buffer.
#define CCxxx0_SWORRST 0x3C // Reset real time clock.
#define CCxxx0_SNOP 0x3D // No operation. May be used to pad strobe commands to two
// u8s for simpler software.
#define CCxxx0_PARTNUM 0x30
#define CCxxx0_VERSION 0x31
#define CCxxx0_FREQEST 0x32
#define CCxxx0_LQI 0x33
#define CCxxx0_RSSI 0x34
#define CCxxx0_MARCSTATE 0x35
#define CCxxx0_WORTIME1 0x36
#define CCxxx0_WORTIME0 0x37
#define CCxxx0_PKTSTATUS 0x38
#define CCxxx0_VCO_VC_DAC 0x39
#define CCxxx0_TXBYTES 0x3A
#define CCxxx0_RXBYTES 0x3B
#define CCxxx0_PATABLE 0x3E
#define CCxxx0_TXFIFO 0x3F
#define CCxxx0_RXFIFO 0x3F
#define CC1101_BUFLEN 16
// RF_SETTINGS is a data structure which contains all relevant CCxxx0 registers
typedef struct {
u8 iocfg0; // GDO0 Output Pin Configuration
u8 fifothr; // RX FIFO and TX FIFO Thresholds
u8 pktctrl0; // Packet Automation Control
u8 fsctrl1; // Frequency Synthesizer Control
u8 freq2; // Frequency Control Word, High Byte
u8 freq1; // Frequency Control Word, Middle Byte
u8 freq0; // Frequency Control Word, Low Byte
u8 mdmcfg4; // Modem Configuration
u8 mdmcfg3; // Modem Configuration
u8 mdmcfg2; // Modem Configuration
u8 deviatn; // Modem Deviation Setting
u8 mcsm0; // Main Radio Control State Machine Configuration
u8 foccfg; // Frequency Offset Compensation Configuration
u8 worctrl; // Wake On Radio Control
u8 fscal3; // Frequency Synthesizer Calibration
u8 fscal2; // Frequency Synthesizer Calibration
u8 fscal1; // Frequency Synthesizer Calibration
u8 fscal0; // Frequency Synthesizer Calibration
u8 test2; // Various Test Settings
u8 test1; // Various Test Settings
u8 test0; // Various Test Settings
} RF_SETTINGS;
/*
* Some registers must be read back to modify.
* To save time we cache them here in memory.
*/
struct cc110x_chip {
struct spi_device *spi;
struct cdev cdev;
dev_t devNo;
int irqNo;
int pin_rdy;
wait_queue_head_t read_wait;
volatile int rcv_flag;
unsigned char cc1101_buf[CC1101_BUFLEN];
};
#ifdef __cplusplus
}
#endif
#endif /* CC110X_H */
cc110x.c
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/freezer.h>
#include <linux/workqueue.h>
#include <linux/export.h>
#include "cc110x.h"
#include <linux/irq.h>
#include <linux/timer.h>
//*****************************************************************************************
//SpiTxRxByte(struct cc11xx_chip *chip, u8 dat)
//*****************************************************************************************
int SpiTxRxByte(struct cc11xx_chip *chip, u8 dat) {
struct spi_message m;
struct spi_transfer xfer;
u8 w, r;
int rc;
spi_message_init(&m);
memset(&xfer, 0, sizeof (xfer));
w = dat;
xfer.tx_buf = &w;
xfer.rx_buf = &r;
xfer.bits_per_word = 8;
xfer.len = 1;
spi_message_add_tail(&xfer, &m);
rc = spi_sync(chip->spi, &m);
if (rc) {
dev_err(&chip->spi->dev, "VK32xx write error\n");
return -EIO;
}
return r;
}
//*****************************************************************************************
//RESET_CC1100
//*****************************************************************************************
void RESET_CC1100(struct cc11xx_chip *chip) {
SpiTxRxByte(chip, CCxxx0_SRES); //
}
//*****************************************************************************************
//void halSpiWriteReg(INT8U addr, INT8U value)
//*****************************************************************************************
int halSpiWriteReg(struct cc11xx_chip *chip, u8 addr, u8 val) {
struct spi_message m;
struct spi_transfer xfer;
u8 w[2];
int rc;
spi_message_init(&m);
memset(&xfer, 0, sizeof (xfer));
w[0] = addr;
w[1] = val;
xfer.tx_buf = &w[0];
xfer.bits_per_word = 8;
xfer.len = 2;
spi_message_add_tail(&xfer, &m);
rc = spi_sync(chip->spi, &m);
if (rc) {
dev_err(&chip->spi->dev, "cc1101 write error\n");
return -EIO;
}
return 0;
}
//*****************************************************************************************
//halSpiWriteBurstReg
//*****************************************************************************************
int halSpiWriteBurstReg(struct cc11xx_chip *chip, u8 addr, u8 *buffer, u8 cnt) {
struct spi_message m;
struct spi_transfer xfer;
u8 w[cnt];
int rc;
spi_message_init(&m);
memset(&xfer, 0, sizeof (xfer));
for (i = 0; i < cnt; i++) {
w[i] = buffer[i];
}
SpiTxRxByte(chip, addr | WRITE_BURST);
xfer.tx_buf = &w[0];
xfer.bits_per_word = 8;
xfer.len = cnt;
spi_message_add_tail(&xfer, &m);
rc = spi_sync(chip->spi, &m);
if (rc) {
dev_err(&chip->spi->dev, "cc1101 write burst mode error\n");
return -EIO;
}
return 0;
}
//*****************************************************************************************
//halSpiStrobe
//*****************************************************************************************
void halSpiStrobe(struct cc11xx_chip *chip,u8 strobe) {
SpiTxRxByte(chip,strobe); //
}
//*****************************************************************************************
//halSpiReadReg
//*****************************************************************************************
u8 halSpiReadReg(struct cc11xx_chip *chip, u8 addr) {
SpiTxRxByte(chip, addr | READ_SINGLE);
return SpiTxRxByte(chip, 0);
}
//*****************************************************************************************
//halSpiReadBurstReg
//*****************************************************************************************
void halSpiReadBurstReg(struct cc11xx_chip *chip,u8 addr, u8 *buffer, u8 cnt) {
struct spi_message m;
struct spi_transfer xfer;
u8 r[cnt],i;
SpiTxRxByte(chip, addr | READ_BURST);
spi_message_init(&m);
for(i =0 ;i < cnt; i++)
r[i] = 0x00;
memset(&xfer, 0, sizeof (xfer));
xfer.rx_buf = &r[0];
xfer.bits_per_word = 8;
xfer.len = cnt;
spi_message_add_tail(&xfer, &m);
rc = spi_sync(chip->spi, &m);
if (rc) {
dev_err(&chip->spi->dev, "cc110x write error\n");
return -EIO;
}
for (i = 0; i < cnt; i++) {
buffer[i] = r[i];
}
return 0;
}
//*****************************************************************************************
//u8 halSpiReadReg(INT8U addr)
//*****************************************************************************************
u8 halSpiReadStatus(struct cc11xx_chip *chip, u8 addr) {
SpiTxRxByte(chip, addr | READ_BURST);
return SpiTxRxByte(chip, 0);
}
//*****************************************************************************************
//oid halRfWriteRfSettings(RF_SETTINGS *pRfSettings)
//*****************************************************************************************
void halRfWriteRfSettings(struct cc11xx_chip *chip) {
//*******************************rfSettingsSmart RF***********************************//
//*******************************Low data rate----2.4kbaud**************************************//
//*******************************Carrier frequency-----433.99MHz********************************//
RF_SETTINGS rfSettings = {
0x06, // IOCFG0 GDO0 Output Pin Configuration
0x47, // FIFOTHR RX FIFO and TX FIFO Thresholds
0x05, // PKTCTRL0 Packet Automation Control
0x06, // FSCTRL1 Frequency Synthesizer Control
0x10, // FREQ2 Frequency Control Word, High Byte
0xB1, // FREQ1 Frequency Control Word, Middle Byte
0x3B, // FREQ0 Frequency Control Word, Low Byte
0xF6, // MDMCFG4 Modem Configuration
0x83, // MDMCFG3 Modem Configuration
0x13, // MDMCFG2 Modem Configuration
0x15, // DEVIATN Modem Deviation Setting
0x18, // MCSM0 Main Radio Control State Machine Configuration
0x16, // FOCCFG Frequency Offset Compensation Configuration
0xFB, // WORCTRL Wake On Radio Control
0xE9, // FSCAL3 Frequency Synthesizer Calibration
0x2A, // FSCAL2 Frequency Synthesizer Calibration
0x00, // FSCAL1 Frequency Synthesizer Calibration
0x1F, // FSCAL0 Frequency Synthesizer Calibration
0x81, // TEST2 Various Test Settings
0x35, // TEST1 Various Test Settings
0x09, // TEST0 Various Test Settings
};
halSpiWriteReg(chip, CCxxx0_IOCFG0, rfSettings.iocfg0);
halSpiWriteReg(chip, CCxxx0_FIFOTHR, rfSettings.fifothr);
halSpiWriteReg(chip, CCxxx0_PKTCTRL0, rfSettings.pktctrl0);
halSpiWriteReg(chip, CCxxx0_FSCTRL1, rfSettings.fsctrl1);
halSpiWriteReg(chip, CCxxx0_FREQ2, rfSettings.freq2);
halSpiWriteReg(chip, CCxxx0_FREQ1, rfSettings.freq1);
halSpiWriteReg(chip, CCxxx0_FREQ0, rfSettings.freq0);
halSpiWriteReg(chip, CCxxx0_MDMCFG4, rfSettings.mdmcfg4);
halSpiWriteReg(chip,CCxxx0_MDMCFG3, rfSettings.mdmcfg3);
halSpiWriteReg(chip, CCxxx0_MDMCFG2, rfSettings.mdmcfg2);
halSpiWriteReg(chip, CCxxx0_DEVIATN, rfSettings.deviatn);
halSpiWriteReg(chip, CCxxx0_MCSM0, rfSettings.mcsm0);
halSpiWriteReg(chip, CCxxx0_FOCCFG, rfSettings.foccfg);
halSpiWriteReg(chip, CCxxx0_WORCTRL, rfSettings.worctrl);
halSpiWriteReg(chip, CCxxx0_FSCAL3, rfSettings.fscal3);
halSpiWriteReg(chip, CCxxx0_FSCAL2, rfSettings.fscal2);
halSpiWriteReg(chip, CCxxx0_FSCAL1, rfSettings.fscal1);
halSpiWriteReg(chip, CCxxx0_FSCAL0, rfSettings.fscal0);
halSpiWriteReg(chip, CCxxx0_TEST2, rfSettings.test2);
halSpiWriteReg(chip, CCxxx0_TEST1, rfSettings.test1);
halSpiWriteReg(chip, CCxxx0_TEST0, rfSettings.test0);
}
//*****************************************************************************************
//halRfSendPacket
//*****************************************************************************************
void halRfSendPacket(struct cc11xx_chip *chip, u8 *txBuffer, u8 size) {
halSpiStrobe(chip, CCxxx0_SIDLE);
halSpiStrobe(chip, CCxxx0_STX);
halSpiWriteReg(chip, CCxxx0_TXFIFO, size);
halSpiWriteBurstReg(chip, CCxxx0_TXFIFO, txBuffer, size);
// Wait for GDO0 to be set -> sync transmitted
while (!gpio_get_value(chip->pin_rdy));
// Wait for GDO0 to be cleared -> end of packet
while (gpio_get_value(chip->pin_rdy));
halSpiStrobe(chip, CCxxx0_SFTX);
halSpiStrobe(chip, CCxxx0_SIDLE);
halSpiStrobe(chip, CCxxx0_SRX);
}
//************************************************************************************************//
//halRfReceivePacket
//***********************************************************************************************//
u8 halRfReceivePacket(struct cc11xx_chip *chip,u8 *rxBuffer, u8 *length) {
u8 status[2];
u8 packetLength;
u8 i = (*length)*4;
halSpiStrobe(chip,CCxxx0_SIDLE);
halSpiStrobe(chip,CCxxx0_SRX); //
udelay(20);
while (gpio_get_value(chip->pin_rdy)) {
udelay(20);
--i;
if (i < 1)
return 0;
}
if ((halSpiReadStatus(chip,CCxxx0_RXBYTES) & BYTES_IN_RXFIFO))
{
packetLength = halSpiReadReg(chip,CCxxx0_RXFIFO);
if (packetLength <= *length) //
{
halSpiReadBurstReg(chip,CCxxx0_RXFIFO, rxBuffer, packetLength); //
*length = packetLength; //
// Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI)
halSpiReadBurstReg(chip,CCxxx0_RXFIFO, status, 2);
halSpiStrobe(chip,CCxxx0_SFRX);
return (status[1] & CRC_OK);
}
else {
*length = packetLength;
halSpiStrobe(chip,CCxxx0_SFRX); //
return 0;
}
}
else
return 0;
}
/*
**************************************************************************************
*cc1101_rcv_interrupt(int irq, void *dev_id)
**************************************************************************************
*/
static irqreturn_t cc1101_rcv_interrupt(int irq, void *dev_id) {
struct cc110x_chip *chip = (struct cc110x_chip *)dev_id ;
u8 count = CC1101_BUFLEN;
int ret;
printk(KERN_DEBUG "cc1101 handle interrupt!\n");
ret = halRfReceivePacket(chip, chip->cc1101_buf, &count);
if (0 != ret) {
printk(KERN_DEBUG "cc1101 receiving .... start\n");
printk(KERN_DEBUG "cc1101 receiving .... end\n");
printk(KERN_DEBUG "cc1101 receiving %d bytes(s):%s\n", count, chip->cc1101_buf);
chip->rcv_flag = 1;
wake_up_interruptible(&chip->read_wait);
}
return IRQ_RETVAL(IRQ_HANDLED);
}
/*cc1101_open*/
int cc1101_open(struct inode *inode, struct file *filp) {
struct cc110x_chip *chip;
int ret;
chip = container_of(inode->i_cdev, struct cc110x_chip, cdev);
filp->private_data = chip;
ret = request_irq(chip->irq, cc1101_rcv_interrupt,
IRQ_TYPE_EDGE_FALLING,
"cc1101",
(void *) chip);
if (ret) {
printk(KERN_DEBUG "request_irq error!\n");
return -EBUSY;
}
return 0;
}
/*写函数*/
static ssize_t cc1101_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) {
struct cc110x_chip *chip = filp->private_data;
unsigned int count = size;
int ret = 0;
if (CC1101_BUFLEN != size) {
printk(KERN_DEBUG "cc1101 write wrong len:%d\n", size);
return -ENOMEM;
}
if (copy_from_user(chip->cc1101_buf, buf, count))
ret = -EFAULT;
else {
ret = count;
printk(KERN_DEBUG "kernel-space: cc1101 written %d bytes(s):%s\n",
count, chip->cc1101_buf);
}
/* CC1101 */
printk(KERN_DEBUG "kernel-space: cc1101 sending .... start\n");
halRfSendPacket(chip, chip->cc1101_buf, count);
printk(KERN_DEBUG "kernel-space: cc1101 sending .... end\n");
return ret;
}
/* cc1101_waitqueue_read */
static ssize_t cc1101_waitqueue_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) {
struct cc110x_chip *chip = filp->private_data;
unsigned int count = size;
int ret = 0;
DECLARE_WAITQUEUE(wait, current);
if (CC1101_BUFLEN != count) {
printk(KERN_DEBUG "kernel-space: cc1101 read wrong len:%d\n", count);
return -ENOMEM;
}
add_wait_queue(&chip->read_wait, &wait);
if (0 == chip->rcv_flag) {
if (filp->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
ret = -ERESTARTSYS;
goto out;
}
}
/* 内核空间->用户空间 */
copy_to_user(buf, chip->cc1101_buf, count);
ret = count;
out:
remove_wait_queue(&chip->read_wait, &wait);
set_current_state(TASK_RUNNING);
chip->rcv_flag = 0;
return ret;
}
/*
* poll
*/
static unsigned int cc1101_poll(struct file *filp, poll_table *wait) {
struct cc110x_chip *chip = filp->private_data;
unsigned int mask = 0;
poll_wait(filp, &chip->read_wait, wait);
if (1 == chip->rcv_flag) {
mask |= POLLIN | POLLRDNORM;
printk(KERN_DEBUG "kernel-space: cc1101_poll rcv_flag = 1!\n");
}
return mask;
}
static int cc1101_close(struct inode *inode, struct file *filp) {
struct cc110x_chip *chip = filp->private_data;
free_irq(chip->irq, chip);
printk("kernel-space: cc1101_close!\n");
return 0;
}
struct file_operations cc1101_fops = {
.owner = THIS_MODULE,
.open = cc1101_open,
.release = cc1101_close,
.write = cc1101_write,
.read = cc1101_waitqueue_read,
.poll = cc1101_poll,
};
//cc1101_setup
static int cc1101_setup(struct cc11xx_chip *chip) {
u8 tbl[8] = {0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60};
RESET_CC1100(chip);
halRfWriteRfSettings(chip);
halSpiWriteBurstReg(chip, CCxxx0_PATABLE, tbl, 8);
return 0;
}
/*cc1101_probe
*
*/
struct class *cc1101_class;
static int __devinit cc1101_probe(struct spi_device *spi) {
struct cc110x_chip *chip;
int ret;
chip = kzalloc(sizeof (struct vk32xx_chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
spi_set_drvdata(spi, chip);
chip->spi = spi;
chip->irqNo = spi->irq;
spi_setup(spi);
ret = alloc_chrdev_region(&chip->devNo, 0, 1, "cc1101");
if (ret)
return ret;
init_waitqueue_head(&chip->read_wait);
cdev_init(&chip->cdev, &cc1101_fops);
chip->cdev.owner = THIS_MODULE;
chip->cdev.ops = &cc1101_fops;
ret = cdev_add(&chip->cdev, chip->devNo, 1);
if(ret)
{
unregister_chrdev_region(chip->devNo, 1);
return ret;
}
cc1101_class = class_create(THIS_MODULE, "cc1101");
device_create(cc1101_class,
NULL,
chip->devNo,
NULL,
"%s",
"cc1101");
//setup cc1101
cc1101_setup(chip);
printk(KERN_DEBUG "cc1101 init success!\n");
return 0;
}
static int __devexit cc1101_remove(struct spi_device *spi) {
struct cc110x_chip *chip = spi_get_drvdata(spi);
if (chip == NULL) {
return -ENODEV;
}
unregister_chrdev_region(chip->devNo, 1);
cdev_del(&chip->cdev);
device_destroy(cc1101_class, chip->devNo);
class_destroy(cc1101_class);
kfree(chip);
spi_set_drvdata(spi, NULL);
return 0;
}
/* Spi driver data */
static struct spi_driver cc1101_spi_driver = {
.driver =
{
.name = "cc1101",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = cc1101_probe,
.remove = __devexit_p(cc1101_remove),
};
static int __init cc1101_init(void) {
return spi_register_driver(&cc11xx_spi_driver);
}
static void __exit cc1101_exit(void) {
spi_unregister_driver(&cc11xx_spi_driver);
}
module_init(cc1101_init);
module_exit(cc1101_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hawk hunter");
MODULE_DESCRIPTION("cc1101 control");