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

📄 mtd_dataflash.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		return len;	spi_message_init(&m);	l = 4 + base + off + len;	scratch = kzalloc(l, GFP_KERNEL);	if (!scratch)		return -ENOMEM;	/* OUT: OP_READ_SECURITY, 3 don't-care bytes, zeroes	 * IN:  ignore 4 bytes, data bytes 0..N (max 127)	 */	scratch[0] = OP_READ_SECURITY;	memset(&t, 0, sizeof t);	t.tx_buf = scratch;	t.rx_buf = scratch;	t.len = l;	spi_message_add_tail(&t, &m);	dataflash_waitready(spi);	status = spi_sync(spi, &m);	if (status >= 0) {		memcpy(buf, scratch + 4 + base + off, len);		status = len;	}	kfree(scratch);	return status;}static int dataflash_read_fact_otp(struct mtd_info *mtd,		loff_t from, size_t len, size_t *retlen, u_char *buf){	struct dataflash	*priv = (struct dataflash *)mtd->priv;	int			status;	/* 64 bytes, from 0..63 ... start at 64 on-chip */	mutex_lock(&priv->lock);	status = otp_read(priv->spi, 64, buf, from, len);	mutex_unlock(&priv->lock);	if (status < 0)		return status;	*retlen = status;	return 0;}static int dataflash_read_user_otp(struct mtd_info *mtd,		loff_t from, size_t len, size_t *retlen, u_char *buf){	struct dataflash	*priv = (struct dataflash *)mtd->priv;	int			status;	/* 64 bytes, from 0..63 ... start at 0 on-chip */	mutex_lock(&priv->lock);	status = otp_read(priv->spi, 0, buf, from, len);	mutex_unlock(&priv->lock);	if (status < 0)		return status;	*retlen = status;	return 0;}static int dataflash_write_user_otp(struct mtd_info *mtd,		loff_t from, size_t len, size_t *retlen, u_char *buf){	struct spi_message	m;	const size_t		l = 4 + 64;	uint8_t			*scratch;	struct spi_transfer	t;	struct dataflash	*priv = (struct dataflash *)mtd->priv;	int			status;	if (len > 64)		return -EINVAL;	/* Strictly speaking, we *could* truncate the write ... but	 * let's not do that for the only write that's ever possible.	 */	if ((from + len) > 64)		return -EINVAL;	/* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes	 * IN:  ignore all	 */	scratch = kzalloc(l, GFP_KERNEL);	if (!scratch)		return -ENOMEM;	scratch[0] = OP_WRITE_SECURITY;	memcpy(scratch + 4 + from, buf, len);	spi_message_init(&m);	memset(&t, 0, sizeof t);	t.tx_buf = scratch;	t.len = l;	spi_message_add_tail(&t, &m);	/* Write the OTP bits, if they've not yet been written.	 * This modifies SRAM buffer1.	 */	mutex_lock(&priv->lock);	dataflash_waitready(priv->spi);	status = spi_sync(priv->spi, &m);	mutex_unlock(&priv->lock);	kfree(scratch);	if (status >= 0) {		status = 0;		*retlen = len;	}	return status;}static char *otp_setup(struct mtd_info *device, char revision){	device->get_fact_prot_info = dataflash_get_otp_info;	device->read_fact_prot_reg = dataflash_read_fact_otp;	device->get_user_prot_info = dataflash_get_otp_info;	device->read_user_prot_reg = dataflash_read_user_otp;	/* rev c parts (at45db321c and at45db1281 only!) use a	 * different write procedure; not (yet?) implemented.	 */	if (revision > 'c')		device->write_user_prot_reg = dataflash_write_user_otp;	return ", OTP";}#elsestatic char *otp_setup(struct mtd_info *device, char revision){	return " (OTP)";}#endif/* ......................................................................... *//* * Register DataFlash device with MTD subsystem. */static int __devinitadd_dataflash_otp(struct spi_device *spi, char *name,		int nr_pages, int pagesize, int pageoffset, char revision){	struct dataflash		*priv;	struct mtd_info			*device;	struct flash_platform_data	*pdata = spi->dev.platform_data;	char				*otp_tag = "";	priv = kzalloc(sizeof *priv, GFP_KERNEL);	if (!priv)		return -ENOMEM;	mutex_init(&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_WRITEABLE;	device->erase = dataflash_erase;	device->read = dataflash_read;	device->write = dataflash_write;	device->priv = priv;	if (revision >= 'c')		otp_tag = otp_setup(device, revision);	dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n",			name, DIV_ROUND_UP(device->size, 1024),			pagesize, otp_tag);	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;}static inline int __devinitadd_dataflash(struct spi_device *spi, char *name,		int nr_pages, int pagesize, int pageoffset){	return add_dataflash_otp(spi, name, nr_pages, pagesize,			pageoffset, 0);}struct flash_info {	char		*name;	/* JEDEC id has a high byte of zero plus three data bytes:	 * the manufacturer id, then a two byte device id.	 */	uint32_t	jedec_id;	/* The size listed here is what works with OP_ERASE_PAGE. */	unsigned	nr_pages;	uint16_t	pagesize;	uint16_t	pageoffset;	uint16_t	flags;#define SUP_POW2PS	0x0002		/* supports 2^N byte pages */#define IS_POW2PS	0x0001		/* uses 2^N byte pages */};static struct flash_info __devinitdata dataflash_data [] = {	/*	 * NOTE:  chips with SUP_POW2PS (rev D and up) need two entries,	 * one with IS_POW2PS and the other without.  The entry with the	 * non-2^N byte page size can't name exact chip revisions without	 * losing backwards compatibility for cmdlinepart.	 *	 * These newer chips also support 128-byte security registers (with	 * 64 bytes one-time-programmable) and software write-protection.	 */	{ "AT45DB011B",  0x1f2200, 512, 264, 9, SUP_POW2PS},	{ "at45db011d",  0x1f2200, 512, 256, 8, SUP_POW2PS | IS_POW2PS},	{ "AT45DB021B",  0x1f2300, 1024, 264, 9, SUP_POW2PS},	{ "at45db021d",  0x1f2300, 1024, 256, 8, SUP_POW2PS | IS_POW2PS},	{ "AT45DB041x",  0x1f2400, 2048, 264, 9, SUP_POW2PS},	{ "at45db041d",  0x1f2400, 2048, 256, 8, SUP_POW2PS | IS_POW2PS},	{ "AT45DB081B",  0x1f2500, 4096, 264, 9, SUP_POW2PS},	{ "at45db081d",  0x1f2500, 4096, 256, 8, SUP_POW2PS | IS_POW2PS},	{ "AT45DB161x",  0x1f2600, 4096, 528, 10, SUP_POW2PS},	{ "at45db161d",  0x1f2600, 4096, 512, 9, SUP_POW2PS | IS_POW2PS},	{ "AT45DB321x",  0x1f2700, 8192, 528, 10, 0},		/* rev C */	{ "AT45DB321x",  0x1f2701, 8192, 528, 10, SUP_POW2PS},	{ "at45db321d",  0x1f2701, 8192, 512, 9, SUP_POW2PS | IS_POW2PS},	{ "AT45DB642x",  0x1f2800, 8192, 1056, 11, SUP_POW2PS},	{ "at45db642d",  0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},};static struct flash_info *__devinit jedec_probe(struct spi_device *spi){	int			tmp;	uint8_t			code = OP_READ_ID;	uint8_t			id[3];	uint32_t		jedec;	struct flash_info	*info;	int status;	/* 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.	 *	 * If the vendor ID isn't Atmel's (0x1f), assume this call failed.	 * That's not an error; only rev C and newer chips handle it, and	 * only Atmel sells these chips.	 */	tmp = spi_write_then_read(spi, &code, 1, id, 3);	if (tmp < 0) {		DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n",			spi->dev.bus_id, tmp);		return ERR_PTR(tmp);	}	if (id[0] != 0x1f)		return NULL;	jedec = id[0];	jedec = jedec << 8;	jedec |= id[1];	jedec = jedec << 8;	jedec |= id[2];	for (tmp = 0, info = dataflash_data;			tmp < ARRAY_SIZE(dataflash_data);			tmp++, info++) {		if (info->jedec_id == jedec) {			DEBUG(MTD_DEBUG_LEVEL1, "%s: OTP, sector protect%s\n",				dev_name(&spi->dev),				(info->flags & SUP_POW2PS)					? ", binary pagesize" : ""				);			if (info->flags & SUP_POW2PS) {				status = dataflash_status(spi);				if (status < 0) {					DEBUG(MTD_DEBUG_LEVEL1,						"%s: status error %d\n",						dev_name(&spi->dev), status);					return ERR_PTR(status);				}				if (status & 0x1) {					if (info->flags & IS_POW2PS)						return info;				} else {					if (!(info->flags & IS_POW2PS))						return info;				}			}		}	}	/*	 * Treat other chips as errors ... we won't know the right page	 * size (it might be binary) even when we can tell which density	 * class is involved (legacy chip id scheme).	 */	dev_warn(&spi->dev, "JEDEC id %06x not handled\n", jedec);	return ERR_PTR(-ENODEV);}/* * Detect and initialize DataFlash device, using JEDEC IDs on newer chips * or else the ID code embedded in the status bits: * *   Device      Density         ID code          #Pages PageSize  Offset *   AT45DB011B  1Mbit   (128K)  xx0011xx (0x0c)    512    264      9 *   AT45DB021B  2Mbit   (256K)  xx0101xx (0x14)   1024    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;	struct flash_info	*info;	/*	 * Try to detect dataflash by JEDEC ID.	 * If it succeeds we know we have either a C or D part.	 * D will support power of 2 pagesize option.	 * Both support the security register, though with different	 * write procedures.	 */	info = jedec_probe(spi);	if (IS_ERR(info))		return PTR_ERR(info);	if (info != NULL)		return add_dataflash_otp(spi, info->name, info->nr_pages,				info->pagesize, info->pageoffset,				(info->flags & SUP_POW2PS) ? 'd' : 'c');	/*	 * Older chips support only legacy commands, identifing	 * capacity using bits in the status byte.	 */	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 == 0 || 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", 1024, 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 + -