1. 程式人生 > >基於MTD的NANDFLASH裝置驅動底層實現原理分析

基於MTD的NANDFLASH裝置驅動底層實現原理分析

    enum s3c_cpu_type cpu_type;
    struct s3c2410_nand_info *info;
    struct s3c2410_nand_mtd *nmtd;
    struct s3c2410_nand_set *sets;
    struct resource *res;
    int err = 0;
    int size;
    int nr_sets;
    int setno;
    /*獲取CPU型別*/
    cpu_type = platform_get_device_id(pdev)->driver_data;

    pr_debug("s3c2410_nand_probe(%p)\n", pdev);
    /*為s3c2410_nand_info分配記憶體*/
    info = kmalloc(sizeof(*info), GFP_KERNEL);
    if (info == NULL) {
        dev_err(&pdev->dev, "no memory for flash info\n");
        err = -ENOMEM;
        goto exit_error;
    }
    /**初始化s3c2410_nand_info**/
    memset(info, 0, sizeof(*info));
    /**將nand裝置的資料資訊傳遞到系統平臺裝置中去**/
    platform_set_drvdata(pdev, info);
    /**初始化自旋鎖和等待佇列**/
    spin_lock_init(&info->controller.lock);
    init_waitqueue_head(&info->controller.wq);

    /* get the clock source and enable it */

    info->clk = clk_get(&pdev->dev, "nand");
    if (IS_ERR(info->clk)) {
        dev_err(&pdev->dev, "failed to get clock\n");
        err = -ENOENT;
        goto exit_error;
    }

    clk_enable(info->clk);//使能時鐘

    /* allocate and map the resource */
     
    /* currently we assume we have the one resource */
    res  = pdev->resource;
    size = res->end - res->start + 1;
    /**為資源申請IO記憶體**/
    info->area = request_mem_region(res->start, size, pdev->name);

    if (info->area == NULL) {
        dev_err(&pdev->dev, "cannot reserve register region\n");
        err = -ENOENT;
        goto exit_error;
    }
    /*****這都是給info這個結構的成員變數賦值啊*沒啥可說的,*/
    info->device     = &pdev->dev;
    info->platform   = plat;
    info->regs       = ioremap(res->start, size);
    info->cpu_type   = cpu_type;

    if (info->regs == NULL) {
        dev_err(&pdev->dev, "cannot reserve register region\n");
        err = -EIO;
        goto exit_error;
    }

    dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);

    /* initialise the hardware *//**解析c*/
    /**初始化硬體**/
    err = s3c2410_nand_inithw(info);
    if (err != 0)
        goto exit_error;
     /*struct s3c2410_platform_nand 中包含了一個struct s3c2410_nand_set *sets
    的成員變數 專門用來描述晶片資訊的**/
    sets = (plat != NULL) ? plat->sets : NULL;
    nr_sets = (plat != NULL) ? plat->nr_sets : 1;

    info->mtd_count = nr_sets;

    /* allocate our information */

    size = nr_sets * sizeof(*info->mtds);
    info->mtds = kmalloc(size, GFP_KERNEL);
    if (info->mtds == NULL) {
        dev_err(&pdev->dev, "failed to allocate mtd storage\n");
        err = -ENOMEM;
        goto exit_error;
    }

    memset(info->mtds, 0, size);

    /* initialise all possible chips */

    nmtd = info->mtds;

    for (setno = 0; setno < nr_sets; setno++, nmtd++) {
        pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info);
       /**nand_chip結構的初始化**見下一遍分析d)**/
        s3c2410_nand_init_chip(info, nmtd, sets);
        /**讀取晶片的ID**/
        nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
                         (sets) ? sets->nr_chips : 1);

        if (nmtd->scan_res == 0) {
            s3c2410_nand_update_chip(info, nmtd);
            nand_scan_tail(&nmtd->mtd);
            s3c2410_nand_add_partition(info, nmtd, sets);
        }

        if (sets != NULL)
            sets++;
    }

    err = s3c2410_nand_cpufreq_register(info);
    if (err < 0) {
        dev_err(&pdev->dev, "failed to init cpufreq support\n");
        goto exit_error;
    }

    if (allow_clk_stop(info)) {
        dev_info(&pdev->dev, "clock idle support enabled\n");
        clk_disable(info->clk);
    }

    pr_debug("initialised ok\n");
    return 0;

 exit_error:
    s3c24xx_nand_remove(pdev);

    if (err == 0)
        err = -EINVAL;
    return err;
}