zoukankan      html  css  js  c++  java
  • SPI驱动程序设计

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


    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    CDH Mysql元数据库升级
    greenplum gpcheckperf 命令(GP集群压力测试)
    centos7 升级openssh到openssh-8.0p1版本(转)
    正则表达式中的 1
    Docker系列03—Docker 基础入门
    Docker系列01—容器的发展历程
    二进制安装部署 4 kubernetes集群---超详细教程
    kubernetes系列11—PV和PVC详解
    kubernetes系列10—存储卷详解
    kubernetes系列09—Ingress控制器详解
  • 原文地址:https://www.cnblogs.com/ch122633/p/7363290.html
Copyright © 2011-2022 走看看