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

📄 mtd_dataflash.c

📁 飞思卡尔芯片imx27下的MTD模块的驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		spi->dev.bus_id, (unsigned)to, (unsigned)(to + len));	*retlen = 0;	/* Sanity checks */	if (!len)		return 0;	if ((to + len) > mtd->size)		return -EINVAL;	spi_message_init(&msg);	x[0].tx_buf = command = priv->command;	x[0].len = 4;	spi_message_add_tail(&x[0], &msg);	pageaddr = ((unsigned)to / priv->page_size);	offset = ((unsigned)to % priv->page_size);	if (offset + len > priv->page_size)		writelen = priv->page_size - offset;	else		writelen = len;	down(&priv->lock);	while (remaining > 0) {		DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n",			pageaddr, offset, writelen);		/* REVISIT:		 * (a) each page in a sector must be rewritten at least		 *     once every 10K sibling erase/program operations.		 * (b) for pages that are already erased, we could		 *     use WRITE+MWRITE not PROGRAM for ~30% speedup.		 * (c) WRITE to buffer could be done while waiting for		 *     a previous MWRITE/MWERASE to complete ...		 * (d) error handling here seems to be mostly missing.		 *		 * Two persistent bits per page, plus a per-sector counter,		 * could support (a) and (b) ... we might consider using		 * the second half of sector zero, which is just one block,		 * to track that state.  (On AT91, that sector should also		 * support boot-from-DataFlash.)		 */		addr = pageaddr << priv->page_offset;		/* (1) Maybe transfer partial page to Buffer1 */		if (writelen != priv->page_size) {			command[0] = OP_TRANSFER_BUF1;			command[1] = (addr & 0x00FF0000) >> 16;			command[2] = (addr & 0x0000FF00) >> 8;			command[3] = 0;			DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n",				command[0], command[1], command[2], command[3]);			status = spi_sync(spi, &msg);			if (status < 0)				DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n",					spi->dev.bus_id, addr, status);			(void) dataflash_waitready(priv->spi);		}		/* (2) Program full page via Buffer1 */		addr += offset;		command[0] = OP_PROGRAM_VIA_BUF1;		command[1] = (addr & 0x00FF0000) >> 16;		command[2] = (addr & 0x0000FF00) >> 8;		command[3] = (addr & 0x000000FF);		DEBUG(MTD_DEBUG_LEVEL3, "PROGRAM: (%x) %x %x %x\n",			command[0], command[1], command[2], command[3]);		x[1].tx_buf = writebuf;		x[1].len = writelen;		spi_message_add_tail(x + 1, &msg);		status = spi_sync(spi, &msg);		spi_transfer_del(x + 1);		if (status < 0)			DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n",				spi->dev.bus_id, addr, writelen, status);		(void) dataflash_waitready(priv->spi);#ifdef	CONFIG_DATAFLASH_WRITE_VERIFY		/* (3) Compare to Buffer1 */		addr = pageaddr << priv->page_offset;		command[0] = OP_COMPARE_BUF1;		command[1] = (addr & 0x00FF0000) >> 16;		command[2] = (addr & 0x0000FF00) >> 8;		command[3] = 0;		DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n",			command[0], command[1], command[2], command[3]);		status = spi_sync(spi, &msg);		if (status < 0)			DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n",				spi->dev.bus_id, addr, status);		status = dataflash_waitready(priv->spi);		/* Check result of the compare operation */		if ((status & (1 << 6)) == 1) {			printk(KERN_ERR "%s: compare page %u, err %d\n",				spi->dev.bus_id, pageaddr, status);			remaining = 0;			status = -EIO;			break;		} else			status = 0;#endif	/* CONFIG_DATAFLASH_WRITE_VERIFY */		remaining = remaining - writelen;		pageaddr++;		offset = 0;		writebuf += writelen;		*retlen += writelen;		if (remaining > priv->page_size)			writelen = priv->page_size;		else			writelen = remaining;	}	up(&priv->lock);	return status;}/* ......................................................................... *//* * Register DataFlash device with MTD subsystem. */static int __devinitadd_dataflash(struct spi_device *spi, char *name,		int nr_pages, int pagesize, int pageoffset){	struct dataflash		*priv;	struct mtd_info			*device;	struct flash_platform_data	*pdata = spi->dev.platform_data;	priv = (struct dataflash *) kzalloc(sizeof *priv, GFP_KERNEL);	if (!priv)		return -ENOMEM;	init_MUTEX(&priv->lock);	priv->spi = spi;	priv->page_size = pagesize;	priv->page_offset = pageoffset;	/* name must be usable with cmdlinepart */	sprintf(priv->name, "spi%d.%d-%s",			spi->master->bus_num, spi->chip_select,			name);	device = &priv->mtd;	device->name = (pdata && pdata->name) ? pdata->name : priv->name;	device->size = nr_pages * pagesize;	device->erasesize = pagesize;	device->writesize = pagesize;	device->owner = THIS_MODULE;	device->type = MTD_DATAFLASH;	device->flags = MTD_CAP_NORFLASH;	device->erase = dataflash_erase;	device->read = dataflash_read;	device->write = dataflash_write;	device->priv = priv;	dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024);	dev_set_drvdata(&spi->dev, priv);	if (mtd_has_partitions()) {		struct mtd_partition	*parts;		int			nr_parts = 0;#ifdef CONFIG_MTD_CMDLINE_PARTS		static const char *part_probes[] = { "cmdlinepart", NULL, };		nr_parts = parse_mtd_partitions(device, part_probes, &parts, 0);#endif		if (nr_parts <= 0 && pdata && pdata->parts) {			parts = pdata->parts;			nr_parts = pdata->nr_parts;		}		if (nr_parts > 0) {			priv->partitioned = 1;			return add_mtd_partitions(device, parts, nr_parts);		}	} else if (pdata && pdata->nr_parts)		dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",				pdata->nr_parts, device->name);	return add_mtd_device(device) == 1 ? -ENODEV : 0;}/* * Detect and initialize DataFlash device: * *   Device      Density         ID code          #Pages PageSize  Offset *   AT45DB011B  1Mbit   (128K)  xx0011xx (0x0c)    512    264      9 *   AT45DB021B  2Mbit   (256K)  xx0101xx (0x14)   1025    264      9 *   AT45DB041B  4Mbit   (512K)  xx0111xx (0x1c)   2048    264      9 *   AT45DB081B  8Mbit   (1M)    xx1001xx (0x24)   4096    264      9 *   AT45DB0161B 16Mbit  (2M)    xx1011xx (0x2c)   4096    528     10 *   AT45DB0321B 32Mbit  (4M)    xx1101xx (0x34)   8192    528     10 *   AT45DB0642  64Mbit  (8M)    xx111xxx (0x3c)   8192   1056     11 *   AT45DB1282  128Mbit (16M)   xx0100xx (0x10)  16384   1056     11 */static int __devinit dataflash_probe(struct spi_device *spi){	int status;	status = dataflash_status(spi);	if (status <= 0 || status == 0xff) {		DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n",				spi->dev.bus_id, status);		if (status == 0xff)			status = -ENODEV;		return status;	}	/* if there's a device there, assume it's dataflash.	 * board setup should have set spi->max_speed_max to	 * match f(car) for continuous reads, mode 0 or 3.	 */	switch (status & 0x3c) {	case 0x0c:	/* 0 0 1 1 x x */		status = add_dataflash(spi, "AT45DB011B", 512, 264, 9);		break;	case 0x14:	/* 0 1 0 1 x x */		status = add_dataflash(spi, "AT45DB021B", 1025, 264, 9);		break;	case 0x1c:	/* 0 1 1 1 x x */		status = add_dataflash(spi, "AT45DB041x", 2048, 264, 9);		break;	case 0x24:	/* 1 0 0 1 x x */		status = add_dataflash(spi, "AT45DB081B", 4096, 264, 9);		break;	case 0x2c:	/* 1 0 1 1 x x */		status = add_dataflash(spi, "AT45DB161x", 4096, 528, 10);		break;	case 0x34:	/* 1 1 0 1 x x */		status = add_dataflash(spi, "AT45DB321x", 8192, 528, 10);		break;	case 0x38:	/* 1 1 1 x x x */	case 0x3c:		status = add_dataflash(spi, "AT45DB642x", 8192, 1056, 11);		break;	/* obsolete AT45DB1282 not (yet?) supported */	default:		DEBUG(MTD_DEBUG_LEVEL1, "%s: unsupported device (%x)\n",				spi->dev.bus_id, status & 0x3c);		status = -ENODEV;	}	if (status < 0)		DEBUG(MTD_DEBUG_LEVEL1, "%s: add_dataflash --> %d\n",				spi->dev.bus_id, status);	return status;}static int __devexit dataflash_remove(struct spi_device *spi){	struct dataflash	*flash = dev_get_drvdata(&spi->dev);	int			status;	DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", spi->dev.bus_id);	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 status;}static struct spi_driver dataflash_driver = {	.driver = {		.name		= "mtd_dataflash",		.bus		= &spi_bus_type,		.owner		= THIS_MODULE,	},	.probe		= dataflash_probe,	.remove		= __devexit_p(dataflash_remove),	/* FIXME:  investigate suspend and resume... */};static int __init dataflash_init(void){	return spi_register_driver(&dataflash_driver);}module_init(dataflash_init);static void __exit dataflash_exit(void){	spi_unregister_driver(&dataflash_driver);}module_exit(dataflash_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Andrew Victor, David Brownell");MODULE_DESCRIPTION("MTD DataFlash driver");

⌨️ 快捷键说明

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