分类: LINUX
2013-09-07 20:18:07
/***************************************************************************************************
参考
drivers\mtd\nand\s3c2410.c
drivers\mtd\nand\at91_nand.c
***************************************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct nand_regs {
unsigned long NFCONF ;
unsigned long NFCONT;
unsigned long NFCMMD ;
unsigned long NFADDR;
unsigned long NFDATA;
unsigned long NFECCD0;
unsigned long NFECCD1;
unsigned long NFSECCD;
unsigned long NFSTAT;
unsigned long NFESTAT0;
unsigned long NFESTAT1;
unsigned long NFMECC0;
unsigned long NFMECC1;
unsigned long NFSECC;
unsigned long NFSBLK;
unsigned long NFEBLK ;
};
static struct nand_chip *nand_chip;
static struct mtd_info *mtd_info;
static struct nand_regs *nand_regs;
static struct mtd_partition nand_parts[] = { /* 分区 */
[0] = {
.name = "bootloader", /* 第一个分区名称 */
.size = 0x00040000, /* 分区大小 */
.offset = 0, /* */
},
[1] = {
.name = "params", /* 第二个分区名称 */
.offset = MTDPART_OFS_APPEND, /* 分区偏移 ,MTDPART_OFS_APPEND 表示紧跟第一个分区后面*/
.size = 0x00020000, /* 分区大小 */
},
[2] = {
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = 0x00200000,
},
[3] = {
.name = "root",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL, /* 表示剩余的所有的存储空间 */
}
};
static void Nand_Select (struct mtd_info *mtd, int chip)
{
if(chip==-1)
{ /* 取消片选 */
nand_regs->NFCONT|=(1<<1);
}
else
{/* 选中 */
nand_regs->NFCONT&=~(1<<1);
}
}
static void Nand_cmd(struct mtd_info *mtd, int data, unsigned int ctrl)
{
if (data == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE) /* 如果是命令 */
{
nand_regs->NFCMMD=data;
}
else /* 是地址 */
{
nand_regs->NFADDR=data;
}
}
static int Nand__ready(struct mtd_info *mtd)
{
return nand_regs->NFSTAT&(1<<0);
}
static int __init nand_init(void)
{
struct clk *clk;
/* 为了方便下面的设置,首先进行NAND Flash控制器寄存器映射 */
nand_regs=ioremap(0x4E000000, sizeof(struct nand_regs));
/*1 : 分配和设置 nand_chip 结构*/
/* 分配*/
nand_chip=kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
/* 设置 */
nand_chip->select_chip = Nand_Select ; /*芯片的选中与否*/
nand_chip->cmd_ctrl =Nand_cmd; /* 命令的 发送*/
nand_chip->dev_ready =Nand__ready; /* NAND Flash 的状态:忙或不忙 */
nand_chip->IO_ADDR_R =&nand_regs->NFDATA; /* 读数据寄存器的地址,是ioremap映射后的虚拟地址 */
nand_chip->IO_ADDR_W =&nand_regs->NFDATA; /* 写数据寄存器的地址,是ioremap映射后的虚拟地址 */
nand_chip->ecc.mode =NAND_ECC_SOFT; /* 软件ECC校验 */
/*2: 分配和设置 mtd_info 结构*/
/* 分配*/
mtd_info=kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
/* 设置 */
mtd_info->priv=nand_chip; /* 这是必须的 */
mtd_info->owner=THIS_MODULE;
/* 3. 硬件相关的设置: 根据NAND FLASH的手册设置时间参数 */
/* 使能NAND FLASH控制器的时钟 */
clk = clk_get(NULL, "nand");
clk_enable(clk); /* CLKCON'bit[4] */
/* HCLK=100MHz
* TACLS: 发出CLE/ALE之后多长时间才发出nWE信号, 从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
* TWRPH0: nWE的脉冲宽度, HCLK x ( TWRPH0 + 1 ), 从NAND手册可知它要>=12ns, 所以TWRPH0>=1
* TWRPH1: nWE变为高电平后多长时间CLE/ALE才能变为低电平, 从NAND手册可知它要>=5ns, 所以TWRPH1>=0
*/
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
nand_regs->NFCONF=(TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<6);
/* NFCONT:
* BIT1-设为1, 取消片选
* BIT0-设为1, 使能NAND FLASH控制器
*/
nand_regs->NFCONT=(1<<1)|(1<<0);
nand_scan(mtd_info,1); /* 以mtd_info为参数调用nand_scan函数探测NAND Flash的存在 (实际是识别NAND FLASH, 并构造mtd_info) */
add_mtd_partitions(mtd_info,nand_parts,4); /* 注册 */
return 0;
}
static void __exit nand_exit(void)
{
iounmap(nand_regs);
kfree(nand_chip);
kfree(mtd_info);
del_mtd_partitions(mtd_info);
}
module_init(nand_init);
module_exit(nand_exit);
MODULE_AUTHOR("shenchaoping"); //描述模块作者
MODULE_LICENSE("Dual BSD/GPL");//指定代码使用双重许可证
MODULE_VERSION("v1.0"); //模块版本
MODULE_DESCRIPTION("A Nand Flash Operation Module"); //说明模块用途
MODULE_ALIAS("NF"); //模块别名