【详解】如何编写Linux下Nand Flash驱动 :http://www.cnblogs.com/linux-rookie/articles/3016990.html
当读写文件请求到来的时候,流程如下
1.通过vfs进入文件系统,
2.文件系统把文件读写转换为块设备读写,其中有运用算法对读写操作进行合并,排序等,最后把块设备读写放进队列
3.循环从队列中取出读写要求,然后用处理函数(blk_init_queue设置)进行处理。
这个函数就是连接上层(IO调度)跟底层(硬件操作)的桥梁,当我们调用add_mtd_partitions的时候,就建立了上下层的联系。
4.对不同的处理要求,调用不同的nand的底层处理函数
nand flash驱动代码:
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/cpufreq.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h> #include <asm/io.h> #include <plat/regs-nand.h>
#include <plat/nand.h> struct nand_flash_regs {
unsigned long NFCONF ;
unsigned long NFCONT ;
unsigned long NFCMMD ;
unsigned long NFADDR ;
unsigned long NFDATA ;
unsigned long NFMECCD0 ;
unsigned long NFMECCD1 ;
unsigned long NFSECCD ;
unsigned long NFSBLK ;
unsigned long NFEBLK ;
unsigned long NFSTAT ;
unsigned long NFECCERR0 ;
unsigned long NFECCERR1 ;
unsigned long NFMECC0 ;
unsigned long NFMECC1 ;
unsigned long NFSECC ;
unsigned long NFMLCBITPT ;
};
static unsigned long *MP0_3CON ; static struct nand_flash_regs *nand_regs;
static struct nand_chip *chip;
static struct mtd_info *nand_mtd;
static struct clk *nand_clk; //nand flash分区
static unsigned char nbparts = ;
struct mtd_partition mynand_partition_info[] = {
{
.name = "misc",
.offset = (*SZ_1K), /* for bootloader */
.size = (*SZ_1K),
.mask_flags = MTD_CAP_NANDFLASH,
},
{
.name = "recovery",
.offset = MTDPART_OFS_APPEND,
.size = (*SZ_1M),
},
{
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = (*SZ_1M),
},
{
.name = "ramdisk",
.offset = MTDPART_OFS_APPEND,
.size = (*SZ_1M),
},
{
.name = "system",
.offset = MTDPART_OFS_APPEND,
.size = (*SZ_1M),
},
{
.name = "cache",
.offset = MTDPART_OFS_APPEND,
.size = (*SZ_1M),
},
{
.name = "userdata",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
}; static void my_select_chip(struct mtd_info *mtd, int chip)
{
if(chip == -) {
/*取消片选*/
nand_regs->NFCONT |= << ;
}
else {
/*使能片选*/
nand_regs->NFCONT &= ~( << );
}
} static void my_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
if(ctrl & NAND_CLE) /*发命令*/
nand_regs->NFCMMD = dat;
if(ctrl & NAND_ALE) /*发地址*/
nand_regs->NFADDR = dat;
} static int my_dev_ready(struct mtd_info *mtd)
{
return nand_regs->NFSTAT & ( << );
} static int __init my_nand_init(void)
{
int err;
/*分配一个nand_chip结构体*/
chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
if(IS_ERR(chip)) {
printk(KERN_ALERT"nand_chip kzalloc error\n");
return -ENOMEM;
}
nand_regs = ioremap(0xB0E00000, sizeof(struct nand_flash_regs));
MP0_3CON = ioremap(0xE0200320, ); /*使能nand flash时钟*/
nand_clk = clk_get(NULL, "nand");
if(IS_ERR(nand_clk)) {
printk(KERN_ALERT"nand_clk clk_get error\n");
err = -ENOMEM;
goto clk_err;
}
clk_enable(nand_clk); /*设置结构体nand_chip*/
chip->select_chip = my_select_chip;
chip->cmd_ctrl = my_cmd_ctrl;
chip->dev_ready = my_dev_ready;
chip->IO_ADDR_R = &nand_regs->NFDATA;
chip->IO_ADDR_W = &nand_regs->NFDATA;
chip->ecc.mode = NAND_ECC_SOFT; /*硬件设置*/ /*设置MP0_3CON寄存器*/
*MP0_3CON = 0x22222222;
/*设置时序*/
#define TACLS 1
#define TWRPH0 1
#define TWRPH1 1
nand_regs->NFCONF |= (TACLS << ) | (TWRPH0 << ) | (TWRPH1 << ); //1 = 5 address cycle ,其他默认
nand_regs->NFCONF |= << ; //1 = Force nRCS[0] to High (Disable chip select)
//1 = Enable NAND Flash Controller
nand_regs->NFCONT |= ( << ) | ( << ); /*使用nand_chip : nand_sacn*/
nand_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
if(IS_ERR(nand_mtd)) {
printk(KERN_ALERT"nand_mtd kzalloc error\n");
return -ENOMEM;
} nand_mtd->owner = THIS_MODULE;
nand_mtd->priv = chip; nand_scan(nand_mtd, ); /*添加分区*/
err = mtd_device_register(nand_mtd, mynand_partition_info, nbparts);
if(!err) {
printk(KERN_ALERT"add_mtd_partitions error\n");
return -EINVAL;
} return ; clk_err:
kfree(chip);
return err;
} static void __exit my_nand_exit(void)
{
mtd_device_unregister(nand_mtd);
iounmap(nand_regs);
iounmap(MP0_3CON);
kfree(nand_mtd);
kfree(chip);
} module_init(my_nand_init);
module_exit(my_nand_exit);
MODULE_LICENSE("GPL");