SC16IS752驱动编写与调试记录

参考:

SC16IS752驱动编写与调试记录_青&天-CSDN博客

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");

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值