SPI驱动程序设计
一、SPI驱动子系统架构
m25p80.c:
- static int __devinit m25p_probe(struct spi_device *spi)
- {
- struct flash_platform_data *data;
- struct m25p *flash;
- struct flash_info *info;
- unsigned i;
- data = spi->dev.platform_data;
- if (data && data->type) { //配对设备,在m25p_data中找是否有对应的ID
- for (i = 0, info = m25p_data;
- i < ARRAY_SIZE(m25p_data);
- i++, info++) {
- if (strcmp(data->type, info->name) == 0)
- break;
- }
- /* unrecognized chip? */ //芯片没有被认出
- if (i == ARRAY_SIZE(m25p_data)) {
- DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
- dev_name(&spi->dev), data->type);
- info = NULL;
- /* recognized; is that chip really what's there? */ //找到芯片
- } else if (info->jedec_id) {
- struct flash_info *chip = jedec_probe(spi);
- if (!chip || chip != info) {
- dev_warn(&spi->dev, "found %s, expected %s\n",
- chip ? chip->name : "UNKNOWN",
- info->name);
- info = NULL;
- }
- }
- } else
- info = jedec_probe(spi);
- if (!info)
- return -ENODEV;
- flash = kzalloc(sizeof *flash, GFP_KERNEL); //分配空间
- if (!flash)
- return -ENOMEM;
- flash->spi = spi;
- mutex_init(&flash->lock);
- dev_set_drvdata(&spi->dev, flash);
- /*
- * Atmel serial flash tend to power up
- * with the software protection bits set
- */
- if (info->jedec_id >> 16 == 0x1f) {
- write_enable(flash);
- write_sr(flash, 0);
- }
- if (data && data->name)
- flash->mtd.name = data->name;
- else
- flash->mtd.name = dev_name(&spi->dev);
- flash->mtd.type = MTD_NORFLASH; //初始化操作集
- flash->mtd.writesize = 1;
- flash->mtd.flags = MTD_CAP_NORFLASH;
- flash->mtd.size = info->sector_size * info->n_sectors;
- flash->mtd.erase = m25p80_erase;
- flash->mtd.read = m25p80_read;
- flash->mtd.write = m25p80_write;
- /* prefer "small sector" erase if possible */
- if (info->flags & SECT_4K) {
- flash->erase_opcode = OPCODE_BE_4K;
- flash->mtd.erasesize = 4096;
- } else {
- flash->erase_opcode = OPCODE_SE;
- flash->mtd.erasesize = info->sector_size;
- }
- flash->mtd.dev.parent = &spi->dev;
- dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name,
- (long long)flash->mtd.size >> 10);
- DEBUG(MTD_DEBUG_LEVEL2,
- "mtd .name = %s, .size = 0x%llx (%lldMiB) "
- ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
- flash->mtd.name,
- (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
- flash->mtd.erasesize, flash->mtd.erasesize / 1024,
- flash->mtd.numeraseregions);
- if (flash->mtd.numeraseregions)
- for (i = 0; i < flash->mtd.numeraseregions; i++)
- DEBUG(MTD_DEBUG_LEVEL2,
- "mtd.eraseregions[%d] = { .offset = 0x%llx, "
- ".erasesize = 0x%.8x (%uKiB), "
- ".numblocks = %d }\n",
- i, (long long)flash->mtd.eraseregions[i].offset,
- flash->mtd.eraseregions[i].erasesize,
- flash->mtd.eraseregions[i].erasesize / 1024,
- flash->mtd.eraseregions[i].numblocks);
- /* partitions should match sector boundaries; and it may be good to
- * use readonly partitions for writeprotected sectors (BP2..BP0).
- */
- if (mtd_has_partitions()) {
- struct mtd_partition *parts = NULL;
- int nr_parts = 0;
- if (mtd_has_cmdlinepart()) {
- static const char *part_probes[]
- = { "cmdlinepart", NULL, };
- nr_parts = parse_mtd_partitions(&flash->mtd,
- part_probes, &parts, 0);
- }
- if (nr_parts <= 0 && data && data->parts) {
- parts = data->parts;
- nr_parts = data->nr_parts;
- }
- if (nr_parts > 0) {
- for (i = 0; i < nr_parts; i++) {
- DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
- "{.name = %s, .offset = 0x%llx, "
- ".size = 0x%llx (%lldKiB) }\n",
- i, parts[i].name,
- (long long)parts[i].offset,
- (long long)parts[i].size,
- (long long)(parts[i].size >> 10));
- }
- flash->partitioned = 1;
- return add_mtd_partitions(&flash->mtd, parts, nr_parts);
- }
- } else if (data->nr_parts)
- dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
- data->nr_parts, data->name);
- return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
- }
m25p_write:
- static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
- {
- struct m25p *flash = mtd_to_m25p(mtd);
- u32 page_offset, page_size;
- struct spi_transfer t[2]; //重要结构,一次发送
- struct spi_message m; //重要结构,消息结构
- DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
- dev_name(&flash->spi->dev), __func__, "to",
- (u32)to, len);
- if (retlen)
- *retlen = 0;
- /* sanity checks */
- if (!len)
- return(0);
- if (to + len > flash->mtd.size)
- return -EINVAL;
- spi_message_init(&m); //这边进行了初始化
- memset(t, 0, (sizeof t)); //清空
- t[0].tx_buf = flash->command;
- t[0].len = CMD_SIZE;
- spi_message_add_tail(&t[0], &m); //把数据挂汲取
- t[1].tx_buf = buf;
- spi_message_add_tail(&t[1], &m);
- mutex_lock(&flash->lock);
- /* Wait until finished previous write command. */
- if (wait_till_ready(flash)) {
- mutex_unlock(&flash->lock);
- return 1;
- }
- write_enable(flash);
- /* Set up the opcode in the write buffer. */ //数据发送
- flash->command[0] = OPCODE_PP;
- flash->command[1] = to >> 16;
- flash->command[2] = to >> 8;
- flash->command[3] = to;
- /* what page do we start with? */
- page_offset = to % FLASH_PAGESIZE;
- /* do all the bytes fit onto one page? */
- if (page_offset + len <= FLASH_PAGESIZE) {
- t[1].len = len;
- spi_sync(flash->spi, &m); //把message提交给控制器
- *retlen = m.actual_length - CMD_SIZE;
- } else {
- u32 i;
- /* the size of data remaining on the first page */
- page_size = FLASH_PAGESIZE - page_offset;
- t[1].len = page_size;
- spi_sync(flash->spi, &m);
- *retlen = m.actual_length - CMD_SIZE;
- /* write everything in PAGESIZE chunks */
- for (i = page_size; i < len; i += page_size) {
- page_size = len - i;
- if (page_size > FLASH_PAGESIZE)
- page_size = FLASH_PAGESIZE;
- /* write the next page to flash */
- flash->command[1] = (to + i) >> 16;
- flash->command[2] = (to + i) >> 8;
- flash->command[3] = (to + i);
- t[1].tx_buf = buf + i;
- t[1].len = page_size;
- wait_till_ready(flash);
- write_enable(flash);
- spi_sync(flash->spi, &m);
- if (retlen)
- *retlen += m.actual_length - CMD_SIZE;
- }
- }
- mutex_unlock(&flash->lock);
- return 0;
- }

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

SPI驱动程序设计的更多相关文章
- [国嵌攻略][160][SPI驱动程序设计]
SPI Flash驱动 1.打开/drivers/mtd/devices/m25p80.c驱动文件.找到初始化m25p80_init函数,其中通过spi_register_driver来注册spi设备 ...
- 基于μC/OS—III的CC1120驱动程序设计
基于μC/OS—III的CC1120驱动程序设计 时间:2014-01-21 来源:电子设计工程 作者:张绍游,张贻雄,石江宏 关键字:CC1120 嵌入式操作系统 STM32F103ZE ...
- 基于TQ2440的SPI驱动学习(OLED)
平台简介 开发板:TQ2440 (NandFlash:256M 内存:64M) u-boot版本:u-boot-2015.04 内核版本:Linux-3.14 作者:彭东林 邮箱:pengdongl ...
- SPI 驱动分析
断更博客两个月后我又回来了,眯着躺倒就能睡熟的小眼睛,在这儿敲键盘.这篇文章给你快乐,你有没有爱上我! SPI驱动由三部分组成,分别为drivers.core.device.通过bus总线连接.困了不 ...
- 20145316&20145229实验四:驱动程序设计
20145316&20145229实验四:驱动程序设计 结对伙伴:20145316 许心远 博客链接:http://www.cnblogs.com/xxy745214935/p/6130871 ...
- linux驱动程序设计的硬件基础,王明学learn
linux驱动程序设计的硬件基础(一) 本章讲总结学习linux设备程序设计的硬件基础. 一.处理器 1.1通用处理器 通用处理器(GPP)并不针对特定的应用领域进行体系结构和指令集的优化,它们具有一 ...
- 信息安全系统设计基础实验四:外设驱动程序设计 20135211李行之&20135216刘蔚然
北京电子科技学院(BESTI) 实 验 报 告 封面 课程:信息安全系统设计基础 班级:1352 ...
- 2017-2018-1 20155214&20155216 实验四:外设驱动程序设计
2017-2018-1 20155214&20155216 实验四:外设驱动程序设计 实验四外设驱动程序设计-1 实验要求: 学习资源中全课中的"hqyj.嵌入式Linux应用程序开 ...
- Linux Spi驱动移植小结
2012-01-07 22:21:29 效果图: 理论学习后,主要是linux中spi子系统设备框架的了解后,主控制器与设备分离的思想,那么我要开始动手了. 1, make menuconfig添加 ...
随机推荐
- 线性规划(Simplex单纯形)与对偶问题
线性规划 首先一般所有的线性规划问题我们都可以转换成如下标准型: 但是我们可以发现上面都是不等式,而我们计算中更希望是等式,所以我们引入这个新的概念:松弛型: 很显然我们最后要求是所有的约束左边的变量 ...
- c#蜘蛛
C#写一个采集器 using System; using System.Collections.Generic; using System.Text; using System.Net; using ...
- Http协议面试题(总结)
Http协议面试题(总结) 一.总结 一句话总结: 主要考常见的状态码,以及https,其它的多抓抓包就熟悉了 1.说一下什么是Http协议? 数据传输的格式规范:对器客户端和 服务器端之间数据传输的 ...
- 杂项-报表-Minitab:Minitab百科
ylbtech-杂项-报表-Minitab:Minitab百科 Minitab软件是现代质量管理统计的领先者,全球六西格玛实施的共同语言,以无可比拟的强大功能和简易的可视化操作深受广大质量学者和统计专 ...
- Java 反射简介(转载)
反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java ...
- 微众银行c++选择题后记
一个类的成员可以有:另一个类的对象,类的自身指针,自身类对象的引用(私有的如何初始化呢,所以不行,换成静态的可以),自身类对象(构造时如何初始化呢?) class A{ public: A(){} A ...
- js 使用技巧
一,获取客户端状态 1.获取cookie function cookieInfo() { setcookie('cookie_test','1'); var cookie_test = getcook ...
- 在线常用库 + API手册
以下链接经过本人测试,均可正常访问 jQuery: http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js bootsrap: http://app ...
- HTML设置span宽度
CSS中的 width 属性并不总是有效的如果对象是 inline 对象,width 属性就会被忽略,Firefox 和 IE 是遵循CSS标准,因而直接设置span宽度会无效. 解决:span { ...
- ---搭建springMvc框架,希望对初学者有所参考
Spring Mvc ==> Struts2 spring 无法替代 myBatis 工作量大 要自己操作sql语句 ==> hibernate Spring Mvc 取代St ...