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
",
-
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
",
-
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)
", 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
",
-
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 }
",
-
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) }
",
-
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
",
-
data->nr_parts, data->name);
-
-
return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
- }
- 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
",
-
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)。