参考:
1路spi接口转2路uart; 该驱动已经在xilinx zynq7100产品上使用.
/***********************************************************************************************/ /**
*\n @file spi_sc16is752_drv.c
*\n @brief sc16is752 drivers
*\n @details
*\n -----------------------------------------------------------------------------------
*\n 文件说明:
*\n 1. sc16is752 drivers
*\n 2. ref_clock = 14.7456MHz
*\n 3. bandrate = ref_clock / (16 * (DLH,DLL))
*\n 4. A Channal is RS485,
*\n B Channal is RS232
*\n
*\n devicetree:
*\n &spi1 {
*\n // num-cs = <1>;
*\n status = "okay";
*\n sc16is752@0 {
*\n compatible = "sc16is752";
*\n reg = <0>;
*\n status = "okay";
*\n spi-max-frequency = <1000000>;
*\n // gpios = <&gpio0 39 GPIO_ACTIVE_LOW>;
*\n gpios = <&gpio0 39 1>;
*\n interrupt-parent = <&gpio0>;
*\n // interrupts = <0 12 IRQ_TYPE_EDGE_FALLING>;
*\n interrupts = <0 12 3>;
*\n };
*\n
*\n
*\n
*\n -----------------------------------------------------------------------------------
*\n 版本: 修改人: 修改日期: 描述:
*\n V0.01 luo_xian_neng 2021.4.29 创建
*\n
***************************************************************************************************/
/**************************************************************************************************
* 头文件
***************************************************************************************************/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/utsname.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h>
/**************************************************************************************************
* 宏定义、结构定义
***************************************************************************************************/
#define RHR 0x00 //R
#define THR 0x00 //W
#define IER 0x01
#define FCR 0x02 //W
#define IIR 0x02 //R
#define LCR 0x03
#define MCR 0x04
#define LSR 0x05
#define MSR_1 0x06 //本来是直接定义为MSR的,但是这样定义与汇编指令MSR有冲突
#define SPR 0x07
#define TCR 0x06 //These registers are accessible only when EFR[4] = 1, and MCR[2] = 1
#define TLR 0x07
#define TXLVL 0x08
#define RXLVL 0x09
#define IODIR_752 0x0a
#define IOSTATE 0x0b
#define IOINTENA 0x0c
#define RESERVED 0x0d
#define IOCONTROL 0x0e
#define EFCR 0x0f
//special register The Special Register set is accessible only when LCR[7] = 1 and not 0xBF
#define DLL 0x00
#define DLH 0x01
//enhanced register Enhanced Features Registers are only accessible when LCR = 0xBF
#define EFR 0x02
#define XON1 0x04
#define XON2 0x05
#define XOFF1 0x06
#define XOFF2 0x07
//定义端口
#define channelA 0x0
#define channelB 0x1
//定义spi uart操作幻数
// ioctl(cmd) 参数
#define GET_STATUS _IOW('k', 0, int) /* 读取channel0/1 中断状态值 bit[0~15]: channel0, bit[16~31]: channel1 */
#define GET_TXFIFO _IOW('k', 1, int) /* txFifo空字节: tx0Fifo: bit0~15, tx1Fifo: bit16~31 */
#define SET_STOP_BIT _IOW('k', 2, int) /* 设置停止位1==1bit, 2=-1.5bit or 2bit */
#define SET_BPS _IOW('k', 3, int) /* 设置波特率 */
#define SET_PARITY _IOW('k', 4, int) /* 设置奇偶校验 0==none, 1=odd, 2=even */
#define SET_DATABIT _IOW('k', 5, int) /* 数据位 5,6,7,8bit */
#define DEVICE_NAME "spi2uart"
#define SPI_CLK_HZ 10000000 /* SPI 时钟频率 */
/**************************************************************************************************
* 全局变量声明、定义
***************************************************************************************************/
/**************************************************************************************************
* 私有变量声明、定义
***************************************************************************************************/
struct sc16is752_dev
{
struct spi_device *spi;
spinlock_t spi_lock;
struct mutex lock;
unsigned int channel_num;
int irq;
struct work_struct *sc752_irq_work;
wait_queue_head_t sc16is752_q;
unsigned int condition;
void* proc_fd;
unsigned char rx_buf[1024*2];
unsigned char tx_buf[1024*2];
};
static struct sc16is752_dev *sc16is752 = NULL;
/**************************************************************************************************
* 私有函数声明、定义
***************************************************************************************************/
// read寄存器, channel =0,1
static char read_reg(unsigned int reg, unsigned int channel)
{
#if 0
struct spi_transfer t[2];
struct spi_message m;
char val = 0;
unsigned char cmd = 0x80 | (reg << 3) | (channel << 1);
spi_message_init(&m);
memset(t, 0, (sizeof t));
t[0].tx_buf = &cmd;
t[0].len = 1;
t[0].speed_hz = SPI_CLK_HZ,
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = &val;
t[1].len = 1;
t[1].speed_hz = SPI_CLK_HZ,
spi_message_add_tail(&t[1], &m);
// spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &m);
// spin_unlock_irq(&sc16is752->spi_lock);
return val;
#endif
#if 1
char tx_buf[2];
char rx_buf[2];
struct spi_transfer t = {
.tx_buf = tx_buf,
.rx_buf = rx_buf,
.len = 2,
.speed_hz = SPI_CLK_HZ,
};
struct spi_message message;
tx_buf[0] = 0x80 | ((reg & 0x0f) << 3) | ((channel & 0x03) << 1);
tx_buf[1] = 0;
rx_buf[0] = rx_buf[1] = 0;
spi_message_init(&message);
spi_message_add_tail(&t, &message);
// spin_lock_irq(&sc16is752->spi_lock);
int status = spi_sync(sc16is752->spi, &message);
// spin_unlock_irq(&sc16is752->spi_lock);
return rx_buf[1];
#endif
}
static void write_reg(unsigned int reg, unsigned int channel, unsigned char data)
{
char tx_buf[2];
struct spi_transfer t = {
.tx_buf = tx_buf,
.len = 2,
.speed_hz = SPI_CLK_HZ,
};
struct spi_message message;
tx_buf[0] = 0x00 | ((reg & 0x0f) << 3) | ((channel & 0x3) << 1);
tx_buf[1] = data;
spi_message_init(&message);
spi_message_add_tail(&t, &message);
// spin_lock_irq(&sc16is752->spi_lock);
int status = spi_sync(sc16is752->spi, &message);
// spin_unlock_irq(&sc16is752->spi_lock);
return;
}
// 读取RX fifo中的多个数据
static ssize_t read_fifo(int len, unsigned int channel)
{
#if 0
unsigned int length = 0;
unsigned char status = 0;
do{
status = read_reg(LSR, channel);
if(status & 0x01)
{
sc16is752->buf[length] = read_reg(RHR, channel);
length ++;
}
}while(status & 0x01);
return length;
#endif
#if 1
unsigned char status;
unsigned int length = 0;
char tx_buf[72];
char rx_buf[72];
struct spi_transfer t = {
.tx_buf = tx_buf,
.rx_buf = rx_buf,
//.len = size+1,
.speed_hz = SPI_CLK_HZ,
};
struct spi_message message;
while(1)
{
int size = read_reg(RXLVL, channel);
if (size == 0)
{
break;
}
memset(rx_buf, 0, sizeof(tx_buf));
memset(tx_buf, 0, sizeof(tx_buf));
tx_buf[0] = 0x80 | ((RHR & 0x0f) << 3) | ((channel & 0x03) << 1);
t.len = size+1;
spi_message_init(&message);
spi_message_add_tail(&t, &message);
// spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &message);
// spin_unlock_irq(&sc16is752->spi_lock);
if (size < len-length)
{
memcpy(&sc16is752->rx_buf[length], rx_buf+1, size);
length += size;
}
}
return length;
#endif
}
static int write_fifo(unsigned char *buf, int len, unsigned int channel)
{
#if 0
unsigned char status;
int size = len < 64 ? len : 64; // TX Fifo max == 64;
char tx_buf[72];
struct spi_transfer t = {
.tx_buf = tx_buf,
.len = size+1,
.speed_hz = SPI_CLK_HZ,
};
struct spi_message message;
status = read_reg(LSR, channel);
if (status & 0x20) // TX FIFO is empty ?
{
tx_buf[0] = 0x00 | (THR << 3) | ((uint8_t)channel << 1);
memcpy(&tx_buf[1], buf, size);
t.len = size+1,
spi_message_init(&message);
spi_message_add_tail(&t, &message);
// spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &message);
// spin_unlock_irq(&sc16is752->spi_lock);
}
else
size = 0;
return size;
#endif
#if 1
char tx_buf[72];
struct spi_transfer t = {
.tx_buf = tx_buf,
// .len = size+1,
.speed_hz = SPI_CLK_HZ,
};
struct spi_message message;
int empty_size = read_reg(TXLVL, channel); // empty fifo size
// printk(KERN_INFO "txfifo size=%d\n", empty_size);
int size = (empty_size < len) ? empty_size : len;
if (size > 0)
{
tx_buf[0] = 0x00 | (THR << 3) | ((uint8_t)channel << 1);
memcpy(&tx_buf[1], buf, size);
t.len = size+1;
spi_message_init(&message);
spi_message_add_tail(&t, &message);
// spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &message);
// spin_unlock_irq(&sc16is752->spi_lock);
}
return size;
#endif
}
static int init_regs(unsigned int channel, unsigned long bandrate)
{
// 计算波特率: DLH,DLL = 14.7456MHz / 16 / 115200 bps
unsigned long dl = 14745600 / 16 / bandrate;
/*initlizate channel A*/
write_reg(LCR, channel, 0x80); // bandrate = 9600 bps:
write_reg(DLL, channel, (char)dl);
write_reg(DLH, channel, (char)((unsigned long)dl >> 8));
write_reg(LCR, channel, 0xbf);
write_reg(EFR, channel, 0x10);
write_reg(LCR, channel, 0x03); // 8 bit
write_reg(IER, channel, 0x01);
write_reg(FCR, channel, 0xf1); // enable FIFO,RX trigger=60bytes, TX trigger=56bytes
//write_reg(FCR, channel, 0x51);
write_reg(SPR, channel, 0x41);
write_reg(IODIR_752, channel, 0xff);
write_reg(IOSTATE, channel, 0x00);
#if 0
/*initlizate channel B*/
write_reg(LCR, channelB, 0x80); // 设置波特率 bandrate = 9600 bps:
write_reg(DLL, channelB, 0x08); // DLH,DLL = 14.7456MHz / 16 / 115200 bps = 8
write_reg(DLH, channelB, 0x00);
write_reg(LCR, channelB, 0xbf); // 设置
write_reg(EFR, channelB, 0x10);
write_reg(LCR, channelB, 0x03);
write_reg(IER, channelB, 0x01);
write_reg(FCR, channelB, 0xf1);
//write_reg(FCR, channelB, 0x51);
write_reg(SPR, channelB, 0x41);
write_reg(IODIR_752, channelB, 0xff);
write_reg(IOSTATE, channelB, 0x00);
#endif
return 0;
}
#if 1 // ----------------------------------------------------
static int sc16is752a_open(struct inode *inode, struct file *filp)
{
filp->private_data = sc16is752;
// sc16is752->buf = kmalloc(64, GFP_KERNEL);
// if (!sc16is752->buf)
// {
// printk(KERN_INFO "kzallo buf error\n");
// return -ENOMEM;
// }
nonseekable_open(inode, filp); //设置为不可随机读取。
// printk(KERN_INFO "open and initlizate channel A/B succeed\n ");
return 0;
}
static int sc16is752a_release(struct inode *inode, struct file *filp)
{
// if (NULL != sc16is752->buf)
// kfree(sc16is752->buf);
return 0;
}
static long sc16is752a_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
unsigned int channel_num = 0; // 通道
int retval = -EFAULT;
unsigned char tmp = 0;
struct sc16is752_dev *sc16is752 = filp->private_data;
mutex_lock(&sc16is752->lock);
switch (cmd)
{
case GET_STATUS:
{
__u32 status = 0;
status = ((__u32)read_reg(IIR, 0) & 0xff); // bit[0 ~15] == channel0 status;
status += ((__u32)read_reg(IIR, 1) & 0xff) << 16; // bit[16~31] == channel1 status;
retval = __put_user(status, (__u32 __user *)args);
retval = 0;
break;
}
case GET_TXFIFO:
{
__u32 status = 0;
status = ((__u32)read_reg(TXLVL, 0) & 0xff); // bit[0 ~15] == channel0 status;
status += ((__u32)read_reg(TXLVL, 1) & 0xff) << 16; // bit[16~31] == channel1 status;
retval = __put_user(status, (__u32 __user *)args);
retval = 0;
break;
}
case SET_STOP_BIT:
{
// retval = __get_user(tmp, (u32 __user *)args);
tmp = read_reg(LCR, channel_num);
if (1 == args)
{
tmp &= (~(0x01 << 2)); //设置1位停止位
write_reg(LCR, channel_num, tmp);
}
else if (2 == args)
{
tmp |= (0x01 << 2); //设置1.5/2位停止位
write_reg(LCR, channel_num, tmp);
}
retval = 0;
break;
}
case SET_BPS:
{
//printk(KERN_INFO "set bandrate %d bps\n ", (int)args);
//禁止睡眠模式才可以设置波特率。
tmp = read_reg(IER, channel_num);
tmp &= (~(0x01 << 4));
write_reg(IER, channel_num, tmp);
if(args > 0)
{
init_regs(channel_num, args);
retval = 0;
}
break;
}
case SET_DATABIT:
{
/* 数据位 5,6,7,8bit */
// LCR[1] LCR[0] Word length (bits)
// 0 0 5
// 0 1 6
// 1 0 7
// 1 1 8
tmp = read_reg(LCR, channel_num);
switch(args)
{
default:
break;
case 8:
tmp &= ~(0x3);
tmp |= (0x3);
break;
case 7:
tmp &= ~(0x3);
tmp |= (0x2);
break;
case 6:
tmp &= ~(0x3);
tmp |= (0x1);
break;
case 5:
tmp &= ~(0x3);
break;
}
write_reg(LCR, channel_num, tmp);
retval = 0;
break;
}
case SET_PARITY:
{
/* 设置奇偶校验 0==none, 1=odd, 2=even */
// LCR[5] LCR[4] LCR[3] Parity selection
// X X 0 no parity
// 0 0 1 odd parity
// 0 1 1 even parity
// 1 0 1 forced parity ‘1’
// 1 1 1 forced parity ‘0
tmp = read_reg(LCR, channel_num);
switch(args)
{
default:
case 0:
tmp &= ~(0x7 << 3);
break;
case 1:
tmp &= ~(0x7 << 3);
tmp |= (0x1 << 3);
break;
case 2:
tmp &= ~(0x7 << 3);
tmp |= (0x3 << 3);
break;
}
write_reg(LCR, channel_num, tmp);
retval = 0;
break;
}
default:
break;
}
mutex_unlock(&sc16is752->lock);
return retval;
}
static ssize_t sc16is752a_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
struct sc16is752_dev *sc16is752 = filp->private_data;
int length = 0;
int missing;
//wait_event(sc16is752->sc16is752_q,sc16is752->condition);//用此函数会导致进程杀不死。
//wait_event_interruptible(sc16is752->sc16is752_q, sc16is752->condition);
mutex_lock(&sc16is752->lock);
length = read_fifo(size, 0);
length = length < size ? length : size;
missing = copy_to_user(buf, sc16is752->rx_buf, length);
if (missing == length)
length = -EFAULT;
else
length = length - missing;
mutex_unlock(&sc16is752->lock);
sc16is752->condition = 0;
return length;
}
static ssize_t sc16is752a_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
int missing;
struct sc16is752_dev *self = filp->private_data;
if (size > 64)
return -EMSGSIZE;
mutex_lock(&self->lock);
missing = copy_from_user(self->tx_buf, buf, size);
ssize_t ret = write_fifo(self->tx_buf, size, 0);
mutex_unlock(&self->lock);
return ret;
}
struct file_operations sc16is752a_fops =
{
.owner = THIS_MODULE,
.open = sc16is752a_open,
.write = sc16is752a_write,
.read = sc16is752a_read,
.unlocked_ioctl = sc16is752a_ioctl,
.release = sc16is752a_release,
};
struct miscdevice sc16is752a_misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME "0",
.fops = &sc16is752a_fops,
};
#endif // ------------------------------------------
#if 1 // ----------------------------------------------------
static int sc16is752b_open(struct inode *inode, struct file *filp)
{
filp->private_data = sc16is752;
// sc16is752->buf = kmalloc(64, GFP_KERNEL);
// if (!sc16is752->buf)
// {
// printk(KERN_INFO "kzallo buf error\n");
// return -ENOMEM;
// }
nonseekable_open(inode, filp); //设置为不可随机读取。
// printk(KERN_INFO "open and initlizate channel A/B succeed\n ");
return 0;
}
static int sc16is752b_release(struct inode *inode, struct file *filp)
{
// if (NULL != sc16is752->buf)
// kfree(sc16is752->buf);
return 0;
}
static long sc16is752b_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
unsigned int channel_num = 1; // 通道
int retval = -EFAULT;
unsigned char tmp = 0;
struct sc16is752_dev *sc16is752 = filp->private_data;
mutex_lock(&sc16is752->lock);
switch (cmd)
{
case GET_STATUS: // 读取中断状态(并清除中断)
{
__u32 status = 0;
status = ((__u32)read_reg(IIR, 0) & 0xff); // byte[0] == channel0 rx Fifo data length;
status += ((__u32)read_reg(IIR, 1) & 0xff) << 16; // byte[1] == channel1 RX fifo data length;
retval = __put_user(status, (__u32 __user *)args);
break;
}
case GET_TXFIFO:
{
__u32 status = 0;
status = ((__u32)read_reg(TXLVL, 0) & 0xff); // bit[0 ~15] == channel0 status;
status += ((__u32)read_reg(TXLVL, 1) & 0xff) << 16; // bit[16~31] == channel1 status;
retval = __put_user(status, (__u32 __user *)args);
retval = 0;
break;
}
case SET_STOP_BIT:
{
// retval = __get_user(tmp, (u32 __user *)args);
tmp = read_reg(LCR, channel_num);
if (1 == args)
{
tmp &= (~(0x01 << 2)); //设置1位停止位
write_reg(LCR, channel_num, tmp);
}
else if (2 == args)
{
tmp |= (0x01 << 2); //设置1.5/2位停止位
write_reg(LCR, channel_num, tmp);
}
retval = 0;
break;
}
case SET_BPS:
{
//printk(KERN_INFO "set bandrate %d bps\n ", (int)args);
//禁止睡眠模式才可以设置波特率。
tmp = read_reg(IER, channel_num);
tmp &= (~(0x01 << 4));
write_reg(IER, channel_num, tmp);
if(args > 0)
{
init_regs(channel_num, args);
retval = 0;
}
break;
}
case SET_DATABIT:
{
/* 数据位 5,6,7,8bit */
// LCR[1] LCR[0] Word length (bits)
// 0 0 5
// 0 1 6
// 1 0 7
// 1 1 8
tmp = read_reg(LCR, channel_num);
switch(args)
{
default:
break;
case 8:
tmp &= ~(0x3);
tmp |= (0x3);
break;
case 7:
tmp &= ~(0x3);
tmp |= (0x2);
break;
case 6:
tmp &= ~(0x3);
tmp |= (0x1);
break;
case 5:
tmp &= ~(0x3);
break;
}
write_reg(LCR, channel_num, tmp);
retval = 0;
break;
}
case SET_PARITY:
{
/* 设置奇偶校验 0==none, 1=odd, 2=even */
// LCR[5] LCR[4] LCR[3] Parity selection
// X X 0 no parity
// 0 0 1 odd parity
// 0 1 1 even parity
// 1 0 1 forced parity ‘1’
// 1 1 1 forced parity ‘0
tmp = read_reg(LCR, channel_num);
switch(args)
{
default:
case 0:
tmp &= ~(0x7 << 3);
break;
case 1:
tmp &= ~(0x7 << 3);
tmp |= (0x1 << 3);
break;
case 2:
tmp &= ~(0x7 << 3);
tmp |= (0x3 << 3);
break;
}
write_reg(LCR, channel_num, tmp);
retval = 0;
break;
}
default:
break;
}
mutex_unlock(&sc16is752->lock);
return retval;
}
static ssize_t sc16is752b_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
struct sc16is752_dev *sc16is752 = filp->private_data;
int length = 0;
int missing;
//wait_event(sc16is752->sc16is752_q,sc16is752->condition);//用此函数会导致进程杀不死。
//wait_event_interruptible(sc16is752->sc16is752_q, sc16is752->condition);
mutex_lock(&sc16is752->lock);
length = read_fifo(size, 1);
missing = copy_to_user(buf, sc16is752->rx_buf, length);
if (missing == length)
length = -EFAULT;
else
length = length - missing;
mutex_unlock(&sc16is752->lock);
sc16is752->condition = 0;
return length;
}
static ssize_t sc16is752b_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
int missing;
struct sc16is752_dev *self = filp->private_data;
if (size > 64)
return -EMSGSIZE;
mutex_lock(&self->lock);
missing = copy_from_user(self->tx_buf, buf, size);
ssize_t ret = write_fifo(self->tx_buf, size, 1);
mutex_unlock(&self->lock);
return ret;
}
struct file_operations sc16is752b_fops =
{
.owner = THIS_MODULE,
.open = sc16is752b_open,
.write = sc16is752b_write,
.read = sc16is752b_read,
.unlocked_ioctl = sc16is752b_ioctl,
.release = sc16is752b_release,
};
struct miscdevice sc16is752b_misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME "1", //
.fops = &sc16is752b_fops,
};
#endif // ------------------------------------------
void sc752_work_func(struct work_struct *work)
{
unsigned char tmp = 0;
tmp = read_reg(IIR, sc16is752->channel_num);
printk(KERN_INFO "enter sc752_work_func\n");
if (tmp & 0x04)
{
sc16is752->condition = 1;
wake_up(&sc16is752->sc16is752_q);
}
}
// 中断函数
irqreturn_t sc16is752_handler(int irq, void *dev_id)
{
schedule_work(sc16is752->sc752_irq_work);
printk(KERN_INFO "sc16is752_handler\n");
return IRQ_HANDLED;
}
#if 1
/*
* create /proc/<DEVICE_NAME>, show version information of drivers
* 在/proc/目录建立只读文件<DEVICE_NAME>,存放版本信息
*/
#define DRIVER_VERSION "v0.4"
static int proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%s,build(%s,%s)\n", DRIVER_VERSION, __DATE__, __TIME__);
return 0;
}
static int proc_file_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_show, NULL);
}
static const struct file_operations proc_fops = {
.open = proc_file_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int proc_init(void)
{
sc16is752->proc_fd = proc_create(DEVICE_NAME, 0444, NULL, &proc_fops);
return 0;
}
static int proc_uninit(void)
{
proc_remove(sc16is752->proc_fd);
return 0;
}
#endif
static int sc16is752_probe(struct spi_device *spi)
{
int ret = 0;
printk(KERN_INFO "Spi device sc16is752 is probed!\n");
sc16is752 = kzalloc(sizeof(*sc16is752), GFP_KERNEL);
if (!sc16is752)
return -ENOMEM;
sc16is752->channel_num = channelA; //默认使用channelA
sc16is752->spi = spi;
sc16is752->irq = spi->irq; //中断
// sc16is752->buf = NULL;
spin_lock_init(&sc16is752->spi_lock);
mutex_init(&sc16is752->lock);
// printk(KERN_INFO "sc16is752->irq = %d\n", sc16is752->irq);
// ret = request_threaded_irq(sc16is752->irq, NULL, sc16is752_handler,
// IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "sc16is752", NULL);
// if (ret < 0)
// {
// printk(KERN_INFO "Failed to request IRQ!\n");
// }
sc16is752->sc752_irq_work = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
INIT_WORK(sc16is752->sc752_irq_work, sc752_work_func);
init_waitqueue_head(&sc16is752->sc16is752_q);
sc16is752->condition = 0; //初始化等待条件为0
ret = misc_register(&sc16is752a_misc);
ret += misc_register(&sc16is752b_misc);
if (ret != 0)
{
printk(KERN_INFO "cannot register miscdev err = %d\n", ret);
}
spi_set_drvdata(spi, sc16is752);
proc_init();
init_regs(channelA, 9600);
init_regs(channelB, 9600);
return 0;
}
static int sc16is752_remove(struct spi_device *spi)
{
misc_deregister(&sc16is752a_misc);
misc_deregister(&sc16is752b_misc);
if (sc16is752->sc752_irq_work)
{
kfree(sc16is752->sc752_irq_work);
sc16is752->sc752_irq_work = NULL;
}
free_irq(sc16is752->irq, NULL);
kfree(sc16is752);
proc_uninit();
return 0;
}
static const struct of_device_id sc16is752_dt_ids[] =
{
{.compatible = DEVICE_NAME },
{},
};
MODULE_DEVICE_TABLE(of, sc16is752_dt_ids);
static struct spi_driver sc16is752_driver =
{
.driver = {
.owner = THIS_MODULE,
.name = "sc16is752",
.of_match_table = of_match_ptr(sc16is752_dt_ids),
},
.probe = sc16is752_probe,
.remove = sc16is752_remove,
};
static int __init sc16is752_init(void)
{
return spi_register_driver(&sc16is752_driver);
}
static void __exit sc16is752_exit(void)
{
spi_unregister_driver(&sc16is752_driver);
}
module_init(sc16is752_init);
module_exit(sc16is752_exit);
MODULE_DESCRIPTION("Driver for SPI SC16IS752");
MODULE_AUTHOR("SC16IS752");
MODULE_LICENSE("GPL");