Chinaunix首页 | 论坛 | 博客
  • 博客访问: 203240
  • 博文数量: 33
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1277
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-03 10:03
个人简介

现于杭州电子科技大学攻读硕士学位

文章分类

全部博文(33)

文章存档

2013年(33)

我的朋友

分类: 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");    //模块别名

阅读(1719) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~