Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2675743
  • 博文数量: 877
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5921
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-05 12:25
个人简介

技术的乐趣在于分享,欢迎多多交流,多多沟通。

文章分类

全部博文(877)

文章存档

2021年(2)

2016年(20)

2015年(471)

2014年(358)

2013年(26)

分类: LINUX

2014-08-15 15:45:04

原文地址:SPI设备的驱动 作者:wangchenxicool

今天折腾了一天的SPI设备的驱动加载,甚至动用了逻辑分析仪来查看spi总线的波形,主要包括两个SPI设备,at45db321dmcp2515,一个是串行的dataflash,一个是can总线设备芯片。前者对于我们来说非常重要,我们可以借助该设备对uboot和kernel以及根文件系统进行更新。

    预备知识:设备和驱动是如何匹配的?系统的热插拔是如何实现的?
[device_register]
    首先一点,设备和驱动是严格区分的,设备是设备,驱动是驱动,设备通过struct device来定义,当然用户也可以将该结构体封装到自己定义的device结构体中,例如,struct platform_device,这是我们采用platform_bus_type总线的设备定义的结构体形式:
include/linux/platform_device.h文件中:
  1. struct platform_device {
  2.     const char * name;
  3.     u32 id;
  4.     struct device dev;
  5.     u32 num_resources;
  6.     struct resource * resource;
  7. };
只要是9260的外围模块,就像IIC硬件控制器,SPI硬件控制器,都被完全的定义成这种结构体的格式,这种结构体主要包含了硬件资源和名称,硬件资源分为寄存器和IRQ两种。platform_device通过向内核注册struct device dev这个结构体来告诉内核加载这个设备
 方法就是  device_register(&platform_device->dev)  
内核不关心你使用的是platform_device还是spi_device,内核只关心你的struct device结构体,内核通过这个struct device结构体自然能够顺藤摸瓜找到你是platform_device还是spi_device,这就是linux最引以为傲的contian_of()。
[driver_register]
驱动通过struct driver这个结构体来定义,与struct device一致,你也可以用自己的结构体去封装:例如,struct platform_driver。
include/linux/platform_device.h文件中:
  1. struct platform_driver {
  2.     int (*probe)(struct platform_device *);
  3.     int (*remove)(struct platform_device *);
  4.     void (*shutdown)(struct platform_device *);
  5.     int (*suspend)(struct platform_device *, pm_message_t state);
  6.     int (*suspend_late)(struct platform_device *, pm_message_t state);
  7.     int (*resume_early)(struct platform_device *);
  8.     int (*resume)(struct platform_device *);
  9.     struct device_driver driver;
  10. };
与device一致,应用程序通过driver_register(&platform_driver->driver)向内核中注册你当前的驱动,而内核不关心你封装成的结构,而内核搜索的方法还是同样的contain_of。
[总线]
系统如何将这两者匹配上的?而不会将iic的设备加载到spi的驱动上面?不会将这个iic设备的驱动加载到那个iic设备上,设备和驱动之间是如何联系的?总线,这就是总线的作用!
include/linux/device.h文件中有总线类型的定义。
  1. struct bus_type {
  2.     const char * name;
  3.     struct subsystem subsys;
  4.     struct kset drivers;
  5.     struct kset devices;
  6.     struct klist klist_devices;
  7.     struct klist klist_drivers;
  8.     struct blocking_notifier_head bus_notifier;
  9.     struct bus_attribute * bus_attrs;
  10.     struct device_attribute * dev_attrs;
  11.     struct driver_attribute * drv_attrs;
  12.     int (*match)(struct device * dev, struct device_driver * drv);
  13.     int (*uevent)(struct device *dev, char **envp,
  14.                   int num_envp, char *buffer, int buffer_size);
  15.     int (*probe)(struct device * dev);
  16.     int (*remove)(struct device * dev);
  17.     void (*shutdown)(struct device * dev);
  18.     int (*suspend)(struct device * dev, pm_message_t state);
  19.     int (*suspend_late)(struct device * dev, pm_message_t state);
  20.     int (*resume_early)(struct device * dev);
  21.     int (*resume)(struct device * dev);
  22. };
这个总线设备中最重要的可能是match成员,由于我们一般很少去建立一个新的总线,所以我们很少涉及总线的编程,我们就只关注我们所关注的。
总线如何将两者关联起来,热插拔大家知道吧,当一个设备被通过device_register注册到内核中时,会导致一个热插拔事件产生,系统会遍历该总线上的所有驱动程序,调用bus的match算法,来寻找与该设备相匹配的驱动程序,当一个驱动注册到内核的时候,处理过程与此相似(这是我理解的阿,大家批评指正),而一般的macth算法都比较简单,例如platform_bus的匹配算法就很简单,就是比较platform_device和platform_driver的name成员,如果匹配成功,就加载相应的设备或者驱动!这就完成了一个连接的过程。。。
[sys文件系统]
那么这两种设备驱动中最重要的类型在linux中如何表现出来,那我们就有必要介绍一下从2.6开始实现的sys文件系统了,
/sys/bus $ cat /etc/fstab
  1. proc /proc proc defaults 0 0
  2. devpts /dev/pts devpts defaults 0 0
  3. tmpfs /dev/shm tmpfs defaults 0 0
  4. sysfs /sys sysfs defaults 0 0
  5. /dev/mtdblock2 /mnt/flash2 yaffs defaults 0 0
加载这个文件系统对于我们分析设备模型是非常有好处的。
sys文件夹下一般有如下的目录:
/sys $ ls -al
  1. drwxr-xr-x 10 root root 0 Jan 1 1970 .
  2. drwxrwxrwx 11 1000 tao 4096 May 22 06:56 ..
  3. drwxr-xr-x 7 root root 0 Oct 27 14:09 block
  4. drwxr-xr-x 8 root root 0 Jan 1 1970 bus
  5. drwxr-xr-x 21 root root 0 Jan 1 1970 class
  6. drwxr-xr-x 4 root root 0 Jan 1 1970 devices
  7. drwxr-xr-x 2 root root 0 Jan 1 1970 firmware
  8. drwxr-xr-x 2 root root 0 Jan 1 1970 fs
  9. drwxr-xr-x 2 root root 0 Jan 1 1970 kernel
  10. drwxr-xr-x 22 root root 0 Oct 27 14:10 module
block是由于历史原因形成的block设备的文件夹。我们关心的是bus文件夹。
我们以spi设备为例:spi部分要包括两种设备,一种是platform_device,一种是spi_device。
arch/arm/mach-at91/at91sam9260_device.c文件中,定义的SPI硬件控制模块设备,这我们不需要关心。
还有一种是spi_device,定义在arch/arm/mach-at91/board-sam9260ek.c文件中,这就是我们的dataflash和mcp2515设备,
所以如何设备加载成功的话,在bus下面的每个目录里面,都存在devices和drivers两个文件夹,分别对应设备和文件。
/sys/bus/platform/devices $ ls -al
  1. drwxr-xr-x 2 root root 0 Oct 27 16:01 .
  2. drwxr-xr-x 4 root root 0 Jan 1 1970 ..
  3. lrwxrwxrwx 1 root root 0 Oct 27 16:01 at91_i2c -> ../../../devices/platform/at91_i2c
  4. lrwxrwxrwx 1 root root 0 Oct 27 16:01 at91_nand -> ../../../devices/platform/at91_nand
  5. lrwxrwxrwx 1 root root 0 Oct 27 16:01 at91_ohci -> ../../../devices/platform/at91_ohci
  6. lrwxrwxrwx 1 root root 0 Oct 27 16:01 atmel_spi.0 -> ../../../devices/platform/atmel_spi.0
  7. lrwxrwxrwx 1 root root 0 Oct 27 16:01 atmel_spi.1 -> ../../../devices/platform/atmel_spi.1
  8. lrwxrwxrwx 1 root root 0 Oct 27 16:01 atmel_usart.0 -> ../../../devices/platform/atmel_usart.0
  9. lrwxrwxrwx 1 root root 0 Oct 27 16:01 atmel_usart.1 -> ../../../devices/platform/atmel_usart.1
  10. lrwxrwxrwx 1 root root 0 Oct 27 16:01 atmel_usart.2 -> ../../../devices/platform/atmel_usart.2
  11. lrwxrwxrwx 1 root root 0 Oct 27 16:01 macb -> ../../../devices/platform/macb
  12. 驱动
  13. /sys/bus/platform/drivers/atmel_spi $ ls -al
  14. drwxr-xr-x 2 root root 0 Jan 1 1970 .
  15. drwxr-xr-x 8 root root 0 Jan 1 1970 ..
  16. lrwxrwxrwx 1 root root 0 Oct 27 16:10 atmel_spi.0 -> ../../../../devices/platform/atmel_spi.0
  17. lrwxrwxrwx 1 root root 0 Oct 27 16:10 atmel_spi.1 -> ../../../../devices/platform/atmel_spi.1
  18. --w------- 1 root root 4096 Oct 27 16:10 bind
  19. --w------- 1 root root 4096 Oct 27 16:10 unbind
如果出现上面的这个情况,说明你的设备(两路spi总线)和驱动都加载成功了,如果你的devices下面没有spi.0设备和spi.1设备的话,说明
board-sam9260ek.c文件中的这个函数出错:
  1. static void __init ek_board_init(void)
  2. {
  3.     /* Serial */
  4.     at91_add_device_serial();
  5.     /* USB Host */
  6.     at91_add_device_usbh(&ek_usbh_data);
  7.     /* USB Device */
  8.     at91_add_device_udc(&ek_udc_data);
  9.     /* SPI */
  10.     at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
  11.     /* NAND */
  12.     at91_add_device_nand(&ek_nand_data);
  13.     /* Ethernet */
  14.     at91_add_device_eth(&ek_macb_data);
  15.     /* MMC */
  16.     at91_add_device_mmc(0, &ek_mmc_data);
  17.     /* I2C */
  18.     at91_add_device_i2c();
  19. }
这里是设备注册的地方,我们还应该在下面这个目录下看到这两个文件。
/sys/bus/spi/devices $ ls -al
  1. drwxr-xr-x 2 root root 0 Oct 27 14:09 .
  2. drwxr-xr-x 4 root root 0 Jan 1 1970 ..
  3. lrwxrwxrwx 1 root root 0 Oct 27 14:09 spi0.1 -> ../../../devices/platform/atmel_spi.0/spi0.1
  4. lrwxrwxrwx 1 root root 0 Oct 27 14:09 spi1.0 -> ../../../devices/platform/atmel_spi.1/spi1.0
这两个链接说明我们的两个spi设备注册都被接受了,剩下来就是驱动的问题。有人看不懂这个sys文件系统的层次关系,其实这里比较好说明,就是spi0.1是atmel_spi.0设备的子设备嘛,很好理解的。
[驱动]
platform_driver驱动:
/sys/bus/platform/drivers $ ls -al
  1. drwxr-xr-x 8 root root 0 Jan 1 1970 .
  2. drwxr-xr-x 4 root root 0 Jan 1 1970 ..
  3. drwxr-xr-x 2 root root 0 Jan 1 1970 at91_i2c
  4. drwxr-xr-x 2 root root 0 Jan 1 1970 at91_nand
  5. drwxr-xr-x 2 root root 0 Jan 1 1970 at91_ohci
  6. drwxr-xr-x 2 root root 0 Oct 27 16:10 atmel_spi
  7. drwxr-xr-x 2 root root 0 Jan 1 1970 atmel_usart
  8. drwxr-xr-x 2 root root 0 Jan 1 1970 macb
我们可以看到这个驱动只有一个atmel_spi,这个驱动是在哪加载的?
driver/spi/atmel_spi.c文件加载的。
spi_driver驱动:
/sys/bus/spi/drivers $ ls -al
  1. drwxr-xr-x 4 root root 0 Oct 27 14:10 .
  2. drwxr-xr-x 4 root root 0 Jan 1 1970 ..
  3. drwxr-xr-x 2 root root 0 Oct 27 14:10 mcp2515
  4. drwxr-xr-x 2 root root 0 Oct 27 14:09 mtd_dataflash
这是我们加载的两个驱动,说明驱动也加载正常了。
下面我们来说说我们遇到的问题吧。
在设备和驱动都加载正常之后,出现与dataflash设备通信不上的情况,驱动加载的时候,读取芯片的状态字读出是0xff,说明工作不正常,动用逻辑分析仪监控spi总线的通信,意外的发现,sck信号和cs信号正常,但是mosi无信号输出,开始觉得可能是spi总线适配器有问题,后来仔细观察原理图之后,发现dataflash和mmc/sd是使用同样的io口的,即pa0,pa1,pa2,而我的内核配置中打开了对mmc的支持,所以导致mosi不正常,所以可能9260的mmc与dataflash不能同时使用,但9263的可以。
解决办法:make menuconfig
Device Drivers--->MMC/SD card support,取消其支持,问题解决!
 
昨天其实还有一个问题可能大家没有注意到,没有解释清楚,其实是有问题的,我们的at91_add_device_spi函数如下:
  1. static struct spi_board_info ek_spi_devices[] = {
  2. #if !defined(CONFIG_MMC_AT91)
  3.     { /* DataFlash chip */
  4.         .modalias = "mtd_dataflash",
  5.         .chip_select = 1,
  6.         .max_speed_hz = 15 * 1000 * 1000,
  7.         .bus_num = 0,
  8.     },
  9. #if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
  10.     { /* DataFlash card */
  11.         .modalias = "mtd_dataflash",
  12.         .chip_select = 0,
  13.         .max_speed_hz = 15 * 1000 * 1000,
  14.         .bus_num = 0,
  15.     },
  16. #endif
  17. #endif
  18. #if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
  19.     { /* AT73C213 DAC */
  20.         .modalias = "at73c213",
  21.         .chip_select = 0,
  22.         .max_speed_hz = 10 * 1000 * 1000,
  23.         .bus_num = 1,
  24.     },
  25. #endif
  26. /* spi can ,add by mrz */
  27. #if defined(CONFIG_CAN_MCP2515_MODULE) ||defined(CONFIG_CAN_MCP2515)
  28. //defined(CONFIG_CAN_MCP2515)

  29.     {
  30.         .modalias = "mcp2515",
  31.         .chip_select = 0,
  32. // .controller_data = AT91_PIN_PB3,

  33.         .irq = AT91_PIN_PC6, //AT91SAM9260_ID_IRQ0,

  34.         .platform_data = &mcp251x_data,
  35.         .max_speed_hz = 10 * 1000 * 1000,
  36.         .bus_num = 1,
  37.         .mode = 0,
  38.     },
  39.     /*
  40.     {
  41.         .modalias = "mcp2515",
  42.         .chip_select = 1,
  43. // .controller_data = AT91_PIN_PC5,
  44.         .irq = AT91_PIN_PC7, //AT91SAM9260_ID_IRQ1,
  45.         .platform_data = &mcp251x_data,
  46.         .max_speed_hz = 10 * 1000 * 1000,
  47.         .bus_num = 1,
  48.         .mode = 0,
  49.     },
  50. */
  51. #elif defined(CONFIG_CAN_MCP251X)
  52.     {
  53.         .modalias = "mcp251x",
  54.         .chip_select = 0,
  55. // .controller_data = AT91_PIN_PB3,

  56.         .irq = AT91_PIN_PC6, //AT91SAM9260_ID_IRQ0,

  57.         .platform_data = &mcp251x_data,
  58.         .max_speed_hz = 10 * 1000 * 1000,
  59.         .bus_num = 1,
  60.         .mode = 0,
  61.     },
  62.     {
  63.         .modalias = "mcp251x",
  64.         .chip_select = 1,
  65. // .controller_data = AT91_PIN_PC5,

  66.         .irq = AT91_PIN_PC7, //AT91SAM9260_ID_IRQ1,

  67.         .platform_data = &mcp251x_data,
  68.         .max_speed_hz = 10 * 1000 * 1000,
  69.         .bus_num = 1,
  70.         .mode = 0,
  71.     },
  72. #endif
  73. }
  74. void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
  75. {
  76.     int i;
  77.     unsigned long cs_pin;
  78.     short enable_spi0 = 0;
  79.     short enable_spi1 = 0;
  80.     /* Choose SPI chip-selects */
  81.     /*这里加载我们定义的spi_board_info结构体,也就是两个spi设备的信息,注意,他们这里没有使用spi_device结构体来做,而是使用一个板级信息体来完成。*/
  82.     for (i = 0; i < nr_devices; i++) {
  83.     /*该成员定义的就是cs引脚*/
  84.         if (devices[i].controller_data)
  85.             cs_pin = (unsigned long) devices[i].controller_data;
  86.         else if (devices[i].bus_num == 0)
  87.             cs_pin = spi0_standard_cs[devices[i].chip_select];
  88.         else
  89.             cs_pin = spi1_standard_cs[devices[i].chip_select];
  90.     /*根据需要加载的设备,确定需要打开哪几个SPI控制器,我们系统中有两个控制器,所以我们在以模块的方式加载驱动的时候,我们的设备必须在刚开始就被初始化!*/
  91.         if (devices[i].bus_num == 0)
  92.             enable_spi0 = 1;
  93.         else
  94.             enable_spi1 = 1;
  95.         /* enable chip-select pin */
  96.       /*将片选引脚设置为输出*/
  97.         at91_set_gpio_output(cs_pin, 1);
  98.         /* pass chip-select pin to driver */
  99.         devices[i].controller_data = (void *) cs_pin;
  100.     }
  101.     /*到此,循环执行完毕,向内核注册这些板级信息体*/
  102.     spi_register_board_info(devices, nr_devices);
  103.     /* Configure SPI bus(es) */
  104.     /*如果发现spi0上有设备注册,则打开spi0*/
  105.     if (enable_spi0) {
  106.         at91_set_A_periph(AT91_PIN_PA0, 0); /* SPI0_MISO */
  107.         at91_set_A_periph(AT91_PIN_PA1, 0); /* SPI0_MOSI */
  108.         at91_set_A_periph(AT91_PIN_PA2, 0); /* SPI1_SPCK */
  109.         at91_clock_associate("spi0_clk", &at91sam9260_spi0_device.dev, "spi_clk");
  110.         platform_device_register(&at91sam9260_spi0_device);
  111.     }
  112.     /*spi0设备也是如此*/
  113.     if (enable_spi1) {
  114.         at91_set_A_periph(AT91_PIN_PB0, 0); /* SPI1_MISO */
  115.         at91_set_A_periph(AT91_PIN_PB1, 0); /* SPI1_MOSI */
  116.         at91_set_A_periph(AT91_PIN_PB2, 0); /* SPI1_SPCK */
  117.         at91_clock_associate("spi1_clk", &at91sam9260_spi1_device.dev, "spi_clk");
  118.         platform_device_register(&at91sam9260_spi1_device);
  119.     }
  120. }
从上面这个函数我们可以看出,这个函数就完成了两个功能:
1、向内核完成spi板级信息结构体的注册
2、注册了两个platform_device:spi0与spi1,这两个设备是spi总线控制器!
那么我们客户端spi_device设备的注册是如何完成的?不知道,呵呵
我今天仔细的看代码才发现玄机所在。
内核的注释很清晰的告诉我们,我们的spi设备是不允许热插拔!!这是由于spi设备驱动的框架不允许,我们的spi_device设备注册不是在板级初始化的时候完成的。
在spi控制器的驱动加载的时候,也就是platform_driver:atmel_spi驱动加载的时候,
driver/spi/atmel_spi.c文件中:
  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.     regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  10.     if (!regs)
  11.         return -ENXIO;
  12.     irq = platform_get_irq(pdev, 0);
  13.     if (irq < 0)
  14.         return irq;
  15.     clk = clk_get(&pdev->dev, "spi_clk");
  16.     if (IS_ERR(clk))
  17.         return PTR_ERR(clk);

  18. /* setup spi core then atmel-specific driver state */
  19.     ret = -ENOMEM;
  20.     master = spi_alloc_master(&pdev->dev, sizeof *as);
  21.     if (!master)
  22.         goto out_free;
  23.     master->bus_num = pdev->id;
  24.     master->num_chipselect = 4;
  25.     master->setup = atmel_spi_setup;
  26.     master->transfer = atmel_spi_transfer;
  27.     master->cleanup = atmel_spi_cleanup;
  28.     platform_set_drvdata(pdev, master);
  29.     as = spi_master_get_devdata(master);
  30.     as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
  31.                     &as->buffer_dma, GFP_KERNEL);
  32.     if (!as->buffer)
  33.         goto out_free;
  34.     spin_lock_init(&as->lock);
  35.     INIT_LIST_HEAD(&as->queue);
  36.     as->pdev = pdev;
  37.     as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
  38.     if (!as->regs)
  39.         goto out_free_buffer;
  40.     as->irq = irq;
  41.     as->clk = clk;
  42. #ifdef CONFIG_ARCH_AT91
  43.     if (!cpu_is_at91rm9200())
  44.         as->new_1 = 1;
  45. #endif
  46.     ret = request_irq(irq, atmel_spi_interrupt, 0,
  47.             pdev->dev.bus_id, master);
  48.     if (ret)
  49.         goto out_unmap_regs;
  50.     /* Initialize the hardware */
  51.     clk_enable(clk);
  52.     spi_writel(as, CR, SPI_BIT(SWRST));
  53.     spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
  54.     spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
  55.     spi_writel(as, CR, SPI_BIT(SPIEN));
  56.     /* go! */
  57.     dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n",
  58.             (unsigned long)regs->start, irq);
  59.     /*spi注册这个主控制器*/
  60.     ret = spi_register_master(master);
  61.     if (ret)
  62.         goto out_reset_hw;
  63.     return 0;
  64. out_reset_hw:
  65.     spi_writel(as, CR, SPI_BIT(SWRST));
  66.     clk_disable(clk);
  67.     free_irq(irq, master);
  68. out_unmap_regs:
  69.     iounmap(as->regs);
  70. out_free_buffer:
  71.     dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
  72.             as->buffer_dma);
  73. out_free:
  74.     clk_put(clk);
  75.     spi_master_put(master);
  76.     return ret;
  77. }
而这个spi_register_master位于driver/spi/spi.c文件中,该函数调用了scan_boardinfo(master),扫描该spi master下面设备。该函数就存在于该文件下:该函数调用了spi_new_device(master, chip),这个chip就是一个spi_board_info结构体,这就是at91_add_device_spi第一个作用的用处:向内核的链表注册spi_board_info结构体的用处所在。我们来看函数的调用过程:
atmel_spi_probe----->spi_register_master----->scan_boardinfo
---->spi_new_device
我们来看这个spi_new_device函数:
  1. struct spi_device *spi_new_device(struct spi_master *master,
  2.                   struct spi_board_info *chip)
  3. {
  4.     struct spi_device *proxy;
  5.     struct device *dev = master->cdev.dev;
  6.     int status;
  7.     /* NOTE: caller did any chip->bus_num checks necessary */
  8.     if (!spi_master_get(master))
  9.         return NULL;
  10.     /*靠,终于找到你了,先暴打一顿,舒服了。。这里就分配了我们重要的spi_device结构体*/
  11.     proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
  12.     if (!proxy) {
  13.         dev_err(dev, "can't alloc dev for cs%d\n",
  14.             chip->chip_select);
  15.         goto fail;
  16.     }
/*这就是将我们的信息体中的数据转化为spi_device识别的数据*/
  1. proxy->master = master;
  2. proxy->chip_select = chip->chip_select;
  3. proxy->max_speed_hz = chip->max_speed_hz;
  4. proxy->mode = chip->mode;
  5. proxy->irq = chip->irq;
  6. proxy->modalias = chip->modalias;
  7. snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
  8. "%s.%u", master->cdev.class_id,
  9. chip->chip_select);
  10. proxy->dev.parent = dev;
  11. proxy->dev.bus = &spi_bus_type;
    
  /*这里很重要,如果你的spi设备是dataflash的话,保存的就是你的分区表!!!所以我们要返回去修改我们的spi_boardinfo结构体*/
   
  1. proxy->dev.platform_data = (void *) chip->platform_data;
  2.     /*片选信号*/
  3.     proxy->controller_data = chip->controller_data;
  4.     proxy->controller_state = NULL;
  5.     proxy->dev.release = spidev_release;
  6.     /* drivers may modify this default i/o setup */
  7.     status = master->setup(proxy);
  8.     if (status < 0) {
  9.         dev_dbg(dev, "can't %s %s, status %d\n",
  10.                 "setup", proxy->dev.bus_id, status);
  11.         goto fail;
  12.     }
  13.     /* driver core catches callers that misbehave by defining
  14.      * devices that already exist.
  15.      */
  16.     /*看到这句话,大家放心了吧,大家也就知道怎么找到spi_driver驱动的。。。*/
  17.     status = device_register(&proxy->dev);
  18.     if (status < 0) {
  19.         dev_dbg(dev, "can't %s %s, status %d\n",
  20.                 "add", proxy->dev.bus_id, status);
  21.         goto fail;
  22.     }
  23.     dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
  24.     return proxy;
  25. fail:
  26.     spi_master_put(master);
  27.     kfree(proxy);
  28.     return NULL;
  29. }
下面我们要解决最后的一个问题,dataflash的分区的问题,看了这么多,大家应该知道怎么解决了吧!
我们看mtd_dataflash.c文件中驱动加载函数调用了下面这个函数来添加flash设备。。
  1. static int __devinit
  2. add_dataflash(struct spi_device *spi, char *name,
  3.         int nr_pages, int pagesize, int pageoffset)
  4. {
  5.     struct dataflash *priv;
  6.     struct mtd_info *device;
  7.     /*这里就告诉我们要在spi_boardinfo结构体的platform_data成员指向一个我们需要的flash_platform_data数据!*/
  8.     struct flash_platform_data *pdata = spi->dev.platform_data;
  9.     priv = kzalloc(sizeof *priv, GFP_KERNEL);
  10.     if (!priv)
  11.         return -ENOMEM;
  12.     init_MUTEX(&priv->lock);
  13.     priv->spi = spi;
  14.     priv->page_size = pagesize;
  15.     priv->page_offset = pageoffset;
  16.     /* name must be usable with cmdlinepart */
  17.     sprintf(priv->name, "spi%d.%d-%s",
  18.             spi->master->bus_num, spi->chip_select,
  19.             name);
  20.     device = &priv->mtd;
  21.     device->name = (pdata && pdata->name) ? pdata->name : priv->name;
  22.     device->size = nr_pages * pagesize;
  23.     device->erasesize = pagesize;
  24.     device->writesize = pagesize;
  25.     device->owner = THIS_MODULE;
  26.     device->type = MTD_DATAFLASH;
  27.     device->flags = MTD_WRITEABLE;
  28.     device->erase = dataflash_erase;
  29.     device->read = dataflash_read;
  30.     device->write = dataflash_write;
  31.     device->priv = priv;
  32.     dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024);
  33.     dev_set_drvdata(&spi->dev, priv);
  34.     if (mtd_has_partitions()) {
  35.         struct mtd_partition *parts;
  36.         int nr_parts = 0;
  37.     /*我们这里没有定义该宏,所以不会在命令行传递分区表*/
  38. #ifdef CONFIG_MTD_CMDLINE_PARTS
  39.         static const char *part_probes[] = { "cmdlinepart", NULL, };
  40.         nr_parts = parse_mtd_partitions(device, part_probes, &parts, 0);
  41. #endif
  42.         if (nr_parts <= 0 && pdata && pdata->parts) {
  43.             parts = pdata->parts;
  44.             nr_parts = pdata->nr_parts;
  45.         }
  46.         if (nr_parts > 0) {
  47.             priv->partitioned = 1;
  48.             return add_mtd_partitions(device, parts, nr_parts);
  49.         }
  50.     } else if (pdata && pdata->nr_parts)
  51.         dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
  52.                 pdata->nr_parts, device->name);
  53.     return add_mtd_device(device) == 1 ? -ENODEV : 0;
  54. }
所以我们需要修改这个文件:
arch/arm/mach-at91/board-sam9260ek.c文件:
添加如下:
  1. #if !defined(CONFIG_MMC_AT91)
  2. #define SIZE_1PAGE 528
  3. #define SIZE_1M (unsigned long)(1024*1024)
  4. static struct mtd_partition ek_dataflash_partition[] = {
  5.     {
  6.         .name = "U-boot ENV",
  7.         .offset = 0,
  8.         .size = 64*SIZE_1PAGE,
  9.     },
  10.     {
  11.         .name = "U-BOOT",
  12.         .offset = 64*SIZE_1PAGE,
  13.         .size = 400*SIZE_1PAGE,
  14.     },
  15.     {
  16.         .name ="Kernel",
  17.         .offset=464*SIZE_1PAGE,
  18.         .size = 4000*SIZE_1PAGE,
  19.     },
  20.     {
  21.         .name ="Root fs",
  22.         .offset=4464*SIZE_1PAGE,
  23.         .size = (8192-4464)*SIZE_1PAGE,
  24.     },
  25. };

  26. struct flash_platform_data dataflash_atmel={
  27.     .name="AT45DB321",
  28.     .parts=ek_dataflash_partition,
  29.     .nr_parts=ARRAY_SIZE(ek_dataflash_partition),
  30. };
  31. #endif

修改spi_boardinfo结构体:
  1. static struct spi_board_info ek_spi_devices[] = {
  2. #if !defined(CONFIG_MMC_AT91)
  3.     { /* DataFlash chip */
  4.         .modalias = "mtd_dataflash",
  5.         .chip_select = 1,
  6.         .max_speed_hz = 15 * 1000 * 1000,
  7.         .bus_num = 0,
  8.         .platform_data=&dataflash_atmel,
  9.     },
添加platform_data结构成员。

这里我们建立mtd_partition结构体要注意,由于dataflash是以528字节每页的,其实,at45db321x芯片可以设置为512字节每页,这个操作是不可以逆转的,那个位是一个otp位,用过的人就应该知道,但是出厂的时候默认的528字节每页。
如果我们不是以528个字节为单位的话,内核将出警告,强制将分区加载为readonly格式。
到此,分区加载成功,dmesg输出如下信息:
  1. <6>mtd_dataflash spi0.1: AT45DB321x (4224 KBytes)
  2. <5>Creating 4 MTD partitions on "AT45DB321":
  3. <5>0x00000000-0x00008400 : "U-boot ENV"
  4. <5>0x00008400-0x0003bd00 : "U-BOOT"
  5. <5>0x0003bd00-0x0023f700 : "Kernel"
  6. <5>0x0023f700-0x00420000 : "Root fs"
linux简直太伟大了,使用得越多,就越能体会到其思想的伟大!灵活!
 
阅读(734) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~