基於MTD的NANDFLASH裝置驅動底層實現原理分析
阿新 • • 發佈:2019-02-07
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;
}
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;
}