一、SPI驱动子系统架构

m25p80.c:

  1. static int __devinit m25p_probe(struct spi_device *spi)
  2. {
  3. struct flash_platform_data    *data;
  4. struct m25p            *flash;
  5. struct flash_info        *info;
  6. unsigned            i;
  7. data = spi->dev.platform_data;
  8. if (data && data->type) {                                       //配对设备,在m25p_data中找是否有对应的ID
  9. for (i = 0, info = m25p_data;
  10. i < ARRAY_SIZE(m25p_data);
  11. i++, info++) {
  12. if (strcmp(data->type, info->name) == 0)
  13. break;
  14. }
  15. /* unrecognized chip? */                                   //芯片没有被认出
  16. if (i == ARRAY_SIZE(m25p_data)) {
  17. DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
  18. dev_name(&spi->dev), data->type);
  19. info = NULL;
  20. /* recognized; is that chip really what's there? */                //找到芯片
  21. } else if (info->jedec_id) {
  22. struct flash_info    *chip = jedec_probe(spi);
  23. if (!chip || chip != info) {
  24. dev_warn(&spi->dev, "found %s, expected %s\n",
  25. chip ? chip->name : "UNKNOWN",
  26. info->name);
  27. info = NULL;
  28. }
  29. }
  30. } else
  31. info = jedec_probe(spi);
  32. if (!info)
  33. return -ENODEV;
  34. flash = kzalloc(sizeof *flash, GFP_KERNEL);                                    //分配空间
  35. if (!flash)
  36. return -ENOMEM;
  37. flash->spi = spi;
  38. mutex_init(&flash->lock);
  39. dev_set_drvdata(&spi->dev, flash);
  40. /*
  41. * Atmel serial flash tend to power up
  42. * with the software protection bits set
  43. */
  44. if (info->jedec_id >> 16 == 0x1f) {
  45. write_enable(flash);
  46. write_sr(flash, 0);
  47. }
  48. if (data && data->name)
  49. flash->mtd.name = data->name;
  50. else
  51. flash->mtd.name = dev_name(&spi->dev);
  52. flash->mtd.type = MTD_NORFLASH;                                                  //初始化操作集
  53. flash->mtd.writesize = 1;
  54. flash->mtd.flags = MTD_CAP_NORFLASH;
  55. flash->mtd.size = info->sector_size * info->n_sectors;
  56. flash->mtd.erase = m25p80_erase;
  57. flash->mtd.read = m25p80_read;
  58. flash->mtd.write = m25p80_write;
  59. /* prefer "small sector" erase if possible */
  60. if (info->flags & SECT_4K) {
  61. flash->erase_opcode = OPCODE_BE_4K;
  62. flash->mtd.erasesize = 4096;
  63. } else {
  64. flash->erase_opcode = OPCODE_SE;
  65. flash->mtd.erasesize = info->sector_size;
  66. }
  67. flash->mtd.dev.parent = &spi->dev;
  68. dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name,
  69. (long long)flash->mtd.size >> 10);
  70. DEBUG(MTD_DEBUG_LEVEL2,
  71. "mtd .name = %s, .size = 0x%llx (%lldMiB) "
  72. ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
  73. flash->mtd.name,
  74. (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
  75. flash->mtd.erasesize, flash->mtd.erasesize / 1024,
  76. flash->mtd.numeraseregions);
  77. if (flash->mtd.numeraseregions)
  78. for (i = 0; i < flash->mtd.numeraseregions; i++)
  79. DEBUG(MTD_DEBUG_LEVEL2,
  80. "mtd.eraseregions[%d] = { .offset = 0x%llx, "
  81. ".erasesize = 0x%.8x (%uKiB), "
  82. ".numblocks = %d }\n",
  83. i, (long long)flash->mtd.eraseregions[i].offset,
  84. flash->mtd.eraseregions[i].erasesize,
  85. flash->mtd.eraseregions[i].erasesize / 1024,
  86. flash->mtd.eraseregions[i].numblocks);
  87. /* partitions should match sector boundaries; and it may be good to
  88. * use readonly partitions for writeprotected sectors (BP2..BP0).
  89. */
  90. if (mtd_has_partitions()) {
  91. struct mtd_partition    *parts = NULL;
  92. int            nr_parts = 0;
  93. if (mtd_has_cmdlinepart()) {
  94. static const char *part_probes[]
  95. = { "cmdlinepart", NULL, };
  96. nr_parts = parse_mtd_partitions(&flash->mtd,
  97. part_probes, &parts, 0);
  98. }
  99. if (nr_parts <= 0 && data && data->parts) {
  100. parts = data->parts;
  101. nr_parts = data->nr_parts;
  102. }
  103. if (nr_parts > 0) {
  104. for (i = 0; i < nr_parts; i++) {
  105. DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
  106. "{.name = %s, .offset = 0x%llx, "
  107. ".size = 0x%llx (%lldKiB) }\n",
  108. i, parts[i].name,
  109. (long long)parts[i].offset,
  110. (long long)parts[i].size,
  111. (long long)(parts[i].size >> 10));
  112. }
  113. flash->partitioned = 1;
  114. return add_mtd_partitions(&flash->mtd, parts, nr_parts);
  115. }
  116. } else if (data->nr_parts)
  117. dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
  118. data->nr_parts, data->name);
  119. return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
  120. }

m25p_write:

  1. static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
  2. size_t *retlen, const u_char *buf)
  3. {
  4. struct m25p *flash = mtd_to_m25p(mtd);
  5. u32 page_offset, page_size;
  6. struct spi_transfer t[2];                                                  //重要结构,一次发送
  7. struct spi_message m;                                                      //重要结构,消息结构
  8. DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
  9. dev_name(&flash->spi->dev), __func__, "to",
  10. (u32)to, len);
  11. if (retlen)
  12. *retlen = 0;
  13. /* sanity checks */
  14. if (!len)
  15. return(0);
  16. if (to + len > flash->mtd.size)
  17. return -EINVAL;
  18. spi_message_init(&m);                                                  //这边进行了初始化
  19. memset(t, 0, (sizeof t));                                              //清空
  20. t[0].tx_buf = flash->command;
  21. t[0].len = CMD_SIZE;
  22. spi_message_add_tail(&t[0], &m);                                       //把数据挂汲取
  23. t[1].tx_buf = buf;
  24. spi_message_add_tail(&t[1], &m);
  25. mutex_lock(&flash->lock);
  26. /* Wait until finished previous write command. */
  27. if (wait_till_ready(flash)) {
  28. mutex_unlock(&flash->lock);
  29. return 1;
  30. }
  31. write_enable(flash);
  32. /* Set up the opcode in the write buffer. */                            //数据发送
  33. flash->command[0] = OPCODE_PP;
  34. flash->command[1] = to >> 16;
  35. flash->command[2] = to >> 8;
  36. flash->command[3] = to;
  37. /* what page do we start with? */
  38. page_offset = to % FLASH_PAGESIZE;
  39. /* do all the bytes fit onto one page? */
  40. if (page_offset + len <= FLASH_PAGESIZE) {
  41. t[1].len = len;
  42. spi_sync(flash->spi, &m);                                            //把message提交给控制器
  43. *retlen = m.actual_length - CMD_SIZE;
  44. } else {
  45. u32 i;
  46. /* the size of data remaining on the first page */
  47. page_size = FLASH_PAGESIZE - page_offset;
  48. t[1].len = page_size;
  49. spi_sync(flash->spi, &m);
  50. *retlen = m.actual_length - CMD_SIZE;
  51. /* write everything in PAGESIZE chunks */
  52. for (i = page_size; i < len; i += page_size) {
  53. page_size = len - i;
  54. if (page_size > FLASH_PAGESIZE)
  55. page_size = FLASH_PAGESIZE;
  56. /* write the next page to flash */
  57. flash->command[1] = (to + i) >> 16;
  58. flash->command[2] = (to + i) >> 8;
  59. flash->command[3] = (to + i);
  60. t[1].tx_buf = buf + i;
  61. t[1].len = page_size;
  62. wait_till_ready(flash);
  63. write_enable(flash);
  64. spi_sync(flash->spi, &m);
  65. if (retlen)
  66. *retlen += m.actual_length - CMD_SIZE;
  67. }
  68. }
  69. mutex_unlock(&flash->lock);
  70. return 0;
  71. }



spi_master是SPI控制器,其中的queue把spi_message串成链表。这是一次SPI事务,而一个事务又分成一个一个的读写发送操作(spi_transfer)。



SPI驱动程序设计的更多相关文章

  1. [国嵌攻略][160][SPI驱动程序设计]

    SPI Flash驱动 1.打开/drivers/mtd/devices/m25p80.c驱动文件.找到初始化m25p80_init函数,其中通过spi_register_driver来注册spi设备 ...

  2. 基于μC/OS—III的CC1120驱动程序设计

    基于μC/OS—III的CC1120驱动程序设计 时间:2014-01-21 来源:电子设计工程 作者:张绍游,张贻雄,石江宏 关键字:CC1120   嵌入式操作系统   STM32F103ZE   ...

  3. 基于TQ2440的SPI驱动学习(OLED)

    平台简介 开发板:TQ2440 (NandFlash:256M  内存:64M) u-boot版本:u-boot-2015.04 内核版本:Linux-3.14 作者:彭东林 邮箱:pengdongl ...

  4. SPI 驱动分析

    断更博客两个月后我又回来了,眯着躺倒就能睡熟的小眼睛,在这儿敲键盘.这篇文章给你快乐,你有没有爱上我! SPI驱动由三部分组成,分别为drivers.core.device.通过bus总线连接.困了不 ...

  5. 20145316&20145229实验四:驱动程序设计

    20145316&20145229实验四:驱动程序设计 结对伙伴:20145316 许心远 博客链接:http://www.cnblogs.com/xxy745214935/p/6130871 ...

  6. linux驱动程序设计的硬件基础,王明学learn

    linux驱动程序设计的硬件基础(一) 本章讲总结学习linux设备程序设计的硬件基础. 一.处理器 1.1通用处理器 通用处理器(GPP)并不针对特定的应用领域进行体系结构和指令集的优化,它们具有一 ...

  7. 信息安全系统设计基础实验四:外设驱动程序设计 20135211李行之&20135216刘蔚然

    北京电子科技学院(BESTI) 实 验 报 告 封面 课程:信息安全系统设计基础                                           班级:1352           ...

  8. 2017-2018-1 20155214&20155216 实验四:外设驱动程序设计

    2017-2018-1 20155214&20155216 实验四:外设驱动程序设计 实验四外设驱动程序设计-1 实验要求: 学习资源中全课中的"hqyj.嵌入式Linux应用程序开 ...

  9. Linux Spi驱动移植小结

    2012-01-07 22:21:29 效果图: 理论学习后,主要是linux中spi子系统设备框架的了解后,主控制器与设备分离的思想,那么我要开始动手了. 1,  make menuconfig添加 ...

随机推荐

  1. Java序列化及反序列化

    序列化概念: 1.Java序列化与反序列化  Java序列化是指把Java对象转换为字节序列的过程:而Java反序列化是指把字节序列恢复为Java对象的过程. 2.为什么需要序列化与反序列化 我们知道 ...

  2. SpringMvc中乱码问题的解决

    一:如果是前台传递的数据有问题. 在tomcat的service.xml中加上: URIEncoding="UTF-8" <Connector URIEncoding=&qu ...

  3. SpringMvc的过滤器。

    一:过滤器的原理: 过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet.一个Jsp页面,甚至是一个HTML页面)之前截获进入的请求,并且在它返回到客户之前截获输出请 ...

  4. php min()函数 语法

    php min()函数 语法 作用:从所有参数中找到最小数 语法:min(X,Y,Z) 或者min(array(X,Y,Z)) 参数:min函数中参数至少一个,可以多个参数,也可以是数组. 说明:如果 ...

  5. [Repost] 常用素数

    作者:Miskcoo(http://blog.miskcoo.com/2014/07/fft-prime-table) 如果 \(r\cdot 2^k+1\) 是个素数, 那么在 \(\bmod r\ ...

  6. CSS定位,转载的

    转自:http://www.cnblogs.com/jiqing9006/archive/2012/07/26/2610586.html 层级关系为:<div ——————————— posit ...

  7. Visual Studio Code-调试Node.js代码

    打开js文件 F0下断点 F5调试 PS:配置了launch.json会默认执行调试配置的js

  8. git私有仓库提交代码

    #首次提交 #克隆版本库到本地 git clone http://192.168.3.107:9002/develop/zhong.git cd zhong #创建忽略文件(忽略文件自行编辑) tou ...

  9. 禁止修改input内容

    有什么问题请到<a href='/bbs/index.asp?boardid=2'>论坛</a>中发表<br> <!--# 特效来源:http://www.o ...

  10. haskell目录层次

    daniel@daniel-mint /usr/lib/ghc/haskell2010-1.1.1.0 $ tree . ├── Control │   └── Monad.hi ├── Data │ ...