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
");
        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
");
        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
");
        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
");
        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");
原文地址:https://www.cnblogs.com/qigaohua/p/5507557.html