Smart210学习记录----nand flash驱动
【详解】如何编写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 = 7; struct mtd_partition mynand_partition_info[] = { { .name = "misc", .offset = (768*SZ_1K), /* for bootloader */ .size = (256*SZ_1K), .mask_flags = MTD_CAP_NANDFLASH, }, { .name = "recovery", .offset = MTDPART_OFS_APPEND, .size = (5*SZ_1M), }, { .name = "kernel", .offset = MTDPART_OFS_APPEND, .size = (5*SZ_1M), }, { .name = "ramdisk", .offset = MTDPART_OFS_APPEND, .size = (3*SZ_1M), }, { .name = "system", .offset = MTDPART_OFS_APPEND, .size = (110*SZ_1M), }, { .name = "cache", .offset = MTDPART_OFS_APPEND, .size = (80*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 == -1) { /*取消片选*/ nand_regs->NFCONT |= 1 << 1; } else { /*使能片选*/ nand_regs->NFCONT &= ~(1 << 1); } } 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 & (1 << 0); } 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, 4); /*使能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 << 12) | (TWRPH0 << 8) | (TWRPH1 << 4); //1 = 5 address cycle ,其他默认 nand_regs->NFCONF |= 1 << 1; //1 = Force nRCS[0] to High (Disable chip select) //1 = Enable NAND Flash Controller nand_regs->NFCONT |= (1 << 0) | (1 << 1); /*使用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, 1); /*添加分区*/ err = mtd_device_register(nand_mtd, mynand_partition_info, nbparts); if(!err) { printk(KERN_ALERT"add_mtd_partitions error\n"); return -EINVAL; } return 0; 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");