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

📄 mxc_nd.c

📁 飞思卡尔芯片imx27下的MTD模块的驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		break;	case NAND_CMD_READ0:		g_nandfc_info.colAddr = column;		g_nandfc_info.bSpareOnly = false;		useirq = false;		break;	case NAND_CMD_READOOB:		g_nandfc_info.colAddr = column;		g_nandfc_info.bSpareOnly = true;		useirq = false;		if (is2k_Pagesize)			command = NAND_CMD_READ0;	/* only READ0 is valid */		break;	case NAND_CMD_SEQIN:		if (column >= mtd->writesize) {			if (is2k_Pagesize) {				/** 			 				  * FIXME: before send SEQIN command for write OOB,				  * We must read one page out. 			 				  * For K9F1GXX has no READ1 command to set current HW 			 				  * pointer to spare area, we must write the whole page including OOB together.			 				  */				/* call itself to read a page */				mxc_nand_command(mtd, NAND_CMD_READ0, 0,						 page_addr);			}			g_nandfc_info.colAddr = column - mtd->writesize;			g_nandfc_info.bSpareOnly = true;			/* Set program pointer to spare region */			if (!is2k_Pagesize)				send_cmd(NAND_CMD_READOOB, false);		} else {			g_nandfc_info.bSpareOnly = false;			g_nandfc_info.colAddr = column;			/* Set program pointer to page start */			if (!is2k_Pagesize)				send_cmd(NAND_CMD_READ0, false);		}		useirq = false;		break;	case NAND_CMD_PAGEPROG:#ifndef CONFIG_MTD_NAND_MXC_ECC_CORRECTION_OPTION2		if (Ecc_disabled) {			/* Enable Ecc for page writes */			NFC_CONFIG1 |= NFC_ECC_EN;		}#endif		send_prog_page(0, g_nandfc_info.bSpareOnly);		if (is2k_Pagesize) {			/* data in 4 areas datas */			send_prog_page(1, g_nandfc_info.bSpareOnly);			send_prog_page(2, g_nandfc_info.bSpareOnly);			send_prog_page(3, g_nandfc_info.bSpareOnly);		}		break;	case NAND_CMD_ERASE1:		useirq = false;		break;	}	/*	 * Write out the command to the device.	 */	send_cmd(command, useirq);	/*	 * Write out column address, if necessary	 */	if (column != -1) {		/*		 * MXC NANDFC can only perform full page+spare or		 * spare-only read/write.  When the upper layers		 * layers perform a read/write buf operation,		 * we will used the saved column adress to index into		 * the full page.		 */		send_addr(0, page_addr == -1);		if (is2k_Pagesize)			send_addr(0, false);	/* another col addr cycle for 2k page */	}	/*	 * Write out page address, if necessary	 */	if (page_addr != -1) {		send_addr((page_addr & 0xff), false);	/* paddr_0 - p_addr_7 */		if (is2k_Pagesize) {			/* One more address cycle for higher density devices */			if (mtd->size >= 0x10000000) {				send_addr((page_addr >> 8) & 0xff, false);	/* paddr_8 - paddr_15 */				send_addr((page_addr >> 16) & 0xff, true);			} else				send_addr((page_addr >> 8) & 0xff, true);	/* paddr_8 - paddr_15 */		} else {			/* One more address cycle for higher density devices */			if (mtd->size >= 0x4000000) {				send_addr((page_addr >> 8) & 0xff, false);	/* paddr_8 - paddr_15 */				send_addr((page_addr >> 16) & 0xff, true);			} else				send_addr((page_addr >> 8) & 0xff, true);	/* paddr_8 - paddr_15 */		}	}	/*	 * Command post-processing step	 */	switch (command) {	case NAND_CMD_RESET:		break;	case NAND_CMD_READOOB:	case NAND_CMD_READ0:		if (is2k_Pagesize) {			/* send read confirm command */			send_cmd(NAND_CMD_READSTART, true);			/* read for each AREA */			send_read_page(0, g_nandfc_info.bSpareOnly);			send_read_page(1, g_nandfc_info.bSpareOnly);			send_read_page(2, g_nandfc_info.bSpareOnly);			send_read_page(3, g_nandfc_info.bSpareOnly);		} else {			send_read_page(0, g_nandfc_info.bSpareOnly);		}		break;	case NAND_CMD_READID:		send_read_id();		break;	case NAND_CMD_PAGEPROG:#ifndef CONFIG_MTD_NAND_MXC_ECC_CORRECTION_OPTION2		if (Ecc_disabled) {			/* Disble Ecc after page writes */			NFC_CONFIG1 &= ~(NFC_ECC_EN);		}#endif		break;	case NAND_CMD_STATUS:		break;	case NAND_CMD_ERASE2:		break;	}}#ifdef CONFIG_MXC_NAND_LOW_LEVEL_ERASEstatic void mxc_low_erase(struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	unsigned int page_addr, addr;	u_char status;	DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : mxc_low_erase:Erasing NAND\n");	for (addr = 0; addr < this->chipsize; addr += mtd->erasesize) {		page_addr = addr / mtd->writesize;		mxc_nand_command(mtd, NAND_CMD_ERASE1, -1, page_addr);		mxc_nand_command(mtd, NAND_CMD_ERASE2, -1, -1);		mxc_nand_command(mtd, NAND_CMD_STATUS, -1, -1);		status = mxc_nand_read_byte(mtd);		if (status & NAND_STATUS_FAIL) {			printk(KERN_ERR			       "ERASE FAILED(block = %d,status = 0x%x)\n",			       addr / mtd->erasesize, status);		}	}}#endif/*! * This function is called during the driver binding process. * * @param   pdev  the device structure used to store device specific *                information that is used by the suspend, resume and *                remove functions * * @return  The function always returns 0. */static int __init mxcnd_probe(struct platform_device *pdev){	struct nand_chip *this;	struct mtd_info *mtd;	struct flash_platform_data *flash = pdev->dev.platform_data;	int nr_parts = 0;	int err = 0;	/* Allocate memory for MTD device structure and private data */	mxc_nand_data = kmalloc(sizeof(struct mxc_mtd_s), GFP_KERNEL);	if (!mxc_nand_data) {		printk(KERN_ERR "%s: failed to allocate mtd_info\n",		       __FUNCTION__);		err = -ENOMEM;		goto out;	}	memset(mxc_nand_data, 0, sizeof(struct mxc_mtd_s));	memset((char *)&g_nandfc_info, 0, sizeof(g_nandfc_info));	mxc_nand_data->dev = &pdev->dev;	/* structures must be linked */	this = &mxc_nand_data->nand;	mtd = &mxc_nand_data->mtd;	mtd->priv = this;	mtd->owner = THIS_MODULE;	/* 50 us command delay time */	this->chip_delay = 5;	this->priv = mxc_nand_data;	this->dev_ready = mxc_nand_dev_ready;	this->cmdfunc = mxc_nand_command;	this->select_chip = mxc_nand_select_chip;	this->read_byte = mxc_nand_read_byte;	this->read_word = mxc_nand_read_word;	this->write_buf = mxc_nand_write_buf;	this->read_buf = mxc_nand_read_buf;	this->verify_buf = mxc_nand_verify_buf;	nfc_clk = clk_get(&pdev->dev, "nfc_clk");	clk_enable(nfc_clk);	NFC_CONFIG1 |= NFC_INT_MSK;	init_waitqueue_head(&irq_waitq);	err = request_irq(INT_NANDFC, mxc_nfc_irq, 0, "mxc_nd", NULL);	if (err) {		goto out_1;	}	if (hardware_ecc) {		this->ecc.calculate = mxc_nand_calculate_ecc;		this->ecc.hwctl = mxc_nand_enable_hwecc;		this->ecc.correct = mxc_nand_correct_data;		this->ecc.mode = NAND_ECC_HW;		this->ecc.size = 512;		this->ecc.bytes = 3;		this->ecc.layout = &nand_hw_eccoob_8;		NFC_CONFIG1 |= NFC_ECC_EN;	} else {		this->ecc.mode = NAND_ECC_SOFT;	}	/* Reset NAND */	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);	/* preset operation */	/* Unlock the internal RAM Buffer */	NFC_CONFIG = 0x2;	/* Blocks to be unlocked */	NFC_UNLOCKSTART_BLKADDR = 0x0;	NFC_UNLOCKEND_BLKADDR = 0x4000;	/* Unlock Block Command for given address range */	NFC_WRPROT = 0x4;	/* NAND bus width determines access funtions used by upper layer */	if (flash->width == 2) {		this->options |= NAND_BUSWIDTH_16;		this->ecc.layout = &nand_hw_eccoob_16;	} else {		this->options |= 0;	}	if ((NFMS >> NFMS_BIT) & 0x1)		is2k_Pagesize = 1;    else        is2k_Pagesize = 0;	/* Scan to find existence of the device */	if (nand_scan(mtd, 1)) {		DEBUG(MTD_DEBUG_LEVEL0,		      "MXC_ND: Unable to find any NAND device.\n");		err = -ENXIO;		goto out_1;	}	/* Register the partitions */#ifdef CONFIG_MTD_PARTITIONS	nr_parts =	    parse_mtd_partitions(mtd, part_probes, &mxc_nand_data->parts, 0);	if (nr_parts > 0)		add_mtd_partitions(mtd, mxc_nand_data->parts, nr_parts);	else if (flash->parts)		add_mtd_partitions(mtd, flash->parts, flash->nr_parts);	else#endif	{		pr_info("Registering %s as whole device\n", mtd->name);		add_mtd_device(mtd);	}#ifdef CONFIG_MXC_NAND_LOW_LEVEL_ERASE	/* Erase all the blocks of a NAND */	mxc_low_erase(mtd);#endif	platform_set_drvdata(pdev, mtd);	return 0;      out_1:	kfree(mxc_nand_data);      out:	return err;} /*!  * Dissociates the driver from the device.  *  * @param   pdev  the device structure used to give information on which  *  * @return  The function always returns 0.  */static int __exit mxcnd_remove(struct platform_device *pdev){	struct mtd_info *mtd = platform_get_drvdata(pdev);	clk_put(nfc_clk);	platform_set_drvdata(pdev, NULL);	if (mxc_nand_data) {		nand_release(mtd);		free_irq(INT_NANDFC, NULL);		kfree(mxc_nand_data);	}	return 0;}#ifdef CONFIG_PM/*! * This function is called to put the NAND in a low power state. Refer to the * document driver-model/driver.txt in the kernel source tree for more * information. * * @param   pdev  the device information structure * * @param   state the power state the device is entering * * @return  The function returns 0 on success and -1 on failure */static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state){	struct mtd_info *info = platform_get_drvdata(pdev);	int ret = 0;	DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n");	if (info)		ret = info->suspend(info);	/* Disable the NFC clock */	clk_disable(nfc_clk);	return ret;}/*! * This function is called to bring the NAND back from a low power state. Refer * to the document driver-model/driver.txt in the kernel source tree for more * information. * * @param   pdev  the device information structure * * @return  The function returns 0 on success and -1 on failure */static int mxcnd_resume(struct platform_device *pdev){	struct mtd_info *info = platform_get_drvdata(pdev);	int ret = 0;	DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n");	/* Enable the NFC clock */	clk_enable(nfc_clk);	if (info) {		info->resume(info);	}	return ret;}#else/*! * \def mxcnd_resume * The PM is not defined. *//*! * The PM is not defined. */#define mxcnd_suspend   NULL#define mxcnd_resume    NULL#endif				/* CONFIG_PM *//*! * This structure contains pointers to the power management callback functions. */static struct platform_driver mxcnd_driver = {	.driver = {		   .name = "mxc_nand_flash",		   },	.probe = mxcnd_probe,	.remove = __exit_p(mxcnd_remove),	.suspend = mxcnd_suspend,	.resume = mxcnd_resume,};/*! * Main initialization routine * @return  0 if successful; non-zero otherwise */static int __init mxc_nd_init(void){	/* Register the device driver structure. */	pr_info("MXC MTD nand Driver %s\n", DVR_VER);	if (platform_driver_register(&mxcnd_driver) != 0) {		printk(KERN_ERR "Driver register failed for mxcnd_driver\n");		return -ENODEV;	}	return 0;}/*! * Clean up routine */static void __exit mxc_nd_cleanup(void){	/* Unregister the device structure */	platform_driver_unregister(&mxcnd_driver);}module_init(mxc_nd_init);module_exit(mxc_nd_cleanup);MODULE_AUTHOR("Freescale Semiconductor, Inc.");MODULE_DESCRIPTION("MXC NAND MTD driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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