⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m25p80.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		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);		*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 device driver setup and teardown */struct flash_info {	char		*name;	/* JEDEC id zero means "no ID" (most older chips); otherwise it has	 * a high byte of zero plus three data bytes: the manufacturer id,	 * then a two byte device id.	 */	u32		jedec_id;	u16             ext_id;	/* The size listed here is what works with OPCODE_SE, which isn't	 * necessarily called a "sector" by the vendor.	 */	unsigned	sector_size;	u16		n_sectors;	u16		flags;#define	SECT_4K		0x01		/* OPCODE_BE_4K works uniformly */};/* NOTE: double check command sets and memory organization when you add * more flash chips.  This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. */static struct flash_info __devinitdata m25p_data [] = {	/* Atmel -- some are (confusingly) marketed as "DataFlash" */	{ "at25fs010",  0x1f6601, 0, 32 * 1024, 4, SECT_4K, },	{ "at25fs040",  0x1f6604, 0, 64 * 1024, 8, SECT_4K, },	{ "at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K, },	{ "at25df641",  0x1f4800, 0, 64 * 1024, 128, SECT_4K, },	{ "at26f004",   0x1f0400, 0, 64 * 1024, 8, SECT_4K, },	{ "at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K, },	{ "at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K, },	{ "at26df321",  0x1f4701, 0, 64 * 1024, 64, SECT_4K, },	/* Spansion -- single (large) sector size only, at least	 * for the chips listed here (without boot sectors).	 */	{ "s25sl004a", 0x010212, 0, 64 * 1024, 8, },	{ "s25sl008a", 0x010213, 0, 64 * 1024, 16, },	{ "s25sl016a", 0x010214, 0, 64 * 1024, 32, },	{ "s25sl032a", 0x010215, 0, 64 * 1024, 64, },	{ "s25sl064a", 0x010216, 0, 64 * 1024, 128, },        { "s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, },	{ "s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, },	/* SST -- large erase sizes are "overlays", "sectors" are 4K */	{ "sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K, },	{ "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K, },	{ "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K, },	{ "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K, },	/* ST Microelectronics -- newer production may have feature updates */	{ "m25p05",  0x202010,  0, 32 * 1024, 2, },	{ "m25p10",  0x202011,  0, 32 * 1024, 4, },	{ "m25p20",  0x202012,  0, 64 * 1024, 4, },	{ "m25p40",  0x202013,  0, 64 * 1024, 8, },	{ "m25p80",         0,  0, 64 * 1024, 16, },	{ "m25p16",  0x202015,  0, 64 * 1024, 32, },	{ "m25p32",  0x202016,  0, 64 * 1024, 64, },	{ "m25p64",  0x202017,  0, 64 * 1024, 128, },	{ "m25p128", 0x202018, 0, 256 * 1024, 64, },	{ "m45pe80", 0x204014,  0, 64 * 1024, 16, },	{ "m45pe16", 0x204015,  0, 64 * 1024, 32, },	{ "m25pe80", 0x208014,  0, 64 * 1024, 16, },	{ "m25pe16", 0x208015,  0, 64 * 1024, 32, SECT_4K, },	/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */	{ "w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K, },	{ "w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K, },	{ "w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K, },	{ "w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K, },	{ "w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K, },	{ "w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K, },	{ "w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K, },};static struct flash_info *__devinit jedec_probe(struct spi_device *spi){	int			tmp;	u8			code = OPCODE_RDID;	u8			id[5];	u32			jedec;	u16                     ext_jedec;	struct flash_info	*info;	/* JEDEC also defines an optional "extended device information"	 * string for after vendor-specific data, after the three bytes	 * we use here.  Supporting some chips might require using it.	 */	tmp = spi_write_then_read(spi, &code, 1, id, 5);	if (tmp < 0) {		DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n",			spi->dev.bus_id, tmp);		return NULL;	}	jedec = id[0];	jedec = jedec << 8;	jedec |= id[1];	jedec = jedec << 8;	jedec |= id[2];	ext_jedec = id[3] << 8 | id[4];	for (tmp = 0, info = m25p_data;			tmp < ARRAY_SIZE(m25p_data);			tmp++, info++) {		if (info->jedec_id == jedec) {			if (info->ext_id != 0 && info->ext_id != ext_jedec)				continue;			return info;		}	}	dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);	return NULL;}/* * board specific setup should have ensured the SPI clock used here * matches what the READ command supports, at least until this driver * understands FAST_READ (for clocks over 25 MHz). */static int __devinit m25p_probe(struct spi_device *spi){	struct flash_platform_data	*data;	struct m25p			*flash;	struct flash_info		*info;	unsigned			i;	/* Platform data helps sort out which chip type we have, as	 * well as how this board partitions it.  If we don't have	 * a chip ID, try the JEDEC id commands; they'll work for most	 * newer chips, even if we don't recognize the particular chip.	 */	data = spi->dev.platform_data;	if (data && data->type) {		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",					spi->dev.bus_id, 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 = spi->dev.bus_id;	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;	}	dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name,			flash->mtd.size / 1024);	DEBUG(MTD_DEBUG_LEVEL2,		"mtd .name = %s, .size = 0x%.8x (%uMiB) "			".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",		flash->mtd.name,		flash->mtd.size, flash->mtd.size / (1024*1024),		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%.8x, "				".erasesize = 0x%.8x (%uKiB), "				".numblocks = %d }\n",				i, 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;#ifdef CONFIG_MTD_CMDLINE_PARTS		static const char *part_probes[] = { "cmdlinepart", NULL, };		nr_parts = parse_mtd_partitions(&flash->mtd,				part_probes, &parts, 0);#endif		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%.8x, "						".size = 0x%.8x (%uKiB) }\n",					i, parts[i].name,					parts[i].offset,					parts[i].size,					parts[i].size / 1024);			}			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;}static int __devexit m25p_remove(struct spi_device *spi){	struct m25p	*flash = dev_get_drvdata(&spi->dev);	int		status;	/* Clean up MTD stuff. */	if (mtd_has_partitions() && flash->partitioned)		status = del_mtd_partitions(&flash->mtd);	else		status = del_mtd_device(&flash->mtd);	if (status == 0)		kfree(flash);	return 0;}static struct spi_driver m25p80_driver = {	.driver = {		.name	= "m25p80",		.bus	= &spi_bus_type,		.owner	= THIS_MODULE,	},	.probe	= m25p_probe,	.remove	= __devexit_p(m25p_remove),	/* REVISIT: many of these chips have deep power-down modes, which	 * should clearly be entered on suspend() to minimize power use.	 * And also when they're otherwise idle...	 */};static int m25p80_init(void){	return spi_register_driver(&m25p80_driver);}static void m25p80_exit(void){	spi_unregister_driver(&m25p80_driver);}module_init(m25p80_init);module_exit(m25p80_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Mike Lavender");MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -