资讯详情

154 spidev:SPI“万能”驱动

文章目录

    • 一、总结
    • 二、两种数据类型
      • 1、spidev_data结构体
      • 2、spi_ioc_transfer结构体
    • 三、设备树节点
      • 1、pinctrl子节点
      • 2、spidev子节点
    • 四、spidev_init()函数
      • spidev_fops文件操作接口
        • (1) spidev_read()函数
          • spidev_sync_read()函数
            • spidev_sync()函数
        • (2) spidev_ioctl()函数
          • spidev_message()函数
          • 应用层对应ioctl()函数
          • SPI_MODE_MASK宏
          • spidev_get_ioc_message()函数
        • (3) spidev_open()函数
    • 五、spidev_probe()函数

一、总结

内核开放的一般版本spi驱动

drivers/spi/spidev.c 是 SPI万能驱动

内核集成spidev驱动模块将在启动后自动加载 支持多种修改spi通信参数

二、两种数据类型

1、spidev_data结构体

fops使用中间的函数结构,将被赋值file->private_data

struct  spidev_data  {       // 设备号  dev_t      devt;  spinlock_t    spi_lock;  struct  spi_device  *spi;  struct  list_head  device_entry;  struct  mutex    buf_lock;  unsigned    users;  // 发送buf,接收buf,通信频率  u8			*tx_buffer;  u8			*rx_buffer;  u32			speed_hz;};

2、spi_ioc_transfer结构体

include/uapi/linux/spi/spidev.h 可用于设置spi这种结构也用于用户空间编程

struct  spi_ioc_transfer  {       // spi缓存区发送数据  __u64		tx_buf;  // spi缓存区的数据接收  __u64		rx_buf;  // 收发数据长度  __u32		len;  __u32		speed_hz;  __u16		delay_usecs;  __u8		bits_per_word;  __u8		cs_change;  __u8		tx_nbits;  __u8		rx_nbits;  __u16		pad;};

三、设备树节点

1、pinctrl子节点

  pinctrl_ecspi3:ecspi3grp {               // 此属性记录引脚组          fsl,pins =  <            MX6UL_PAD_UART2_TX_DATA__ECSPI3_SS0     0x1a090            MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK		0x11090            MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI			0x11090            MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO			0x11090          >;	};

2、spidev子节点

&ecspi3{
     	pinctrl-names = "default";	// default表示使用pinctrl-0引脚组	pinctrl-0 = <&pinctrl_ecspi3>;	status = "okay";	#address-cells = <1>;	#size-cells = <0>; 	// 追加一个设备节点	// 此节点挂载在spi节点下,会被内核解析成一个spi_device设备,挂在对应的spi总线上	spidev@0 {
     		// 用来匹配对应的驱动,pdidev.c		compatible = "spidev";		spi-max-frequency = <20000000>;		reg = <0>;	};};

四、spidev_init()函数

spidev.c

static int __init spidev_init(void){
     	int status;	...	// 申请设备号,参数1主设备号为153	// 这一步将主设备号153机器所有的次设备号都占用了	status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);	...	// 创建spidev设备类,新增/sys/class/spidev	spidev_class = class_create(THIS_MODULE, "spidev");	...	// 向内核注册一个spi设备驱动	status = spi_register_driver(&spidev_spi_driver);	...	return status;}

spidev_fops文件操作接口

static const struct file_operations spidev_fops = {
     	.owner =	THIS_MODULE,	.write =	spidev_write,	.read =		spidev_read,	// 应用层 ioctl()函数底层操作接口(32位系统)	.unlocked_ioctl = spidev_ioctl,	// 应用层 ioctl()函数底层操作接口(64位系统)	.compat_ioctl = spidev_compat_ioctl,	.open =		spidev_open,	.release =	spidev_release,	.llseek =	no_llseek,};

注意read和write接口只能半双工收发消息, spi支持全双工,可使用unlocked_ioctl接口可以支持半双工,全双工(switch中的default分支)收发消息。

(1) spidev_read()函数

static ssize_tspidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){
     	struct spidev_data	*spidev;	ssize_t			status = 0;	/* chipselect only toggles at start or end of operation */	// 先判断用户空间想要读取的字节数	if (count > bufsiz)		return -EMSGSIZE;	// 通过文件指针获取struct spidev_data,在fops->open中完成赋值	spidev = filp->private_data;	mutex_lock(&spidev->buf_lock);	// 详见下	status = spidev_sync_read(spidev, count);	if (status > 0) {
     		unsigned long	missing;		missing = copy_to_user(buf, spidev->rx_buffer, status);		if (missing == status)			status = -EFAULT;		else			status = status - missing;	}	mutex_unlock(&spidev->buf_lock);	return status;}
spidev_sync_read()函数
spidev_sync_read(struct spidev_data *spidev, size_t len){
     	// 此类型是传输spi消息的最基本的单元	struct spi_transfer	t = {
     			// 此buffer在fops->rx_buf中分配,

标签: uhz液位变送器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

 锐单商城 - 一站式电子元器件采购平台  

 深圳锐单电子有限公司