/* s3c2410_nand_probe
*
* called by device layer when it finds a device matching
* one our driver can handled. This code checks to see if
* it can allocate all necessary resources then calls the
* nand layer to look for devices
*/
static int s3c24xx_nand_probe(struct platform_device *pdev,
enum s3c_cpu_type cpu_type)
{
struct s3c2410_platform_nand *plat = to_nand_plat(pdev);//看下面to_nand_plat定义变知道是获取之前定义的单板nand平台数据
static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
{
return dev->dev.platform_data;
}
struct s3c2410_nand_info *info;//定义nand info指针
struct s3c2410_nand_mtd *nmtd;定义mtd指针
struct s3c2410_nand_set *sets;//定义启动指针
struct resource *res;//定义资源指针
/*一些变量的申明*/
int err = 0;
int size;
int nr_sets;
int setno;
pr_debug("s3c2410_nand_probe(%p)/n", pdev);
info = kmalloc(sizeof(*info), GFP_KERNEL);//申请内存
if (info == NULL) {
dev_err(&pdev->dev, "no memory for flash info/n");
err = -ENOMEM;
goto exit_error;
}
memset(info, 0, sizeof(*info));//初始化nand结构体
platform_set_drvdata(pdev, info);//建立驱动数据
spin_lock_init(&info->controller.lock);
init_waitqueue_head(&info->controller.wq);
/* 得到时钟资源并使能它*/
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);
/* 申请同时映射资源*/
res = pdev->resource;
size = res->end - res->start + 1;//资源大小
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;
}
/*初始化nand结构体*/
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);
/* 初始化硬件 */
err = s3c2410_nand_inithw(info);
if (err != 0)
goto exit_error;
sets = (plat != NULL) ? plat->sets : NULL;
nr_sets = (plat != NULL) ? plat->nr_sets : 1;
info->mtd_count = nr_sets;
/* 申请mtd信息*/
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);
/* 初始化所有可能芯片 */
nmtd = info->mtds;
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
pr_debug("initialising set %d (%p, info %p)/n", setno, nmtd, info);
s3c2410_nand_init_chip(info, nmtd, sets);
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);//注册nand
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:
s3c2410_nand_remove(pdev);
if (err == 0)
err = -EINVAL;
return err;
}