/*判断忙*/
static int s3c_dev_ready(struct mtd_info *mtd)
{
/*返回"NFSTAT的bit[0]";*/
return (s3c_nand_regs->nfstat & (1<<0));
}
static void s3c_cmd_ctrl(struct mtd_info *mtd, int dat,unsigned int ctrl)
{
if (ctrl & NAND_CLE)
{
/* 发命令: NFCMMD=dat */
s3c_nand_regs->nfcmd = dat;
//writeb(cmd, host->io_base + (1 << host->board->cle));/*命令*/
}
else
{
/* 发地址: NFADDR=dat */
s3c_nand_regs->nfaddr = dat;
//writeb(cmd, host->io_base + (1 << host->board->ale));/*地址*/
}
}
static void s3c_select_chip(struct mtd_info *mtd, int chip)
{
if(chip ==-1)
{
/*表示取消选中 NFCONT[1]设为1 */
s3c_nand_regs->nfcont |=(1<<1);
}
else
{
s3c_nand_regs->nfcont &=~(1<<1);
/*选中芯片 NFCONT[1]设为0 */
}
}
static int s3c_nand_init(void)
{
struct clk *clk;
/*1.分配一个nand_chip结构体*/
s3c_nand_chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));
/*2.设置nandc_chip结构体*/
s3c_nand_chip->IO_ADDR_R = &s3c_nand_regs->nfdata;
s3c_nand_chip->IO_ADDR_W = &s3c_nand_regs->nfdata;
s3c_nand_chip->cmd_ctrl = s3c_cmd_ctrl;
s3c_nand_chip->dev_ready = s3c_dev_ready;
s3c_nand_chip->select_chip = s3c_select_chip;
s3c_nand_chip->ecc.mode = NAND_ECC_SOFT;
//s3c_nand_chip->chip_delay = 20;
/* 使能NAND FLASH控制器的时钟 */
clk = clk_get(NULL, "nand");
clk_enable(clk); /* CLKCON'bit[4] */
/*初始化nand控制器 设置寄存器*/
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
/* 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
*/
s3c_nand_regs->nfconf=(TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* NFCONT:
* BIT1-设为1, 取消片选
* BIT0-设为1, 使能NAND FLASH控制器
* BIT4-设为0, 未初始化hardware ECC
*/
s3c_nand_regs->nfcont = (1<<1) | (1<<0);
/*分配一个mtd_info结构体*/
s3c_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
/*设置s3c_mtd结构体*/
s3c_mtd->owner = THIS_MODULE;
s3c_mtd->priv = s3c_nand_chip;
/* 识别NAND FLASH, 构造mtd_info */
nand_scan(s3c_mtd, 1);
/*设置分区表*/
add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4);
add_mtd_device(s3c_mtd);
return 0;
}
static void s3c_nand_exit(void)
{
kfree(s3c_mtd);
kfree(s3c_nand_chip);
iounmap(s3c_nand_regs);
}
module_init(s3c_nand_init);
module_exit(s3c_nand_exit);
MODULE_LICENSE("GPL");