Chinaunix首页 | 论坛 | 博客
  • 博客访问: 96522
  • 博文数量: 35
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 147
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-05 22:10
个人简介

不经历风雨,怎能见彩虹!

文章分类

全部博文(35)

文章存档

2013年(35)

我的朋友

分类: LINUX

2013-05-21 17:41:21

 

spi设备创建

在tiny6410开发板上外接了spi1的引脚SPICLK、MOSI、SPICS、MISO,所以以spi1为例创建spi设备。

首先介绍2个相关到的结构

1.用于片选的信息

 

struct s3c64xx_spi_csinfo {

       u8fb_delay;                                                        //从机指定的返回延时

       unsignedline;                                                     //指定的CS线对应的管脚

       void(*set_level)(unsigned line_id, int lvl);        //片选线控制函数

};

 

2.用来设置与芯片相关的具体spi参数

 

struct spi_board_info {

       char             modalias[SPI_NAME_SIZE];            //驱动的id

       constvoid   *platform_data;              

       void              *controller_data;                           //一些控制器所需的关于硬件设置的索引

       int          irq;                                            //中断号

 

       u32        max_speed_hz;                       //通讯速率

 

       u16        bus_num;                                 //总线号

       u16        chip_select;                             //片选

 

       u8          mode;                                      工作模式

};

 

注:在6410手册中对四种工作方式的概述。



2个相关的函数

设置SPI相关资源的函数:

void __init s3c64xx_spi_set_info(intcntrlr, int src_clk_nr, int num_cs)

 

在开发办上注册SPI设备的函数:

int __init spi_register_board_info(structspi_board_info const *info, unsigned n)

 

之后就要开工了,注册一个spi设备的具体做法:

打开/arch/arm/mach-s3c64xx/mach-mini64xx.c

1. 初始化相关的结构信息

 

/*创建一个用于片选IO管理的函数,函数的具体结构在s3c64xx_spi_csinfo. set_level上有明确的定义*/

staticvoid  cs_set (unsigned line_id, int lvl){

    gpio_direction_output(line_id, lvl);

};

 

staticstruct s3c64xx_spi_csinfo s3c64xx_spi1_csinfo = {

  .fb_delay = 100,

  .line = S3C64XX_GPC(7),

  .set_level = cs_set,

};

 

staticstruct spi_board_info s3c6410_spi1_board[] = {

  [0] = {

    .modalias = "spi",

    .bus_num = 1,

    .chip_select = 0, 

    .irq = IRQ_SPI1,                             // S3C64XX_IRQ_VIC1(16)

    .max_speed_hz = 500*1000,

.mode = SPI_MODE_0,

/*

     * #define SPI_MODE_0        (0|0)

 * #define SPI_MODE_1       (0|SPI_CPHA)

 * #define SPI_MODE_2       (SPI_CPOL|0)

 * #define SPI_MODE_3       (SPI_CPOL|SPI_CPHA)

 */

    .controller_data =&s3c64xx_spi1_csinfo,

  },

};

 

设备信息初始化完成后,就可以添加具体的注册操作了,基本步骤是和I2C相似的。

首先是在static struct platform_device *mini6410_devices[]上添加spi的platform_device结构,如下:

staticstruct platform_device *mini6410_devices[] __initdata = {

//#ifdefCONFIG_S3C64XX_DEV_SPI

    &s3c64xx_device_spi1,

//#endif   

 

//#ifdefCONFIG_KEYBOARD_GPIO

    &mini6410_device_button,

//#endif   

。。。

}

在machine_init函数中注册设备

staticvoid __init mini6410_machine_init(void)

{

    u32 cs1;

    s3c64xx_spi_set_info(0,0,1);

    。。。

    if(ARRAY_SIZE(s3c6410_spi0_board)) {

        spi_register_board_info(s3c6410_spi0_board,ARRAY_SIZE(s3c6410_spi0_board));

    }

    。。。

}

 

到此在设备的基本注册功能就完成了,下面配置以下menuconfig,打开spi device。

此时编译会提示s3c64xx_spi_set_info未定义,这是因为在arch\arm\mach-s3c64xx的Makefile中编译dev-spi.c的前提是要定义CONFIG_S3C64XX_DEV_SPI,我自己找了一下午都没找到CONFIG_S3C64XX_DEV_SPI这个选项在那里,索性自己在kconfig中添加一个好了。

 

上述工作作完之后重起开发板在/dev下面会看到一个spi的设备,目前spidev支持最多32个设备。设备的名字是spidevX.D,其中X是总线编号,D是设备的片选号。允许多个用户同时打开设备节点,spidev使用mutext进行互斥,多个用户同时读写时只有一个活动的用户,其他用户睡眠。

 

下面简单介绍一下用户空间操作spi的方法:

对于/dev/spidevX.D设备节点,可以进行各种操作,下面介绍它支持的函数接口。

1.  open/close

       打开和关闭设备节点没有特别之处,直接使用open/write就可以了。

2.  read/write

       读写SPI设备可以直接使用read/write函数,但是每次读或者写的大小不能大于4096Byte。

3.  IOCTL命令

      用户空间对spidev设备节点使用IOCTL命令失败会返回-1。

-     SPI_IOC_RD_MODE

读取SPI设备对应的spi_device.mode,使用的方法如下:

ioctl(fd,SPI_IOC_RD_MODE, &mode);

其中第三个参数是一个uint8_t类型的变量。

 

-      SPI_IOC_WR_MODE

设置SPI设备对应的spi_device.mode。使用的方式如下:

ioctl(fd,SPI_IOC_WR_MODE, &mode);

 

-         SPI_IOC_RD_LSB_FIRST

查看设备传输的时候是否先传输低比特位。如果是的话,返回1。使用的方式如下:

ioctl(fd,SPI_IOC_RD_LSB_FIRST, &lsb);

                          其中lsb是一个uint8_t类型的变量。返回的结果存在lsb中。

 

-         SPI_IOC_WR_LSB_FIRST

设置设备传输的时候是否先传输低比特位。当传入非零的时候,低比特在前,当传入0的时候高比特在前(默认)。使用的方式如下:

ioctl(fd,SPI_IOC_WR_LSB_FIRST, &lsb);

 

-         SPI_IOC_RD_BITS_PER_WORD

读取SPI设备的字长。使用的方式如下:

ioctl(fd,SPI_IOC_RD_BITS_PER_WORD, &bits);

其中bits是一个uibt8_t类型的变量。返回的结果保存在bits中。

 

-         SPI_IOC_WR_BITS_PER_WORD

设置SPI通信的字长。使用的方式如下:

ioctl(fd,SPI_IOC_WR_BITS_PER_WORD, &bits);

 

-         SPI_IOC_RD_MAX_SPEED_HZ

读取SPI设备的通信的最大时钟频率。使用的方式如下:

ioctl(fd,SPI_IOC_RD_MAX_SPEED_HZ, &speed);

其中speed是一个uint32_t类型的变量。返回的结果保存在speed中。

-         SPI_IOC_WR_MAX_SPEED_HZ

设置SPI设备的通信的最大时钟频率。使用的方式如下:

ioctl(fd,SPI_IOC_WR_MAX_SPEED_HZ, &speed);

 

-        SPI_IOC_MESSAGE(N)

一次进行双向/多次读写操作。使用的方式如下:

structspi_ioc_transfer  xfer[2];

                          ......

                          status= ioctl(fd,SPI_IOC_MESSAGE(2), xfer);

其中N是本次通信中xfer的数组长度。

 

阅读(1698) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~