• spi驱动框架全面分析,从master驱动到设备驱动


    内核版本:linux2.6.32.2 
    硬件资源:s3c2440
    参考:  韦东山SPI视频教程


    内容概括:
        1、I2C 驱动框架回顾
        2、SPI 框架简单介绍
        3、master 驱动框架

            3.1 驱动侧
            3.2 设备侧

        4、SPI 设备驱动框架

            4.1 设备册
            4.2 驱动侧

        5、设备驱动程序实例

    1、I2C 驱动框架回顾
        在前面学习 I2C 驱动程序的时候我们知道,I2C 驱动框架分为两层,一层是控制器驱动程序 i2c_adapter,它一般是由芯片厂商写好的,主要提供一个 algorithm 底层的 i2c 协议的收发函数。i2c_adapter 驱动是基于 platform 模型,在driver侧的probe函数里,取出资源信息进行设置,最后将adapter注册到i2c_bus_type,注册时会调用 i2c_scan_static_board_info,扫描并使用 i2c_new_device 创建设备(设备层的设备)。我们还提到了4种创建device的方式。

        另一层是设备驱动层,基于 i2c_bus_type ,这个就很简单了,在设备驱动层 device 只需要提供一个从设备地址和名字,在 driver 里使用 i2c_smbus_read_byte_data 等类似的函数进行收发即可了,i2c_smbus_read_byte_data 等函数最终就会调用到 我们的 i2c_adapter->algorithm 里的收发函数进行收发。

    2、SPI 框架简单介绍
        对于SPI的大框架,与I2C是完全一致的,也分为两层,控制器驱动程序层叫 spi_master ,主要提供transfer函数,进行spi协议的收发。spi_master 也是基于 Platform 模型的,注册 spi_master 时也会扫描一个链表进行注册设备,简直太相似了。

        另一层是设备驱动层,基于 spi_bus_type,相比 i2c 在device中需要提供的信息多一些,需要有名字、片选、最大速率、模式、中断号等等,在driver里则使用spi_read、spi_writer 等函数,最终也会调用到 master->transfer 函数进行发送接收。

        相比 I2C ,SPI驱动的框架是要简单的,因为它少了两种注册device的方式,另外它不需要像I2C一样去发送Start信号和设备地址去探测设备,SPI只需要片选选中就行了。但是它的底层收发的控制,相对I2C要复杂一点,毕竟4根线。

    3、master 驱动框架
        之前,分析的驱动程序都是 S3C2410S3C2440 平台的,由于我的开发板 Mini2440 没有SPI设备,因此厂商带的内核里关于 SPI 驱动部分不完整,而且在s3c23xx_spi_probe函数里注册master的时候写的十分复杂,干扰信息太多,不适合分析学习,因此,我搜索了一下其他平台的代码,发现 atmel_spi.c (driversspi),里 atmel 实现的底层控制器驱动简单清晰多了,因此就拿它开刀,分析Master驱动框架。

      3.1 驱动侧

        前面简介里,我提到 master 驱动框架是基于 platform 平台的(我分析的这俩都是,其它的不清楚),那么肯定就要注册platform_driver了,下面我们就开看看。

    分配一个platfrom_driver结构

    [cpp] view plain copy
    1. static struct platform_driver atmel_spi_driver = {  
    2.     .driver     = {  
    3.         .name   = "atmel_spi",  
    4.         .owner  = THIS_MODULE,  
    5.     },  
    6.     .suspend    = atmel_spi_suspend,  
    7.     .resume     = atmel_spi_resume,  
    8.     .remove     = __exit_p(atmel_spi_remove),  
    9. };  

        将 atmel_spi_driver 注册到 platform_bus_type ,匹配设备 probe

    [cpp] view plain copy
    1. static int __init atmel_spi_init(void)  
    2. {  
    3.     return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe);  
    4. }     

        我们之前都是将 probe 函数,直接放在driver结构体里,这里不是,而是调用了 platform_driver_probe ,就不贴代码了,还看段函数介绍,大致了解下什么意思。
    /**
     * platform_driver_probe - register driver for non-hotpluggable device
     * @drv: platform driver structure
     * @probe: the driver probe routine, probably from an __init section
     *
     * Use this instead of platform_driver_register() when you know the device
     * is not hotpluggable and has already been registered, and you want to
     * remove its run-once probe() infrastructure from memory after the driver
     * has bound to the device.
     *
     * One typical use for this would be with drivers for controllers integrated
     * into system-on-chip processors, where the controller devices have been
     * configured as part of board setup.
     *
     * Returns zero if the driver registered and bound to a device, else returns
     * a negative error code and with the driver not registered.
     */
        1、适用于非热插拔设备
        2、通常Probe位于__init段3、当你知道device是非热拔插的,而且设备已经被注册了,而且你想在probe函数调用一次之后就销毁它节省空间,使用 platform_driver_probe 而非 platform_driver_register。
        4、一个典型的应用是,用在完整的控制器驱动,控制器设备被当作 board setup 的一部分(在板子初始化的时候,设备就已经被注册了,放在board_info里)
        5、返回0 ,如果driver注册成功且匹配到一个device ,以后再也无法被别的device probe了。
        6、否则,返回一个错误,且driver未注册。
        显然,我们写的正式一个控制器驱动程序,设备侧确实是早已注册(后边会讲)。
        疑问:有人说使用 platform_driver_probe 时 driver 只能被一个 device 匹配绑定,之后再也无法被别的device probe,难道说,我有俩spi控制器还需要写两个控制器驱动程序么?我认为这种说法是不对的,我猜大概是driver注册时,会匹配一遍device链表,把能支持的device都probe,之后再有deivce注册进来就不行了。这个有待验证。

        i2c驱动框架里,是在driver->probe 分配设置注册adapter,想必spi也是在driver->probe里分配设置注册master。

    [cpp] view plain copy
    1. static int __init atmel_spi_probe(struct platform_device *pdev)  
    2. {  
    3.     struct resource     *regs;  
    4.     int         irq;  
    5.     struct clk      *clk;  
    6.     int         ret;  
    7.     struct spi_master   *master;  
    8.     struct atmel_spi    *as;  
    9.       
    10.     /* 获取 device 侧提供的Io内存以及中断 */  
    11.     regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
    12.     irq = platform_get_irq(pdev, 0);  
    13.       
    14.     /* 获取 spi 时钟,一会好使能它 */  
    15.     clk = clk_get(&pdev->dev, "spi_clk");  
    16.   
    17.     /* 分配一个spi_master结构 额外加上一个 atmel_spi 用来存放其它信息 */  
    18.     master = spi_alloc_master(&pdev->dev, sizeof *as);  
    19.   
    20.     /* 设置 master  */  
    21.     master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;   // 所支持的模式  
    22.     master->bus_num = pdev->id;   // 控制器编号,用于分辨外围spi设备是连接在哪一个控制器上  
    23.     master->num_chipselect = 4;  // 片选最大值+1,spi设备的片选值要小于它  
    24.     master->setup = atmel_spi_setup; // 一个控制器上可能接有多个spi设备,它们的频率和模式是不一样的,用于设备之间切换时设置这些信息。  
    25.     master->transfer = atmel_spi_transfer;   // 最重要的发送函数  
    26.     master->cleanup = atmel_spi_cleanup;  
    27.       
    28.     /* 将 Master 放入 pdev->dev->p->driver_data 里*/  
    29.     platform_set_drvdata(pdev, master);   
    30.       
    31.     /* as 指向 master->dev->p->driver_data ,填充多出来那个 atmel_spi 结构 */  
    32.     as = spi_master_get_devdata(master);  
    33.     as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,  
    34.                     &as->buffer_dma, GFP_KERNEL);  
    35.     spin_lock_init(&as->lock);  
    36.     INIT_LIST_HEAD(&as->queue);  
    37.     as->pdev = pdev;  
    38.     as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);  
    39.     as->irq = irq;  
    40.     as->clk = clk;  
    41.       
    42.     /* 注册中断 使能时钟 */  
    43.     ret = request_irq(irq, atmel_spi_interrupt, 0,  
    44.             dev_name(&pdev->dev), master);  
    45.     clk_enable(clk);  
    46.       
    47.     /* 设置硬件寄存器 */  
    48.     spi_writel(as, CR, SPI_BIT(SWRST));  
    49.     spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */  
    50.     spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));  
    51.     spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));  
    52.     spi_writel(as, CR, SPI_BIT(SPIEN));  
    53.   
    54.     /* 注册master */  
    55.     ret = spi_register_master(master);  
    56.   
    57.     return 0;  
    58. }  

        对于master的设置过程注释已经说的很明白了,我们还得看看分配和注册过程。

    [cpp] view plain copy
    1. struct spi_master *spi_alloc_master(struct device *dev, unsigned size)  
    2. {  
    3.     struct spi_master   *master;  
    4.   
    5.     master = kzalloc(size + sizeof *master, GFP_KERNEL);  
    6.   
    7.     device_initialize(&master->dev); // 初始化设备  
    8.     master->dev.class = &spi_master_class;     
    9.     master->dev.parent = get_device(dev);    // 在 sysfs 平台设备xxx目录下创建目录  
    10.     spi_master_set_devdata(master, &master[1]);  
    11.   
    12.     return master;  
    13. }  

        1、spi_alloc_master 实际申请的内存大小为一个struct master + struct atmel_spi,并用master->dev->p->driver_data 指向这个多出来的 struct atmel_spi 空间,用来存放 master 的中断 、寄存器等东西。

        2、初始化 master->dev ,设置它的父设备等。

    [cpp] view plain copy
    1. int spi_register_master(struct spi_master *master)  
    2. {  
    3.     /* 将master注册到内核中去 */  
    4.     dev_set_name(&master->dev, "spi%u", master->bus_num);  
    5.     status = device_add(&master->dev);  
    6.       
    7.     /* 扫描spi设备信息,创建设备 */  
    8.     scan_boardinfo(master);  
    9. }  

        1、设置 master->dev 的名字,例如 spi0、spi1 ...

        2、device_add 注册设备

        3、扫描spi设备信息:scan_boardinfo(master)

    [cpp] view plain copy
    1. static void scan_boardinfo(struct spi_master *master)  
    2. {  
    3.     struct boardinfo    *bi;  
    4.   
    5.     mutex_lock(&board_lock);  
    6.     list_for_each_entry(bi, &board_list, list) {  
    7.         struct spi_board_info   *chip = bi->board_info;  
    8.         unsigned        n;  
    9.         /* 如果说  board_info 提供的bus_num 和 master—>bus_num 一致,则调用 spi_new_device */  
    10.         for (n = bi->n_board_info; n > 0; n--, chip++) {  
    11.             if (chip->bus_num != master->bus_num)  
    12.                 continue;  
    13.   
    14.             (void) spi_new_device(master, chip);    // 我们放到设备驱动层,在分析它  
    15.         }  
    16.     }  
    17.     mutex_unlock(&board_lock);  
    18. }  

        扫描 board_list ,取出每一个 boardinfo ,比对,如果 boardinfo 里的 bus_num 和 master 的 bus_num 相等,则认为这个spi设备在硬件物理连接上是接到这个控制器的,则使用 spi_new_device 创建 spi 设备。这个过程和i2c是多么的相似。至于在哪里填充的 board_list ,到后边设备层驱动框架时再说不迟。


      3.2 设备侧
        有 platform_driver 必然有 platform_device 与之对应,At91sam9260_devices.c 中定义

    [cpp] view plain copy
    1. static struct resource spi0_resources[] = {  
    2.     [0] = {  
    3.         .start  = AT91SAM9260_BASE_SPI0,  
    4.         .end    = AT91SAM9260_BASE_SPI0 + SZ_16K - 1,  
    5.         .flags  = IORESOURCE_MEM,  
    6.     },  
    7.     [1] = {  
    8.         .start  = AT91SAM9260_ID_SPI0,  
    9.         .end    = AT91SAM9260_ID_SPI0,  
    10.         .flags  = IORESOURCE_IRQ,  
    11.     },  
    12. };  

        资源文件,提供寄存器范围,spi中断。

    [cpp] view plain copy
    1. static struct platform_device at91sam9260_spi0_device = {  
    2.     .name       = "atmel_spi",      // 名字与driver一致  
    3.     .id     = 0,  
    4.     .dev        = {  
    5.                 .dma_mask       = &spi_dmamask,  
    6.                 .coherent_dma_mask  = DMA_BIT_MASK(32),  
    7.     },  
    8.     .resource   = spi0_resources,   // 资源文件  
    9.     .num_resources  = ARRAY_SIZE(spi0_resources),  
    10. };  

        与 driver 所配对的设备,显然名字是一样的。一般会有两个spi控制器,at91sam9260_spi1_device 和 at91sam9260_spi0_device 一样一样的,这里就不贴代码了。

        既然分配了 platform_device 那么肯定会在某个地方调用 platform_device_register 将它注册到 platform_bus_type , 就是在 at91_add_device_spi 。

    [cpp] view plain copy
    1. void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)  
    2. {  
    3.     ...  
    4.     spi_register_board_info(devices, nr_devices);  
    5.   
    6.     /* Configure SPI bus(es) */  
    7.     if (enable_spi0) {  
    8.         ...  
    9.         platform_device_register(&at91sam9260_spi0_device);  
    10.     }  
    11.     if (enable_spi1) {  
    12.         ...  
    13.         platform_device_register(&at91sam9260_spi1_device);  
    14.     }  
    15. }  

        1、添加 spi 设备信息,这应该是在设备驱动层要说的东西~就是前边的填充 Board_list 链表。

        2、将我们的 master 的设备侧 at91sam9260_spi0_device 注册到 platform_bus_type

        思考:这样做有什么好处呢?

            这样可以保证,master driver 与 device 匹配成功调用 probe 函数 scan_boardinfo 时,spi设备已经被添加到board_list中去~!如果先注册成功了 master 驱动,再添加spi设备信息就无用了。根 i2c 也是一样的。

        至此,Master 驱动的框架就分析完了,至于 master 的那些设置,我们到下篇文件写 master 驱动里细究。


    4、SPI 设备驱动框架

        设备驱动层,参考韦东山老师的 SPI Flash 驱动来分析,设备驱动层,device driver 都是注册到spi_bus_type的,因此,我们现在看看 spi_bus_type->match 函数,看看它们如何匹配。

    [cpp] view plain copy
    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.     const struct spi_driver *sdrv = to_spi_driver(drv);  
    5.   
    6.     if (sdrv->id_table)  
    7.         return !!spi_match_id(sdrv->id_table, spi);  
    8.   
    9.     return strcmp(spi->modalias, drv->name) == 0;  
    10. }  

        如果,driver里有id_table,则根据id_table进行匹配,没有就根据 spi->moadlias (设备名),和 driver->name 进行比较了。一样则配对成功。

      4.1 设备层

        设备层比较简单,先来分析它吧,目的只有一个分配 spi_board_info 设置 注册。

    [cpp] view plain copy
    1. static struct spi_board_info spi_info_jz2440[] = {  
    2.     {  
    3.         .modalias = "100ask_spi_flash",  /* 对应的spi_driver名字也是"oled" */  
    4.         .max_speed_hz = 80000000,   /* max spi clock (SCK) speed in HZ */  
    5.         .bus_num = 1,     /* jz2440里OLED接在SPI CONTROLLER 1 */  
    6.         .mode    = SPI_MODE_0,  
    7.         .chip_select   = S3C2410_GPG(2), /* flash_cs, 它的含义由spi_master确定 */  
    8.     }  
    9. };  

    [cpp] view plain copy
    1. static int spi_info_jz2440_init(void)  
    2. {  
    3.     return spi_register_board_info(spi_info_jz2440, ARRAY_SIZE(spi_info_jz2440));   // list_add_tail(&bi->list, &board_list);  
    4. }  

        注册 list_add_tail(&spi_info_jz2440->list, &board_list) 

        前面我们提到,master注册成功时会扫描 board_list 注册 spi 设备,现在来看看 spi 设备的注册过程,虽然没有啥重要的。

    [cpp] view plain copy
    1. struct spi_device *spi_new_device(struct spi_master *master,  
    2.                   struct spi_board_info *chip)  
    3. {  
    4.     struct spi_device   *proxy;  
    5.     int         status;  
    6.   
    7.     proxy = spi_alloc_device(master);  
    8.   
    9.     proxy->chip_select = chip->chip_select;  
    10.     proxy->max_speed_hz = chip->max_speed_hz;  
    11.     proxy->mode = chip->mode;  
    12.     proxy->irq = chip->irq;  
    13.     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));  
    14.     proxy->dev.platform_data = (void *) chip->platform_data;  
    15.     proxy->controller_data = chip->controller_data;  
    16.     proxy->controller_state = NULL;  
    17.   
    18.     status = spi_add_device(proxy);  
    19.   
    20.     return proxy;  
    21. }  
    22.   
    23. struct spi_device *spi_alloc_device(struct spi_master *master)  
    24. {  
    25.     struct spi_device   *spi;  
    26.     struct device       *dev = master->dev.parent;  
    27.   
    28.     spi = kzalloc(sizeof *spi, GFP_KERNEL);  
    29.   
    30.     spi->master = master;  
    31.     spi->dev.parent = dev;  
    32.     spi->dev.bus = &spi_bus_type;  
    33.     spi->dev.release = spidev_release;  
    34.     device_initialize(&spi->dev);  
    35.     return spi;  
    36. }  
    37.   
    38. int spi_add_device(struct spi_device *spi)  
    39. {  
    40.     static DEFINE_MUTEX(spi_add_lock);  
    41.     struct device *dev = spi->master->dev.parent;  
    42.     int status;  
    43.   
    44.     /* 片选限制 */  
    45.     if (spi->chip_select >= spi->master->num_chipselect) {  
    46.         dev_err(dev, "cs%d >= max %d ",  
    47.             spi->chip_select,  
    48.             spi->master->num_chipselect);  
    49.         return -EINVAL;  
    50.     }  
    51.   
    52.     /* Set the bus ID string */  
    53.     dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),  
    54.             spi->chip_select);  
    55.           
    56.     status = spi_setup(spi);  
    57.     /* 
    58.         if (!spi->bits_per_word) 
    59.             spi->bits_per_word = 8; 
    60.  
    61.         status = spi->master->setup(spi); 
    62.     */  
    63.   
    64.     status = device_add(&spi->dev);  
    65. }  

        有一点,需要留意的吧,我们在写 master 驱动时,master->num_chipselect 要大于我们将要注册进来的spi设备的 chip_select 。


      4.2 驱动侧

    [cpp] view plain copy
    1. static struct spi_driver spi_flash_drv = {  
    2.     .driver = {  
    3.         .name   = "100ask_spi_flash",  
    4.         .owner  = THIS_MODULE,  
    5.     },  
    6.     .probe      = spi_flash_probe,  
    7.     .remove     = __devexit_p(spi_flash_remove),  
    8. };  

        分配一个 spi_driver ,没有 id_table ,要根据名字进行匹配了,显然跟前面的设备是一样的。

    [cpp] view plain copy
    1. static int spi_flash_init(void)  
    2. {  
    3.     return spi_register_driver(&spi_flash_drv);  
    4. }  

        注册到 spi_bus_type ,匹配成功好调用 probe 函数,韦东山老师是将spi flash 作为一个mtd设备来使用的,因此在probe函数中分配、设置、注册 mtd_info 

    [cpp] view plain copy
    1. static int __devinit spi_flash_probe(struct spi_device *spi)  
    2. {  
    3.     int mid, did;  
    4.       
    5.     spi_flash = spi;  
    6.   
    7.     s3c2410_gpio_cfgpin(spi->chip_select, S3C2410_GPIO_OUTPUT);  
    8.     SPIFlashInit();  
    9.     SPIFlashReadID(&mid, &did);  
    10.     printk("SPI Flash ID: %02x %02x ", mid, did);  
    11.         memset(&spi_flash_dev, 0, sizeof(spi_flash_dev));  
    12.     /* 构造注册一个mtd_info 
    13.      * mtd_device_register(master, parts, nr_parts) 
    14.      * 
    15.      */  
    16.   
    17.     /* Setup the MTD structure */  
    18.     spi_flash_dev.name = "100ask_spi_flash";  
    19.     spi_flash_dev.type = MTD_NORFLASH;  
    20.     spi_flash_dev.flags = MTD_CAP_NORFLASH;  
    21.     spi_flash_dev.size = 0x200000;  /* 2M */  
    22.     spi_flash_dev.writesize = 1;  
    23.     spi_flash_dev.writebufsize = 4096; /* 没有用到 */  
    24.     spi_flash_dev.erasesize = 4096;  /* 擦除的最小单位 */  
    25.   
    26.     spi_flash_dev.owner = THIS_MODULE;  
    27.     spi_flash_dev._erase = spi_flash_erase;  
    28.     spi_flash_dev._read  = spi_flash_read;  
    29.     spi_flash_dev._write = spi_flash_write;  
    30.   
    31.     mtd_device_register(&spi_flash_dev, NULL, 0);  
    32.        
    33.     return 0;  
    34. }  

        在 i2c 设备驱动程序中,我们使用 i2c_read 等函数调用 adapter 里的底层收发函数进行与i2c设备通信,spi肯定也有相应的函数,例如 spi_read、spi_write ,下面我们来仔细看看,这个很重要~不然我们怎么写设备驱动呢,光写个框架不能收发那不白扯么。
    [cpp] view plain copy
    1. static inline int spi_write(struct spi_device *spi, const u8 *buf, size_t len)  
    2. {  
    3.     struct spi_transfer t = {  
    4.             .tx_buf     = buf,  
    5.             .len        = len,  
    6.         };  
    7.     struct spi_message  m;  
    8.   
    9.     spi_message_init(&m);  
    10.     spi_message_add_tail(&t, &m);  
    11.     return spi_sync(spi, &m);  
    12. }  
        以 spi_write 为例,看看它是如何调用到底层收发函数的。它构造了一个 spi_message 并由 spi_transfer组成,然后调用 spi_sync(spi, &m)->spi_async(spi,&m)->master->transfer(spi, &m).过程我们了解了,那么如何组织 spi_messgae ,它对应于时序图怎样的一个过程我们还不明白。

        还记得,i2c 是通过构造 i2c_msg ,然后传递多个 i2c_msg 给底层的发送函数,多个i2c_msg 组成start信号和p信号之间的发送过程,每一个i2c_msg 都有一个start信号。大概 i2c_msg 就类比于spi里的 spi_transfer ,但是通常情况下,整个 spi_messgae 传输过程我们只片选一次就够了。下面看个实例分析。

        上图是 spi flash 读取任意字节的时序图,片选选中之后,我们要先发送一个0x03 命令(1字节),再发送24bit(3字节)地址(先发送高位),然后读取len,最后取消片选。

    [cpp] view plain copy
    1. void SPIFlashRead(unsigned int addr, unsigned char *buf, int len)  
    2. {     
    3.     unsigned char tx_buf[4];     
    4.     struct spi_transfer t[] = {  
    5.             {  
    6.                 .tx_buf     = tx_buf,  
    7.                 .len        = 4,  
    8.             },  
    9.             {  
    10.                 .rx_buf     = buf,  
    11.                 .len        = len,  
    12.             },  
    13.         };  
    14.     struct spi_message  m;  
    15.   
    16.     tx_buf[0] = 0x03;  
    17.     tx_buf[1] = addr >> 16;  
    18.     tx_buf[2] = addr >> 8;  
    19.     tx_buf[3] = addr & 0xff;  
    20.   
    21.     spi_message_init(&m);  
    22.     spi_message_add_tail(&t[0], &m);  
    23.     spi_message_add_tail(&t[1], &m);  
    24.     spi_sync(spi_flash, &m);      
    25. }  

        韦老大的程序里,构造一个 struct spi_transfer 类型的数组,两个成员,第一个有一个tx_buf(表示写),长度为4,用来发送1字节命令和3字节地址。第二个成员 有一个rx_buf(表示读),长度由参数决定,用来读取长度len字节的内容。然后分配一个struct spi_message 并使用 spi_message_init 进行初始化,然后将 spi_transfer 数组成员依次添加到 spi_message 中去,最后 spi_sync(spi_flash, &m)

        纸上谈兵一大堆,现在来看看,我们在写一个spi设备驱动的时候需要做哪些工作。
        设备侧:
          1、分配一个 spi_board_info 结构体
          2、设置 spi_board_info 里的名字、最大频率、控制器编号、模式、片选
          3、注册 spi_register_board_info 
        驱动侧:
          1、分配一个 spi_driver 结构
          2、设置名字、probe等函数
          3、注册 spi_register_driver
          4、使用spi_write等系统调用,搞明白 spi_transfer spi_message ,会使用它们进行收发

       一个 spi_message 对应于一个不可打断的spi传输过程,可以理解为片选选中直到取消选中的过程(特殊情况下,一个spi_message里面是可以取消片选再选中的),而 spi_message 由 spi_transfer 组成,根据 tx_buf  rx_buf 是否为空来判断是 写还是读 操作。

        至此,整个 spi 的框架分析完毕


    5、设备驱动程序实例

    [cpp] view plain copy
    1. #include <linux/init.h>  
    2. #include <linux/fs.h>  
    3. #include <linux/slab.h>  
    4. #include <linux/module.h>  
    5. #include <linux/kernel.h>  
    6. #include <linux/device.h>  
    7. #include <sound/core.h>  
    8. #include <linux/spi/spi.h>  
    9. #include <asm/uaccess.h>  
    10. #include <linux/timer.h>  
    11.   
    12. #include <mach/hardware.h>  
    13. #include <mach/regs-gpio.h>  
    14.   
    15. #include <linux/gpio.h>  
    16. #include <plat/gpio-cfg.h>  
    17.   
    18. #include <linux/mtd/cfi.h>  
    19. #include <linux/mtd/mtd.h>  
    20. #include <linux/mtd/partitions.h>  
    21.   
    22. /* 参考: 
    23.  * driversmtddevicesmtdram.c 
    24.  * drivers/mtd/devices/m25p80.c 
    25.  */  
    26.   
    27. static struct spi_device *spi_flash;  
    28.   
    29. /*  
    30.  *  
    31.  */  
    32. void SPIFlashReadID(int *pMID, int *pDID)  
    33. {  
    34.     unsigned char tx_buf[4];  
    35.     unsigned char rx_buf[2];  
    36.       
    37.     tx_buf[0] = 0x90;  
    38.     tx_buf[1] = 0;  
    39.     tx_buf[2] = 0;  
    40.     tx_buf[3] = 0;  
    41.   
    42.     spi_write_then_read(spi_flash, tx_buf, 4, rx_buf, 2);  
    43.   
    44.     *pMID = rx_buf[0];  
    45.     *pDID = rx_buf[1];  
    46. }  
    47.   
    48. static void SPIFlashWriteEnable(int enable)  
    49. {  
    50.     unsigned char val = enable ? 0x06 : 0x04;  
    51.     spi_write(spi_flash, &val, 1);      
    52. }  
    53.   
    54. static unsigned char SPIFlashReadStatusReg1(void)  
    55. {  
    56.     unsigned char val;  
    57.     unsigned char cmd = 0x05;  
    58.   
    59.     spi_write_then_read(spi_flash, &cmd, 1, &val, 1);  
    60.       
    61.     return val;  
    62. }  
    63.   
    64. static unsigned char SPIFlashReadStatusReg2(void)  
    65. {  
    66.     unsigned char val;  
    67.     unsigned char cmd = 0x35;  
    68.   
    69.     spi_write_then_read(spi_flash, &cmd, 1, &val, 1);  
    70.       
    71.     return val;  
    72. }  
    73.   
    74. static void SPIFlashWaitWhenBusy(void)  
    75. {  
    76.     while (SPIFlashReadStatusReg1() & 1)  
    77.     {  
    78.         /* 休眠一段时间 */  
    79.         /* Sector erase time : 60ms 
    80.          * Page program time : 0.7ms 
    81.          * Write status reg time : 10ms 
    82.          */  
    83.         set_current_state(TASK_INTERRUPTIBLE);  
    84.         schedule_timeout(HZ/100);  /* 休眠10MS后再次判断 */  
    85.     }  
    86. }  
    87.   
    88. static void SPIFlashWriteStatusReg(unsigned char reg1, unsigned char reg2)  
    89. {      
    90.     unsigned char tx_buf[4];  
    91.   
    92.     SPIFlashWriteEnable(1);    
    93.       
    94.     tx_buf[0] = 0x01;  
    95.     tx_buf[1] = reg1;  
    96.     tx_buf[2] = reg2;  
    97.   
    98.     spi_write(spi_flash, tx_buf, 3);     
    99.   
    100.     SPIFlashWaitWhenBusy();  
    101. }  
    102.   
    103. static void SPIFlashClearProtectForStatusReg(void)  
    104. {  
    105.     unsigned char reg1, reg2;  
    106.   
    107.     reg1 = SPIFlashReadStatusReg1();  
    108.     reg2 = SPIFlashReadStatusReg2();  
    109.   
    110.     reg1 &= ~(1<<7);  
    111.     reg2 &= ~(1<<0);  
    112.   
    113.     SPIFlashWriteStatusReg(reg1, reg2);  
    114. }  
    115.   
    116. static void SPIFlashClearProtectForData(void)  
    117. {  
    118.     /* cmp=0,bp2,1,0=0b000 */  
    119.     unsigned char reg1, reg2;  
    120.   
    121.     reg1 = SPIFlashReadStatusReg1();  
    122.     reg2 = SPIFlashReadStatusReg2();  
    123.   
    124.     reg1 &= ~(7<<2);  
    125.     reg2 &= ~(1<<6);  
    126.   
    127.     SPIFlashWriteStatusReg(reg1, reg2);  
    128. }  
    129.   
    130. /* erase 4K */  
    131. void SPIFlashEraseSector(unsigned int addr)  
    132. {  
    133.     unsigned char tx_buf[4];  
    134.     tx_buf[0] = 0x20;  
    135.     tx_buf[1] = addr >> 16;  
    136.     tx_buf[2] = addr >> 8;  
    137.     tx_buf[3] = addr & 0xff;  
    138.   
    139.     SPIFlashWriteEnable(1);    
    140.   
    141.     spi_write(spi_flash, tx_buf, 4);  
    142.   
    143.     SPIFlashWaitWhenBusy();  
    144. }  
    145.   
    146. /* program */  
    147. void SPIFlashProgram(unsigned int addr, unsigned char *buf, int len)  
    148. {  
    149.     unsigned char tx_buf[4];     
    150.     struct spi_transfer t[] = {  
    151.             {  
    152.                 .tx_buf     = tx_buf,  
    153.                 .len        = 4,  
    154.             },  
    155.             {  
    156.                 .tx_buf     = buf,  
    157.                 .len        = len,  
    158.             },  
    159.         };  
    160.     struct spi_message  m;  
    161.   
    162.     tx_buf[0] = 0x02;  
    163.     tx_buf[1] = addr >> 16;  
    164.     tx_buf[2] = addr >> 8;  
    165.     tx_buf[3] = addr & 0xff;  
    166.   
    167.     SPIFlashWriteEnable(1);    
    168.   
    169.     spi_message_init(&m);  
    170.     spi_message_add_tail(&t[0], &m);  
    171.     spi_message_add_tail(&t[1], &m);  
    172.     spi_sync(spi_flash, &m);  
    173.   
    174.     SPIFlashWaitWhenBusy();      
    175. }  
    176.   
    177. void SPIFlashRead(unsigned int addr, unsigned char *buf, int len)  
    178. {  
    179.     /* spi_write_then_read规定了tx_cnt+rx_cnt < 32 
    180.      * 所以对于大量数据的读取,不能使用该函数 
    181.      */  
    182.        
    183.     unsigned char tx_buf[4];     
    184.     struct spi_transfer t[] = {  
    185.             {  
    186.                 .tx_buf     = tx_buf,  
    187.                 .len        = 4,  
    188.             },  
    189.             {  
    190.                 .rx_buf     = buf,  
    191.                 .len        = len,  
    192.             },  
    193.         };  
    194.     struct spi_message  m;  
    195.   
    196.     tx_buf[0] = 0x03;  
    197.     tx_buf[1] = addr >> 16;  
    198.     tx_buf[2] = addr >> 8;  
    199.     tx_buf[3] = addr & 0xff;  
    200.   
    201.     spi_message_init(&m);  
    202.     spi_message_add_tail(&t[0], &m);  
    203.     spi_message_add_tail(&t[1], &m);  
    204.     spi_sync(spi_flash, &m);      
    205. }  
    206.   
    207. static void SPIFlashInit(void)  
    208. {  
    209.     SPIFlashClearProtectForStatusReg();  
    210.     SPIFlashClearProtectForData();  
    211. }  
    212.   
    213. /* 构造注册一个mtd_info 
    214.  * mtd_device_register(master, parts, nr_parts) 
    215.  * 
    216.  */  
    217.   
    218. /* 首先: 构造注册spi_driver 
    219.  * 然后: 在spi_driver的probe函数里构造注册mtd_info 
    220.  */  
    221.   
    222. static struct mtd_info spi_flash_dev;  
    223.   
    224. static int spi_flash_erase(struct mtd_info *mtd, struct erase_info *instr)  
    225. {  
    226.     unsigned int addr = instr->addr;  
    227.     unsigned int len  = 0;  
    228.   
    229.     /* 判断参数 */  
    230.     if ((addr & (spi_flash_dev.erasesize - 1)) || (instr->len & (spi_flash_dev.erasesize - 1)))  
    231.     {  
    232.         printk("addr/len is not aligned ");  
    233.         return -EINVAL;  
    234.     }  
    235.   
    236.     for (len = 0; len < instr->len; len += 4096)  
    237.     {  
    238.         SPIFlashEraseSector(addr);  
    239.         addr += 4096;  
    240.     }  
    241.       
    242.     instr->state = MTD_ERASE_DONE;  
    243.     mtd_erase_callback(instr);  
    244.     return 0;  
    245. }  
    246.   
    247. static int spi_flash_read(struct mtd_info *mtd, loff_t from, size_t len,  
    248.         size_t *retlen, u_char *buf)  
    249. {  
    250.     SPIFlashRead(from, buf, len);  
    251.     *retlen = len;  
    252.     return 0;  
    253. }  
    254.   
    255. static int spi_flash_write(struct mtd_info *mtd, loff_t to, size_t len,  
    256.         size_t *retlen, const u_char *buf)  
    257. {  
    258.     unsigned int addr = to;  
    259.     unsigned int wlen  = 0;  
    260.   
    261.     /* 判断参数 */  
    262.     if ((to & (spi_flash_dev.erasesize - 1)) || (len & (spi_flash_dev.erasesize - 1)))  
    263.     {  
    264.         printk("addr/len is not aligned ");  
    265.         return -EINVAL;  
    266.     }  
    267.   
    268.     for (wlen = 0; wlen < len; wlen += 256)  
    269.     {  
    270.         SPIFlashProgram(addr, (unsigned char *)buf, 256);  
    271.         addr += 256;  
    272.         buf += 256;  
    273.     }  
    274.   
    275.     *retlen = len;  
    276.     return 0;  
    277. }  
    278.   
    279. static int __devinit spi_flash_probe(struct spi_device *spi)  
    280. {  
    281.     int mid, did;  
    282.       
    283.     spi_flash = spi;  
    284.   
    285.     s3c2410_gpio_cfgpin(spi->chip_select, S3C2410_GPIO_OUTPUT);  
    286.     SPIFlashInit();  
    287.     SPIFlashReadID(&mid, &did);  
    288.     printk("SPI Flash ID: %02x %02x ", mid, did);  
    289.         memset(&spi_flash_dev, 0, sizeof(spi_flash_dev));  
    290.     /* 构造注册一个mtd_info 
    291.      * mtd_device_register(master, parts, nr_parts) 
    292.      * 
    293.      */  
    294.   
    295.     /* Setup the MTD structure */  
    296.     spi_flash_dev.name = "100ask_spi_flash";  
    297.     spi_flash_dev.type = MTD_NORFLASH;  
    298.     spi_flash_dev.flags = MTD_CAP_NORFLASH;  
    299.     spi_flash_dev.size = 0x200000;  /* 2M */  
    300.     spi_flash_dev.writesize = 1;  
    301.     spi_flash_dev.writebufsize = 4096; /* 没有用到 */  
    302.     spi_flash_dev.erasesize = 4096;  /* 擦除的最小单位 */  
    303.   
    304.     spi_flash_dev.owner = THIS_MODULE;  
    305.     spi_flash_dev._erase = spi_flash_erase;  
    306.     spi_flash_dev._read  = spi_flash_read;  
    307.     spi_flash_dev._write = spi_flash_write;  
    308.   
    309.     mtd_device_register(&spi_flash_dev, NULL, 0);  
    310.        
    311.     return 0;  
    312. }  
    313.   
    314. static int __devexit spi_flash_remove(struct spi_device *spi)  
    315. {  
    316.     mtd_device_unregister(&spi_flash_dev);  
    317.     return 0;  
    318. }  
    319.   
    320. static struct spi_driver spi_flash_drv = {  
    321.     .driver = {  
    322.         .name   = "100ask_spi_flash",  
    323.         .owner  = THIS_MODULE,  
    324.     },  
    325.     .probe      = spi_flash_probe,  
    326.     .remove     = __devexit_p(spi_flash_remove),  
    327. };  
    328.   
    329. static int spi_flash_init(void)  
    330. {  
    331.     return spi_register_driver(&spi_flash_drv);  
    332. }  
    333.   
    334. static void spi_flash_exit(void)  
    335. {  
    336.     spi_unregister_driver(&spi_flash_drv);  
    337. }  
    338.   
    339. module_init(spi_flash_init);  
    340. module_exit(spi_flash_exit);  
    341. MODULE_DESCRIPTION("Flash SPI Driver");  
    342. MODULE_AUTHOR("weidongshan@qq.com,www.100ask.net");  
    343. MODULE_LICENSE("GPL");  
    344.   
    345.   
    346. <strong style="color: rgb(255, 0, 0);">  
    347. </strong>  

    转自:http://blog.csdn.net/lizuobin2/article/details/51735963

      


  • 相关阅读:
    基本HAL库操作函数整理
    oled(iic协议)
    Uart串口中断收发
    博主回来啦
    博主的冒泡1
    AFO

    起床困难综合症
    费解的开关
    数独
  • 原文地址:https://www.cnblogs.com/alan666/p/8311854.html
Copyright © 2020-2023  润新知