Chinaunix首页 | 论坛 | 博客
  • 博客访问: 498712
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-12-16 21:43:51

一、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)。


阅读(673) | 评论(0) | 转发(0) |
0

上一篇:SPI子系统

下一篇:USB总线介绍

给主人留下些什么吧!~~