Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3010908
  • 博文数量: 674
  • 博客积分: 17881
  • 博客等级: 上将
  • 技术积分: 4849
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 10:15
文章分类

全部博文(674)

文章存档

2013年(34)

2012年(146)

2011年(197)

2010年(297)

分类: LINUX

2010-04-04 13:36:17

NAND设备及资源的定义和注册

我们通过MACHINE_START定义了smdk2410machine_desc对象,这个对象里面有个init_machine的函数指针, 这里指向smdk_machine_init(), 我们的NAND设备就是在这个函数里注册到系统的.

void __init smdk_machine_init(void)

{

   ….

   s3c_device_nand.dev.platform_data = &smdk_nand_info;

   platform_add_device(smdk_devs, ARRAY_SIZE(smdk_devs));  //这里就把设备注册到系统里去了

  

}

Static struct platform_device __initdata *smdk_devs[] =

{

   &s3c_device_nand,    //这样在上面的函数里我们的nand设备就注册好了.

   ...   

}

其他设备我们也可以在这里注册进系统.

struct platform_device s3c_device_nand =

{

   .name = “s3c2410-nand”,  /*名字很重要*/

   .id = -1,

   . num_resources = ARRAY_SIZE(s3c_nand_resource),

   .resource = s3c_nand_resource,  //这个是NAND占用的资源.

};

Static struct s3c2410_platform_nand smdk_nand_info = {

     .tacks = 20,      /*datasheet上有描述*/

     .twrph0 = 60,    /*datasheet上有描述*/

     .twrph1 = 20,    /*datasheet上有描述*/

     .nr_sets = ARRAY_SIZE(smdk_nand_sets),

     .sets = smdk_nand_sets 

}

static struct s3c2410_nand_set smdk_nand_sets[] = {

    [0] = {

        .name       = "NAND",

        .nr_chips   = 1,

        .nr_partitions  = ARRAY_SIZE(smdk_default_nand_part),

        .partitions = smdk_default_nand_part,   /*nand的分区信息*/

    },

};

/*分区信息, 我们可以在这里修改分区内容*/

static struct mtd_partition smdk_default_nand_part[] = {

    [0] = {

        .name   = "Boot Agent",

        .size   = SZ_16K,

        .offset = 0,

    },

    [1] = {

        .name   = "S3C2410 flash partition 1",

        .offset = 0,

        .size   = SZ_2M,

    },

    [2] = {

        .name   = "S3C2410 flash partition 2",

        .offset = SZ_4M,

        .size   = SZ_4M,

    },

    [3] = {

        .name   = "S3C2410 flash partition 3",

        .offset = SZ_8M,

        .size   = SZ_2M,

    },

    [4] = {

        .name   = "S3C2410 flash partition 4",

        .offset = SZ_1M * 10,

        .size   = SZ_4M,

    },

    [5] = {

        .name   = "S3C2410 flash partition 5",

        .offset = SZ_1M * 14,

        .size   = SZ_1M * 10,

    },

    [6] = {

        .name   = "S3C2410 flash partition 6",

        .offset = SZ_1M * 24,

        .size   = SZ_1M * 24,

    },

    [7] = {

        .name   = "S3C2410 flash partition 7",

        .offset = SZ_1M * 48,

        .size   = SZ_16M,

    }

};

这样NAND设备(连同设备的详细信息)就注册进了系统, 以后在nand的驱动注册后就会probe到并使用这里定义的资源信息.

 

NAND驱动流程

   2410的驱动实现在driver\mtd\nand\S3c2410.c

   首先和其他驱动一样先通过module_init(), module_exit()注册一个初始化/卸载函数,

module_init(s3c2410_nand_init);

module_exit(s3c2410_nand_exit);

系统初始化时该函数被调用

 static int __init s3c2410_nand_init(void)

{

    printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");

 

    platform_driver_register(&s3c2412_nand_driver);  /*注册nand驱动*/

    platform_driver_register(&s3c2440_nand_driver);  /*注册nand驱动*/

    return platform_driver_register(&s3c2410_nand_driver);  /*注册nand驱动*/

}

从上面可以看到我们注册了3个驱动程序, 但在系统probe时它只会匹配到s3c2410_nand_driver的驱动, 因为各个驱动的名字是不一样的, 而系统是安名字来probe.

static struct platform_driver s3c2410_nand_driver = {

    .probe      = s3c2410_nand_probe,

    .remove     = s3c2410_nand_remove,

    .suspend    = s3c24xx_nand_suspend,

    .resume     = s3c24xx_nand_resume,

    .driver     = {

        .name   = "s3c2410-nand",  /*这里的名字一定要与设备定义的名字相同*/

        .owner  = THIS_MODULE,

    },

};

当系统probe到我们刚才注册的nand设备后即调用s3c2410_nand_probe函数

static int s3c2410_nand_probe(struct platform_device *dev)

{

    return s3c24xx_nand_probe(dev, TYPE_S3C2410);

}

static int s3c24xx_nand_probe(struct platform_device *pdev, /*nand设备,前面已经列出*/

                              enum s3c_cpu_type cpu_type /*TYPE_S3C2410*/)

{

    struct s3c2410_platform_nand *plat = to_nand_plat(pdev);/*对照前面列出的设备定义来看*/

    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;

 

    pr_debug("s3c2410_nand_probe(%p)\n", pdev);

 

/*该变量用来保存nand详细信息,以后访问nand信息都将从这个变量里得到*/

    info = kmalloc(sizeof(*info), GFP_KERNEL);

if (info == NULL) {

        dev_err(&pdev->dev, "no memory for flash info\n");

        err = -ENOMEM;

        goto exit_error;

    }

 

    memzero(info, sizeof(*info));

    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");  /*获取用于nandclock(nand也要时钟信号的哦)*/

    if (IS_ERR(info->clk)) {

        dev_err(&pdev->dev, "failed to get clock");

        err = -ENOENT;

        goto exit_error;

    }

 

    clk_enable(info->clk); /*使能该clock,实际上就是设置CLKCON的第四位(详见2410datasheet)*/

 

    /* allocate and map the resource */

    /* currently we assume we have the one resource */

    res  = pdev->resource;  /*nand资源,见前面的定义*/

    size = res->end - res->start + 1;

 

     /*

* 请求指定的memory区域(实际上是nand的寄存器区域), 这是物理内存, 实际上只是检测该区域

* 是否空闲的

*/

    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;

/*虚实地址映射,以后程序里就可以直接访问nand的寄存器了*/

    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 */

 

    err = s3c2410_nand_inithw(info, pdev);  /*初始化nand硬件设备*/

    if (err != 0)

        goto exit_error;

 

    /*接下来是MTD方面的初始化*/

    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;

    }

 

    memzero(info->mtds, 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实例*/

        s3c2410_nand_init_chip(info, nmtd, sets);

       

        /*初始化mtd?

阅读(789) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~