pxa255_nand.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 325 行

C
325
字号
/* * MTD NAND device driver for S3C2410 Development Board * based on smc.c *  * This file is subject to the terms and conditions of the GNU General Public * License.  See the file COPYING in the main directory of this archive * for more details. */#include <linux/slab.h>#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <asm/io.h>#include <asm/sizes.h>#include <asm/hardware.h>#ifdef CONFIG_PM#include <linux/pm.h>#endif#ifdef CONFIG_PMstruct pm_dev *smc_pm_dev;#endif/* * MTD structure for S3C2410 Development Board */static struct mtd_info *s3c2410_mtd = NULL;static unsigned long this_nf_addr;#ifdef CONFIG_MTD_PARTITIONSstatic struct mtd_partition partition_info[] = {	{ name: 	"boot",	  offset:	0,	  size:		SZ_256K },	{ name: 	"kernel",	  offset:	SZ_256K,	  size:		SZ_2M - SZ_256K },	{ name:		"rootfs",	  offset:	SZ_2M,	  size:		14 * SZ_1M },	{ name:		"ext-fs1",	  offset:	SZ_16M,	  size:		SZ_16M },	{ name:		"ext-fs2",	  offset:	SZ_32M,	  size:		SZ_32M },};#endifstatic void smc_hwcontrol(struct mtd_info *mtd, int cmd) {	struct nand_chip *my_nand = mtd->priv;    switch (cmd) {    case NAND_CTL_SETNCE:	GPCR1 = 1<<1;	//GP33(nCS5) low	break;    case NAND_CTL_CLRNCE:	GPSR1 = 1<<1;	//GP33(nCS5) high	break;    case NAND_CTL_SETCLE:	my_nand->IO_ADDR_W = this_nf_addr+0x80;	break;    case NAND_CTL_CLRCLE:	my_nand->IO_ADDR_W = this_nf_addr;	break;    case NAND_CTL_SETALE:	my_nand->IO_ADDR_W = this_nf_addr+0x40;	break;    case NAND_CTL_CLRALE:	my_nand->IO_ADDR_W = this_nf_addr;	break;    }}static void smc_command (struct mtd_info *mtd, unsigned command, int column, int page_addr){	register struct nand_chip *my_nand = mtd->priv;		/*	 * Write out the command to the device.	 */	if (command != NAND_CMD_SEQIN)		__raw_writeb(command, this_nf_addr+0x80);	else {		if (mtd->oobblock == 256 && column >= 256) {			column -= 256;			__raw_writeb(NAND_CMD_RESET, this_nf_addr+0x80);			__raw_writeb(NAND_CMD_READOOB, this_nf_addr+0x80);			__raw_writeb(NAND_CMD_SEQIN, this_nf_addr+0x80);		}		else			if (mtd->oobblock == 512 && column >= 256) {				if (column < 512) {					column -= 256;					__raw_writeb(NAND_CMD_READ1, this_nf_addr+0x80);						__raw_writeb(NAND_CMD_SEQIN, this_nf_addr+0x80);				} else {					column -= 512;					__raw_writeb(NAND_CMD_READOOB, this_nf_addr+0x80);						__raw_writeb(NAND_CMD_SEQIN, this_nf_addr+0x80);				}			} else {				__raw_writeb(NAND_CMD_READ0, this_nf_addr+0x80);				__raw_writeb(NAND_CMD_SEQIN, this_nf_addr+0x80);			}	}		/* Serially input address */	if (column != -1)		__raw_writeb(column, this_nf_addr+0x40);	if (page_addr != -1) {		__raw_writeb((unsigned char)(page_addr & 0xff), this_nf_addr+0x40);		__raw_writeb((unsigned char)((page_addr >> 8) & 0xff), this_nf_addr+0x40);		/* One more address cycle for higher density devices */		if (mtd->size & 0x0c000000) {			__raw_writeb((unsigned char)((page_addr >> 16) & 0x0f), this_nf_addr+0x40);		}	}	/* wait until command is processed */	while (!my_nand->dev_ready(mtd))		;}/*static u_char read_data(struct mtd_info *mtd) {    return (u_char)__raw_readb(this_nf_addr);}static void write_data(struct mtd_info *mtd, u_char val) {    __raw_writeb((u_char)val, this_nf_addr);}*/static int device_ready(struct mtd_info *mtd) {	udelay(10);	return GPLR1 & (1<<22);}#ifdef CONFIG_PMstatic unsigned long nfcon;static ints3c2410_smc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){//	struct nand_chip *this = (struct nand_chip *)pm_dev->data;//	switch (req) {//		case PM_SUSPEND://			nfcon = __raw_readl(S3C2410_NFCONF);//			break;//		case PM_RESUME://			__raw_writel(nfcon, S3C2410_NFCONF);//			/* Chip Enable -> RESET -> Wait for Ready -> Chip Disable *///			this->hwcontrol(s3c2410_mtd, NAND_CTL_SETNCE);//			this->cmdfunc(s3c2410_mtd, NAND_CMD_RESET, -1, -1);//			while(!this->dev_ready(s3c2410_mtd));//			this->hwcontrol(s3c2410_mtd, NAND_CTL_CLRNCE);//			break;//	}	return 0;}#endif//#define	SELF_PROBE/* * Main initialization routine */int __init smc_s3c2410_init (void){    struct nand_chip *this;    int err = 0;	pxa_gpio_mode(33|GPIO_OUT);	//CS	pxa_gpio_mode(54|GPIO_IN);	//RDY/BUSY	#ifdef CONFIG_ARCH_FS_PXA255_V30	this_nf_addr = (unsigned long)ioremap(0x08000000, SZ_1M);#else	this_nf_addr = (unsigned long)ioremap(0x04b00000, SZ_1M);#endif	if(!this_nf_addr) {		printk(KERN_ERR "Unable to ioremap nand flash address!\n");		return -ENOMEM;	}	//printk(KERN_INFO "remap nand flash address to %x\n", this_nf_addr);	pxa_gpio_mode(GPIO33_nCS_5|GPIO_OUT);	pxa_gpio_mode(GPIO_IN|GPIO54_pSKTSEL);#ifdef	SELF_PROBE	{			__u16 chip_id, wait_dly = 0;			GPCR1 = 1<<1;		writeb(0x90, this_nf_addr+0x80);		writeb(0x0,  this_nf_addr+0x40);		while(!(GPLR1&(1<<22))) {			if(wait_dly++>1000)				break;		}		chip_id  = readb(this_nf_addr)<<8;		chip_id |= readb(this_nf_addr);		GPSR1 = 1<<1;		printk("Nand Flash ID is 0x%x\n", chip_id);	}#endif	    /* Allocate memory for MTD device structure and private data */    s3c2410_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),			GFP_KERNEL);    if (!s3c2410_mtd) {      printk ("Unable to allocate S3C2410 NAND MTD device structure.\n");      return -ENOMEM;    }    /* Get pointer to private data */    this = (struct nand_chip *) (&s3c2410_mtd[1]);    /* Initialize structures */    memset((char *) s3c2410_mtd, 0, sizeof(struct mtd_info));    memset((char *) this, 0, sizeof(struct nand_chip));    /* Link the private data with the MTD structure */    s3c2410_mtd->priv = this;    /* Set address of NAND IO lines */	this->IO_ADDR_R  = this_nf_addr;	this->IO_ADDR_W  = this_nf_addr;	this->hwcontrol  = smc_hwcontrol;	this->dev_ready  = device_ready;	this->cmdfunc    = smc_command;	this->chip_delay = 20;	this->eccmode    = NAND_ECC_SOFT;//	this->write_cmd  = write_cmd;//	this->write_addr = write_addr;//	this->read_byte  = read_data;//	this->write_byte = write_data;    /* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */    this->hwcontrol(s3c2410_mtd, NAND_CTL_SETNCE);    this->cmdfunc(s3c2410_mtd, NAND_CMD_RESET, -1, -1);    while(!this->dev_ready(s3c2410_mtd));    this->hwcontrol(s3c2410_mtd, NAND_CTL_CLRNCE);    /* Scan to find existance of the device */    if (nand_scan (s3c2410_mtd, 1)) {    	err = -ENXIO;		goto out_mtd;    }    /* Allocate memory for internal data buffer */    this->data_buf = kmalloc(sizeof(u_char) * 			     (s3c2410_mtd->oobblock + s3c2410_mtd->oobsize), 			     GFP_KERNEL);    if (!this->data_buf) {      printk ("Unable to allocate NAND data buffer for S3C2410.\n");      err = -ENOMEM;      goto out_mtd;    }#ifdef CONFIG_MTD_PARTITIONS    switch(s3c2410_mtd->size) {		case SZ_16M:		err = add_mtd_partitions(s3c2410_mtd, partition_info,				ARRAY_SIZE (partition_info)-2 );		break;	case SZ_32M:		err = add_mtd_partitions(s3c2410_mtd, partition_info,				ARRAY_SIZE (partition_info)-1);		break;	case SZ_64M:		err = add_mtd_partitions(s3c2410_mtd, partition_info,				ARRAY_SIZE (partition_info));		break;	default:		printk ("Unsupported SmartMedia device\n");		err = -ENXIO;		goto out_cac;	}#else    add_mtd_device(s3c2410_mtd);#endif#ifdef CONFIG_PM//	smc_pm_dev = pm_register(PM_DEBUG_DEV, PM_SYS_MISC, s3c2410_smc_pm_callback);//	if (smc_pm_dev)//		smc_pm_dev->data = &s3c2410_mtd[1];#endif    goto out;out_cac:	kfree (this->data_buf);out_mtd:	kfree (s3c2410_mtd);out:	return err;}module_init(smc_s3c2410_init);/* * Clean up routine */#ifdef MODULEstatic void __exit smc_s3c2410_cleanup (void){    struct nand_chip *this = (struct nand_chip *) &s3c2410_mtd[1];#if defined(CONFIG_MTD_SMC_S3C2410_SMDK_PARTITION)     del_mtd_partitions(s3c2410_mtd);#else    del_mtd_device(s3c2410_mtd);#endif        kfree (this->data_buf);    kfree (s3c2410_mtd);	iounmap((void *)this_nf_addr);	this_nf_addr = 0;}module_exit(smc_s3c2410_cleanup);#endifMODULE_LICENSE("GPL");MODULE_AUTHOR("antiscle <hzhmei@hotmail.com>");MODULE_DESCRIPTION("nand flash on FS-PXA255 board");

⌨️ 快捷键说明

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