S3C2440驱动移植——SPI

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

PC主机:Ubuntu 10.4 和redhat 9.0

目标板:TQ2440开发板,linux内核2.6.30


本文将从原理上讲解如何进行SPI驱动移植。作者希望在移植SPI驱动之前,您已对SPI子系统有所了解。

本文的讲解将基于我所写的spi子系统分析:

基于S3C2440的嵌入式Linux驱动——SPI子系统解读(一)

基于S3C2440的嵌入式Linux驱动——SPI子系统解读(二)

基于S3C2440的嵌入式Linux驱动——SPI子系统解读(三)

基于S3C2440的嵌入式Linux驱动——SPI子系统解读(四)


1. 配置内核


2. 修改源码

修改arch/arm/mach-s3c2440/mach-smdk2440.c

增加内容:

#include <linux/spi/spi.h>

#include <mach/spi.h>

static struct s3c2410_spi_info s3c2410_spi0_platdata={

      .pin_cs = S3C2410_GPG(2),

      .num_cs = 1,

      .bus_num = 0,

};

static struct spi_board_info s3c2410_spi0_board[]={

   [0] = {

             .modalias = “spidev”,

             .bus_num = 0,

             .chip_select = 0,

             .max_speed_hz = 500 * 1000,

    },

};

在smdk2440_devices[]中增加

&s3c_device_spi0,

在smdk2440_mach_init函数中增加

s3c_device_spi0.dev.platform_data = &s3c2410_spi0_platdata;

spi_register_board_info(s3c2410_spi0_board,ARRAY_SIZE(s3c2410_spi0_board));

修改完毕以后,重新编译内核,并下载内核。查看下设备节点:

[root@yj423 /dev]#ls /dev/spidev0.0
/dev/spidev0.0


3.测试

用杜邦线将MOSI和MISO管脚相连。

在内核源码中提供了SPI测试程序。源码位于Documentation/spi/spidev_test.c,编译之后,下到开发板并执行。

[root@yj423 yj423]#./spidev_test -D /dev/spidev0.0
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)

FF FF FF FF FF FF
40 00 00 00 00 95
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
DE AD BE EF BA AD
F0 0D
NOTE:如果你只是为了移植而移植,那么后面的内容就不要看了。想知道WHY,那请继续往下看。


4.原理

首先,在第二小结中我们看到定义了两个数据结构,之所以要定义那是因为驱动程序需要用到,详见

基于S3C2440的嵌入式Linux驱动——SPI子系统解读(二)

需要这两个数据结构的地方,均用红色字体说明了。

数据s3c2410_spi0_platdata是作为平台的私有数据,因此使用了s3c_device_spi0.dev.platform_data = &s3c2410_spi0_platdata来添加该数据。

而s3c2410_spi0_board必须通过函数spi_register_board_info添加到内核中,

最重要的一个问题,这些数据结构的值是怎么给出的?

先来看看这两个数据结构:


  1. struct spi_board_info {  
  2.     /* the device name and module name are coupled, like platform_bus; 
  3.      * "modalias" is normally the driver name. 
  4.      * 
  5.      * platform_data goes to spi_device.dev.platform_data, 
  6.      * controller_data goes to spi_device.controller_data, 
  7.      * irq is copied too 
  8.      */  
  9.     char        modalias[32];  
  10.     const void  *platform_data;  
  11.     void        *controller_data;  
  12.     int     irq;  
  13.   
  14.     /* slower signaling on noisy or low voltage boards */  
  15.     u32     max_speed_hz;  
  16.   
  17.   
  18.     /* bus_num is board specific and matches the bus_num of some 
  19.      * spi_master that will probably be registered later. 
  20.      * 
  21.      * chip_select reflects how this chip is wired to that master; 
  22.      * it's less than num_chipselect. 
  23.      */  
  24.     u16     bus_num;  
  25.     u16     chip_select;  
  26.   
  27.     /* mode becomes spi_device.mode, and is essential for chips 
  28.      * where the default of SPI_CS_HIGH = 0 is wrong. 
  29.      */  
  30.     u8      mode;  
  31.   
  32.     /* ... may need additional spi_device chip config data here. 
  33.      * avoid stuff protocol drivers can set; but include stuff 
  34.      * needed to behave without being bound to a driver: 
  35.      *  - quirks like clock rate mattering when not selected 
  36.      */  
  37. };  
  38.   
  39. struct s3c2410_spi_info {  
  40.     int             pin_cs;    /* simple gpio cs */  
  41.     unsigned int         num_cs;    /* total chipselects */  
  42.     int             bus_num;       /* bus number to use. */  
  43.   
  44.     void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);  
  45.     void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);  
  46. };  
struct spi_board_info {
	/* the device name and module name are coupled, like platform_bus;
	 * "modalias" is normally the driver name.
	 *
	 * platform_data goes to spi_device.dev.platform_data,
	 * controller_data goes to spi_device.controller_data,
	 * irq is copied too
	 */
	char		modalias[32];
	const void	*platform_data;
	void		*controller_data;
	int		irq;

	/* slower signaling on noisy or low voltage boards */
	u32		max_speed_hz;


	/* bus_num is board specific and matches the bus_num of some
	 * spi_master that will probably be registered later.
	 *
	 * chip_select reflects how this chip is wired to that master;
	 * it's less than num_chipselect.
	 */
	u16		bus_num;
	u16		chip_select;

	/* mode becomes spi_device.mode, and is essential for chips
	 * where the default of SPI_CS_HIGH = 0 is wrong.
	 */
	u8		mode;

	/* ... may need additional spi_device chip config data here.
	 * avoid stuff protocol drivers can set; but include stuff
	 * needed to behave without being bound to a driver:
	 *  - quirks like clock rate mattering when not selected
	 */
};

struct s3c2410_spi_info {
    int             pin_cs;    /* simple gpio cs */
    unsigned int         num_cs;    /* total chipselects */
    int             bus_num;       /* bus number to use. */

    void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
    void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
};

4.1 s3c2410_spi_info

pin_cs:表示哪个管脚用输出片选信号,这里使用GPG2管脚,具体的管脚请参看你的datasheet。

bus_num:表示总线接口。这里使用0,表示使用SPI0控制器。S3C2440有两个SPI控制器,分别为SPI0和SPI1。

num_cs:表示该SPI控制器控制几个SPI从设备,这里为1,仅有一个设备。

s3c2410_spi_info作为平台数据,在s3c24xx_spi_probe函数中,bus_cs和bus_num将被复制给master中的相应字段。也就是说,该master为SPI0控制器,有1个从设备。

而pin_cs将由函数s3c24xx_spi_gpiocs使用,该函数使能片选信号。

  1. static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)    
  2. {    
  3.     gpio_set_value(spi->pin_cs, pol);    
  4. }    
static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)  
{  
    gpio_set_value(spi->pin_cs, pol);  
}  

4.2 spi_board_info

首先,我们知道spi_board_info作为SPI设备的板级信息,在spi_new_device函数中将该板级信息全部复制给spi_device。

modalias:将用于绑定驱动和设备。我们看下match方法:

  1. static int spi_match_device(struct device *dev, struct device_driver *drv)    
  2. {    
  3.     const struct spi_device *spi = to_spi_device(dev);    
  4.     
  5.     return strcmp(spi->modalias, drv->name) == 0;    
  6. }    
static int spi_match_device(struct device *dev, struct device_driver *drv)  
{  
    const struct spi_device *spi = to_spi_device(dev);  
  
    return strcmp(spi->modalias, drv->name) == 0;  
}  
而drv->name为在spi_driver中定义,如下

  1. static struct spi_driver spidev_spi = {    
  2.     .driver = {    
  3.         .name =        "spidev",    
  4.         .owner =    THIS_MODULE,    
  5.     },    
  6.     .probe =    spidev_probe,    
  7.     .remove =    __devexit_p(spidev_remove),    
  8.     
  9.     /* NOTE:  suspend/resume methods are not necessary here.  
  10.      * We don't do anything except pass the requests to/from  
  11.      * the underlying controller.  The refrigerator handles  
  12.      * most issues; the controller driver handles the rest.  
  13.      */    
  14. };    
static struct spi_driver spidev_spi = {  
    .driver = {  
        .name =        "spidev",  
        .owner =    THIS_MODULE,  
    },  
    .probe =    spidev_probe,  
    .remove =    __devexit_p(spidev_remove),  
  
    /* NOTE:  suspend/resume methods are not necessary here. 
     * We don't do anything except pass the requests to/from 
     * the underlying controller.  The refrigerator handles 
     * most issues; the controller driver handles the rest. 
     */  
};  
可见,drv->name为spidev,因此spi-device的modalias字段也必须为spidev,而该字段是由板级信息的spi_board_info的modaias复制得来。这就是为什么modalias必须为spidev。

bus_num:用来匹配主控制器和属于该主控制器的SPI设备。

  1. static void scan_boardinfo(struct spi_master *master)    
  2. {    
  3.     struct boardinfo    *bi;    
  4.     
  5.     mutex_lock(&board_lock);    
  6.     /*以board_list为链表头,遍历所有的boardinfo结构,链表由spi_register_board_info添加*/    
  7.     list_for_each_entry(bi, &board_list, list) {        
  8.         struct spi_board_info    *chip = bi->board_info;    
  9.         unsigned        n;    
  10.         /*遍历该boardinfo指向的spi_board_info数组*/    
  11.         for (n = bi->n_board_info; n > 0; n--, chip++) {    
  12.             if (chip->bus_num != master->bus_num) /*通过bus_num对spi设备和master进行匹配*/    
  13.                 continue;    
  14.             /* NOTE: this relies on spi_new_device to  
  15.              * issue diagnostics when given bogus inputs  
  16.              */    
  17.              /*执行到此,表示匹配完成,SPI设备由该SPI接口来控制,开始创建spi_device*/    
  18.             (void) spi_new_device(master, chip);    
  19.         }    
  20.     }    
  21.     mutex_unlock(&board_lock);    
  22. }    
static void scan_boardinfo(struct spi_master *master)  
{  
    struct boardinfo    *bi;  
  
    mutex_lock(&board_lock);  
    /*以board_list为链表头,遍历所有的boardinfo结构,链表由spi_register_board_info添加*/  
    list_for_each_entry(bi, &board_list, list) {      
        struct spi_board_info    *chip = bi->board_info;  
        unsigned        n;  
        /*遍历该boardinfo指向的spi_board_info数组*/  
        for (n = bi->n_board_info; n > 0; n--, chip++) {  
            if (chip->bus_num != master->bus_num) /*通过bus_num对spi设备和master进行匹配*/  
                continue;  
            /* NOTE: this relies on spi_new_device to 
             * issue diagnostics when given bogus inputs 
             */  
             /*执行到此,表示匹配完成,SPI设备由该SPI接口来控制,开始创建spi_device*/  
            (void) spi_new_device(master, chip);  
        }  
    }  
    mutex_unlock(&board_lock);  
}  
可见,master的bus_num和spi_board_info的bus_num必须相同,从上面我们又知道master的bus_num是由s3c2410_spi_info的bus_num复制而来,因此spi_board_info的bus_num的值必须和s3c2410_spi_info的bus_num相等。

chip_selest:该值表示这是该SPI接口上的第几个设备,这里是0,其实就是第一个设备。该值用于区分不同的设备。注意,该值必须小于s3c2410_spi_info的num_cs字段。

max_speed_hz:表示传输速率,这里设置的速度为500kHz。

其余的字段可以不设置。

5. 结束语

   本文给出了SPI驱动移植的步骤,并使用测试程序测试了该SPI驱动。最后,对移植的原理进行了讲解。

深入浅出spi驱动控制器驱动(二) Allein.Cao原创作品,转载请注明出处: http://blog.csdn.net/alleincao/article/details/7523169 内核版本:2.6.32.2 硬件:S3C2440 控制器驱动是与SOC密切相关的一个模块,在linux中,一般都会采用设备驱动控制器驱动分离的思想,两者通过一个core进行关联,这样能够最大程度保证代码的可移植性,具体可 阅读详情

相关推荐

FL2440开发板spi驱动分析(3)

本文分析SPI发送数据的过程,首先构造spi_ioc_transfer结构,再调用ioctl函数发送。  如测试程序中的transfer函数。

nanaoxue的专栏 785

TQ2440 GPIO模拟SPI读取AD转换器TLC2543芯片

其实接触CSDN好久了,一直没有想写自己的博客,遇到问题的时候才去上CSDN参考别人的资料,想到以后不能脚踩西瓜皮,滑倒哪里是哪里,要一个萝卜一个坑,用CSDN博客记录下自己的每一个脚印,一来自己以后可以回过来温故知新,二来很高兴为后来人做一个可参考的基石。毕设了,打算用MDK去开发TQ2440,题目是单片机的液压控制系统,其中,会用到TLC2543芯片的AD转换器,TLC2543是12位精度的S

striker211的专栏 2450

S3C2440 Linux驱动移植——SPI

PC主机:Ubuntu 10.4 目标板:TQ2440开发板,linux内核2.6.32 本文将从原理上讲解如何进行SPI驱动移植。作者希望在移植SPI驱动之前,您已对SPI子系统有所了解。 本文的讲解将基于我所写的spi子系统分析: 基于S3C2440的嵌入式Linux驱动——SPI子系统解读(一) 基于S3C2440的嵌入式Linux驱动——SPI子系统解读(二)

嵌入式Linux 4805

君正X1000平台内核SPI接口使用

君正x1000平台内核SPI接口使用

wojiaxiaohuang2014的博客 1663

展开讲讲配置内核启动spi

要配置内核启动SPI,你需要进行以下步骤: 确认内核已经支持SPI设备,如果没有,需要重新编译内核并在配置选项中打开SPI支持。 确认SPI设备的硬件连接和电气特性都符合规范。 在内核中启用SPI总线和SPI控制器设备的驱动程序,并将其编译进内核中或作为模块加载。 配置SPI控制器设备的参数,例如时钟频率、数据位宽、模式等。 在设备树中描述SPI设备,包括设备类型、片选引脚、时序等信息。...

weixin_42576186的博客 490

S3C2440驱动移植——SPI .

PC主机:Ubuntu 10.4 和redhat 9.0 目标板:TQ2440开发板,linux内核2.6.30 本文将从原理上讲解如何进行SPI驱动移植。作者希望在移植SPI驱动之前,您已对SPI子系统有所了解。 本文的讲解将基于我所写的spi子系统分析: 基于S3C2440的嵌入式Linux驱动——SPI子系统解读(一) 基于S3C2440的嵌入式Linux驱动——S

孔祥锐 922

基于S3C2440的Linux SPI驱动移植笔记

参考: http://blog.csdn.net/woshixingaaa/article/details/6574215 http://blog.163.com/joyrain_06/blog/static/1788253920113823524293/ Linux内核版本:2.6.30.4 测试平台:EmbedSky TQ2440 在2.6.30.4内核源码中,已经给出了S3

天下对手教会少林武僧 381

mini2440 SPI驱动移植 (基于SPI子系统)

参考一: 按照下面帖子的方法,本人试验成功,只需按照下面步骤进行就行了。 原帖地址: http://blog.csdn.net/lxmky/article/details/6858322 注:原文最后短接的MISO和MOSI指的是SPI1的,区别于SPI0 mini2440中,SPI0和SPI1的四个功能引脚均接有上拉电阻10K到3.3V。

win2domain的专栏 868

.基于S3C2440 Linux2.30.4 SPI驱动移植全过程

原文地址:http://blog.163.com/joyrain_06/blog/static/1788253920113823524293/ 一、环境     硬件:s3c2440     内核:Linux2.30.4     交叉编译工具:EABI4.3.3     开发环境:rhel5.5 二、移植   1.修改arch/arm/mach-s3c2440/mach-mini24...

dazhilao 232

SPI在linux3.14.78 FS_S5PC100(Cortex A8)和S3C2440驱动移植(deep dive)

由于工作的原因,对SPI的理解最为深刻,也和SPI最有感情了,之前工作都是基于OSEK操作系统上进行实现,也在US/OS3上实现过SPI驱动的实现和测试,但是都是基于基本的寄存器操作,没有一个系统软件架构的思想,感觉linux SPI驱动很强大,水很深,废话少说,SPI总线上有两类设备:一类是主机端,通常作为SOC系统的一个子模块出现,比如很多嵌入式MPU中都常常包含SPI模块。一类是从机被控端,...

weixin_42005898的博客 289

基于S3C2440核心板控制zlg zm470sx-m lora无线模块

硬件平台:本人自行开发的基于S3C2440核心板的集中采集一体化设备 linux内核版本:2.6.30.4 目的:通添加spi接口来控制zlg zm470sx-m模块 一、spi驱动移植和测试 在2.6.30.4内核源码中,已经给出了S3C2440SPI驱动,因此要在arch/arm/mach-s3c2440/mach-smdk2440.c中加入SPI的支持,由于S3C2440具有...

xiebingsuccess的博客 1180

linux spidev 应用_Linux下SPI驱动移植和应用程序的测试

Linux2.6.32下SPI驱动移植如下图所示:下面需要修改部分内核代码,具体操作如下:1. 修改arch/arm/mach-s3c2440/mach-mini2440.c文件在include头文件代码行之后增加如下代码//spiaddbyshiguang#include#includestaticstructspi_board_infos3c2410_spi0_board...

weixin_42592399的博客 296

SPI在linux3.14.78 FS_S5PC100(Cortex A8)和S3C2440驱动移植(deep dive)_0

由于工作的原因,对SPI的理解最为深刻,也和SPI最有感情了,之前工作都是基于OSEK操作系统上进行实现,也在US/OS3上实现过SPI驱动的实现和测试,但是都是基于基本的寄存器操作,没有一个系统软件架构的思想,感觉linux SPI驱动很强大,水很深,废话少说,SPI总线上有两类设备:一类是主机端,通常作为SOC系统的一个子模块出现,比如很多嵌入式MPU中都常常包含SPI模块。一类是从机被控端,

缠中说禅的博客 364

Linux2.6.32下SPI驱动移植(mini2440)

目录(?)[-] Linux2.6.32下SPI驱动移植如下图所示:下面需要修改部分内核代码,具体操作如下: 修改arch/arm/mach-s3c2440/mach-mini2440.c文件修改drivers/spi/spi_s3c24xx.c文件最后重新编译内核应用程序测试 Linux2.6.32下SPI驱动移植如下图所示:

huquan0610的专栏 761
上一篇: 用rdesktop远程的方法
下一篇: Linux驱动修炼之道
wqc02
博客等级 码龄15年 53粉丝 4原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值