2014-04-17 nand flash驱动程序__

实验描述:

nand flash驱动程序


内核版本:

Linux 2.6.38


开发板: 

Mini 6410


如何确定参数时间的大小:

s3c6410手册:



nand flash手册:



程序实现:

#include <linux/init.h>  
#include <linux/module.h>  
#include <linux/device.h>
#include <linux/cdev.h> 
#include <linux/fs.h> 
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>

#define PRINTK printk
//#define PRINTK(...) 
struct s3c6410_nand_regs {
	unsigned long nfconf  ;
	unsigned long nfcont  ;
	unsigned long nfcmd   ;
	unsigned long nfaddr  ;
	unsigned long nfdata  ;
	unsigned long nfeccd0 ;
	unsigned long nfeccd1 ;
	unsigned long nfeccd  ;
	unsigned long nfsblk  ;
	unsigned long nfeblk  ;
	unsigned long nfstat  ;
	unsigned long nfeccrr0 ;
	unsigned long nfeccrr1 ;
	unsigned long nfmecc0 ;
	unsigned long nfmecc1 ;
	unsigned long nfsecc ;
	unsigned long nfmlcbitpt;
	unsigned long nf8eccerr0;
	unsigned long nf8eccerr1;
	unsigned long nf8eccerr2;
	unsigned long nfm8ecc0 ;
	unsigned long nfm8ecc1 ;
	unsigned long nfm8ecc2 ;
	unsigned long nfm8ecc3 ;
	unsigned long nfmlc8bitpt0;
	unsigned long nfmlc8bitpt1;
};

static struct nand_chip *s3c6410_nand_chips;
static struct s3c6410_nand_regs *s3c6410_nand_regs;
static struct clk *nand_clk;
static struct mtd_info *s3c6410_mtd_info;

static struct mtd_partition s3c6410_nand_parts[] = {
	[0] = {
		.name   = "bootloader",
		.size   = 0x000000080000,
		.offset	= 0,
	},
	[1] = {
		.name   = "kernel",
		.offset = MTDPART_OFS_APPEND,
		.size   = 0x000000500000,
	},
	[2] = {
		.name   = "file system",
		.offset = MTDPART_OFS_APPEND,
		.size   = MTDPART_SIZ_FULL,
	}
};

void nand_select_chip(struct mtd_info *mtd, int chip)
{
	if (chip == -1)
	{
		s3c6410_nand_regs->nfcont |= (1<<1);	//cancle select	
		PRINTK(KERN_ALERT"cancle select!\n");
	}
	else
	{
		s3c6410_nand_regs->nfcont &= ~(1<<1); //enable select	
		PRINTK(KERN_ALERT"enable select!\n");
	}
}

void nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
	if (ctrl & NAND_CLE)
	{
		s3c6410_nand_regs->nfcmd = dat;	//send  command
		PRINTK(KERN_ALERT"send  command\n");
	}
	else
	{
		s3c6410_nand_regs->nfaddr = dat; //send  address
		PRINTK(KERN_ALERT"send  address\n");
	}
}

int nand_dev_ready(struct mtd_info *mtd)
{
	PRINTK(KERN_ALERT"read:%d\n", s3c6410_nand_regs->nfstat & (1<<0));
	return (s3c6410_nand_regs->nfstat & (1<<0));
}

static int nand_driver_init(void)  
{   
	int err;
	s3c6410_nand_chips = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
	if(!s3c6410_nand_chips){
		err = -ENOMEM;
		PRINTK(KERN_ALERT"s3c6410_nand_chips kzalloc busy!\n");
		goto out_err;
	}
	
	s3c6410_nand_regs = ioremap(0x70200000, sizeof(struct s3c6410_nand_regs));
	if(!s3c6410_nand_regs){
		err = -EIO;
		PRINTK(KERN_ALERT"ioreamp to s3c6410_nand_regs fail!\n");
		goto out_err;
	}
	
	s3c6410_nand_chips->select_chip = nand_select_chip;
	s3c6410_nand_chips->cmd_ctrl = nand_cmd_ctrl;
	s3c6410_nand_chips->IO_ADDR_R = &s3c6410_nand_regs->nfdata;
	s3c6410_nand_chips->IO_ADDR_W = &s3c6410_nand_regs->nfdata;
	s3c6410_nand_chips->dev_ready = nand_dev_ready;
	s3c6410_nand_chips->ecc.mode = NAND_ECC_SOFT;

	nand_clk = clk_get(NULL, "nand"); //we can also use 6410 guide to set clk
	clk_enable(nand_clk);

#define TACLS    0
#define TWRPH0   1
#define TWRPH1   0

	//3.3V, As tclh>=5ns,twp>=12ns,tcls>=12ns, HCLK=10ns, so TACLS=0, TWRPH0=3(1/400)
	s3c6410_nand_regs->nfconf = (TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4);
	s3c6410_nand_regs->nfcont = (1 << 0) | (1 << 1);	//select and enable

	s3c6410_mtd_info = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
	if(!s3c6410_mtd_info){
		err = -ENOMEM;
		PRINTK(KERN_ALERT"s3c6410_mtd_info kzalloc busy!\n");
		goto out_err;
	}
	
	s3c6410_mtd_info->owner = THIS_MODULE;
	s3c6410_mtd_info->priv =s3c6410_nand_chips;

	if(nand_scan(s3c6410_mtd_info, 1)){//scan nand flash to produce mtd_info
		err = -ENXIO;
		goto out_err;
	}  

	add_mtd_partitions(s3c6410_mtd_info, s3c6410_nand_parts, 3);
	PRINTK(KERN_ALERT"init!\n");
	return 0;
out_err:
	if(s3c6410_mtd_info)
		kfree(s3c6410_mtd_info);
	if(s3c6410_nand_regs)
		iounmap(s3c6410_nand_regs);
	if(s3c6410_nand_chips)
		kfree(s3c6410_nand_chips);
	return err;
}  

static int nand_driver_exit(void)  
{   
	del_mtd_partitions(s3c6410_mtd_info);
	if(s3c6410_mtd_info)
		kfree(s3c6410_mtd_info);
	if(s3c6410_nand_regs)
		iounmap(s3c6410_nand_regs);
	if(s3c6410_nand_chips)
		kfree(s3c6410_nand_chips);
	PRINTK(KERN_ALERT"exit!\n");
	return 0;  
}  
 
module_init(nand_driver_init);  
module_exit(nand_driver_exit);
MODULE_LICENSE("GPL");  
MODULE_DESCRIPTION("S3C6410 nand flash driver");
MODULE_AUTHOR("Books, <uppour@sina.cn>");


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值