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

📄 omap-nor-flash.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
		       module_name, offset);		return -EPERM;	}	if ((status & (3 << 4)) == (3 << 4)) {		printk(KERN_ERR		       "%s ERROR: erasing at address 0x%.8x: command sequence error\n",		       module_name, offset);		return -EPERM;	}	if (status & (1 << 5)) {		printk(KERN_ERR		       "%s ERROR: erasing at address 0x%.8x: block erase error\n",		       module_name, offset);		return -ETIMEDOUT;	}	if (status & (1 << 1)) {		printk(KERN_ERR		       "%s ERROR: erasing at address 0x%.8x: block locked error\n",		       module_name, offset);		return -EPERM;	}	return 0;}/* Pick the proper sector addresses for erasing */static intomap_flash_erase(struct mtd_info *mtd, struct erase_info *instr){	__u32 addr, len;	int i, first;	/* sanity checks */	if (instr->addr + instr->len > mtd->size)		return (-EINVAL);	/*	 * check that both start and end of the requested erase are	 * aligned with the erasesize at the appropriate addresses.	 *	 * skip all erase regions which are ended before the start of	 * the requested erase. Actually, to save on the calculations,	 * we skip to the first erase region which starts after the	 * start of the requested erase, and then go back one.	 */	for (i = 0; (i < mtd->numeraseregions) &&	     (instr->addr >= mtd->eraseregions[i].offset); i++) ;	i--;	/*	 * ok, now i is pointing at the erase region in which this	 * erase request starts. Check the start of the requested	 * erase range is aligned with the erase size which is in	 * effect here.	 */	if (instr->addr & (mtd->eraseregions[i].erasesize - 1))		return (-EINVAL);	/* Remember the erase region we start on */	first = i;	/*	 * next, check that the end of the requested erase is aligned	 * with the erase region at that address.	 *	 * as before, drop back one to point at the region in which	 * the address actually falls	 */	for (;	     (i < mtd->numeraseregions) &&	     ((instr->addr + instr->len) >= mtd->eraseregions[i].offset); i++) ;	i--;	/* is the end aligned on a block boundary? */	if ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1))		return (-EINVAL);	addr = instr->addr;	len = instr->len;	i = first;	/* now erase those blocks */	while (len) {		if (omap_flash_sector_erase(addr)) {			instr->state = MTD_ERASE_FAILED;			return (-EIO);		}		addr += mtd->eraseregions[i].erasesize;		len -= mtd->eraseregions[i].erasesize;		if (addr == (mtd->eraseregions[i].offset +			     (mtd->eraseregions[i].erasesize *			      mtd->eraseregions[i].numblocks)))			i++;	}	instr->state = MTD_ERASE_DONE;	if (instr->callback)		instr->callback(instr);	return (0);}/* Read a block of data from flash */static intomap_flash_read(struct mtd_info *mtd, loff_t from,		    size_t len, size_t * retlen, u_char * buf){	/* Sanity checks. */	if (!len)		return (0);	if (from + len > mtd->size)		return (-EINVAL);	/* We always read len bytes. */	*retlen = len;	down(&omap_flash_lock);	memcpy(buf, (void *) (omap_nor_flash_base + (__u32) from), len);	up(&omap_flash_lock);	return (0);}/* Write a flash word. The offset must be on a word boudary */static intomap_flash_write_word(__u32 offset, __u16 x){	__u16 status;	down(&omap_flash_lock);	/* Check if Flash is (sufficiently) erased */	if ((omap_flash_inw(offset) & x) != x) {		printk(KERN_ERR		       "%s ERROR: cannot write, flash not erased at address 0x%.8x.\n",		       module_name, offset);		up(&omap_flash_lock);		return -EIO;	/*flash not erased */	}	omap_flash_outw(offset, 0x0050);	/* clear status register */	omap_flash_outw(offset, 0x0040);	/* write setup */	omap_flash_outw(offset, x);	/* wait for program complete while polling the status register */	while (((status = omap_flash_inw(offset)) & 0x0080) != 0x0080)		schedule_timeout(1);	omap_flash_outw(offset, 0x0050);	/* clear status register */	omap_flash_outw(offset, 0x00FF);	/* restore read mode */	up(&omap_flash_lock);	/* process status register */	if (status & (1 << 3)) {		printk(KERN_ERR		       "%s ERROR: writing at address 0x%.8x: Vpp range error \n",		       module_name, offset);		return -EPERM;	}	if (status & (1 << 4)) {		printk(KERN_ERR		       "%s ERROR: writing at address 0x%.8x: program error \n",		       module_name, offset);		return -ETIMEDOUT;	}	if (status & (1 << 1)) {		printk(KERN_ERR		       "%s ERROR: writing at address 0x%.8x: device protect error\n",		       module_name, offset);		return -EPERM;	}	return 0;}/* Write a block of data to flash. Takes care of the word boundaries */static intomap_flash_write(struct mtd_info *mtd, loff_t to, size_t len,		     size_t * retlen, const u_char * buf){	__u8 tmp[BUSWIDTH];	int i, n;	*retlen = 0;	/* Sanity checks */	if (!len)		return (0);	if (to + len > mtd->size)		return (-EINVAL);	/* First, we write a byte padded with original data until we reach a	 * word boundary. */	if (to & (BUSWIDTH - 1)) {		__u32 aligned = to & ~(BUSWIDTH - 1);		i = to - aligned;		n = 0;		down(&omap_flash_lock);		*((__u16 *) tmp) = omap_flash_inw(aligned);		up(&omap_flash_lock);		while (len && i < BUSWIDTH)			tmp[i++] = buf[n++], len--;		if (omap_flash_write_word(aligned, *((__u16 *) tmp)))			return (-EIO);		to += n;		buf += n;		*retlen += n;	}	/* Now we write words until we reach a non-word boundary. */	while (len >= BUSWIDTH) {		if (omap_flash_write_word(to, *((__u16 *) buf)))			return (-EIO);		to += BUSWIDTH;		buf += BUSWIDTH;		*retlen += BUSWIDTH;		len -= BUSWIDTH;	}	/* Top up the last unaligned bytes, padded with original data.... */	if (len & (BUSWIDTH - 1)) {		i = n = 0;		down(&omap_flash_lock);		*((__u16 *) tmp) = omap_flash_inw(to);		up(&omap_flash_lock);		while (len--)			tmp[i++] = buf[n++];		if (omap_flash_write_word(to, *((__u16 *) tmp)))			return (-EIO);		*retlen += n;	}	return 0;}int __initomap_flash_init(void){	int result;	printk("%s: MTD Self-Contained Driver ver. 1.0 size=0x%ulx\n", module_name, OMAP_NOR_FLASH_SIZE);        omap_nor_flash_base = (unsigned long) ioremap(OMAP_NOR_FLASH_START1, OMAP_NOR_FLASH_SIZE);	result = omap_flash_probe();	if (result < 0) {		iounmap((void *) omap_nor_flash_base);        	omap_nor_flash_base = (unsigned long) ioremap(OMAP_NOR_FLASH_START2, OMAP_NOR_FLASH_SIZE); 	        result = omap_flash_probe();	        if (result < 0) {	                iounmap((void *) omap_nor_flash_base); 			return (-ENXIO);		}	}#ifndef CONFIG_MTD_PARTITIONS	result = add_mtd_device(&mtd);#else	result = add_mtd_partitions(&mtd,				    omap_partitions,				    NB_OF(omap_partitions));#endif	/* check result */	if (result)		iounmap((void *) omap_nor_flash_base);	return (result);}void __exitomap_flash_exit(void){#ifndef CONFIG_MTD_PARTITIONS	del_mtd_device(&mtd);#else	del_mtd_partitions(&mtd);#endif	iounmap((void *) omap_nor_flash_base);}module_init(omap_flash_init);module_exit(omap_flash_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("MontaVista Software Inc.");MODULE_DESCRIPTION("Self-Contained MTD driver for NOR Flash on OMAP board");

⌨️ 快捷键说明

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