linux2.6.28 MTD 内存技术设备(块设备)platform driver源码分析

//drivers/mtd/nand/s3c_nand.c

module_init(s3c_nand_init);//模块初始化
static int __init s3c_nand_init(void)
{
printk(“S3C NAND Driver, © 2008 Samsung Electronics\n”);
platform_driver_register(&s3c6400_nand_driver);
platform_driver_register(&s3c6410_nand_driver);
}

drivers/mtd/nand/s3c_nand.c
platform平台总线驱动结构体
static struct platform_driver s3c6410_nand_driver = {
.probe = s3c6410_nand_probe,
.remove = s3c_nand_remove,
.suspend = s3c_nand_suspend,
.resume = s3c_nand_resume,
.driver = {
.name = “s3c6410-nand”,
.owner = THIS_MODULE,
},
};

drivers/mtd/nand/s3c_nand.c
static int s3c6410_nand_probe(struct platform_device dev)
{
return s3c_nand_probe(dev, TYPE_S3C6410);
}
///drivers/mtd/nand/s3c_nand.c
/
s3c_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 s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type)
    {
    //在Mach-smdk6410.c (linux2.6.28\arch\arm\mach-s3c6410)文件中,有个函数:smdk6410_machine_init
    //s3c_device_nand.dev.platform_data = &s3c_nand_mtd_part_info; nand有关
    struct s3c_nand_mtd_info *plat_info = pdev->dev.platform_data;
    struct mtd_partition *partition_info = (struct mtd_partition *)plat_info->partition;
    struct nand_chip *nand;
    struct resource *res;
    int err = 0;
    int ret = 0;
    int i, j, size;

#if defined(CONFIG_MTD_NAND_S3C_HWECC)
struct nand_flash_dev *type = NULL;
u_char tmp;
#endif

/* get the clock source and enable it */

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

clk_enable(s3c_nand.clk);

/* allocate and map the resource */

//得到I/O内存资源
/* currently we assume we have the one resource */
res = pdev->resource;
size = res->end - res->start + 1;
//I/O内存资源申请
s3c_nand.area = request_mem_region(res->start, size, pdev->name);

if (s3c_nand.area == NULL) {
    dev_err(&pdev->dev, "cannot reserve register region\n");
    err = -ENOENT;
    goto exit_error;
}

s3c_nand.cpu_type   = cpu_type;
s3c_nand.device     = &pdev->dev;

//将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问。
s3c_nand.regs = ioremap(res->start, size);

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

/* allocate memory for MTD device structure and private data */
s3c_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);

if (!s3c_mtd) {
    printk("Unable to allocate NAND MTD dev structure.\n");
    return -ENOMEM;
}

/* Get pointer to private data */

//kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); 跳过sizeof(struct mtd_info)个字节

nand = (struct nand_chip *) (&s3c_mtd[1]);

/* Initialize structures */
memset((char *) s3c_mtd, 0, sizeof(struct mtd_info));
memset((char *) nand, 0, sizeof(struct nand_chip));

/* Link the private data with the MTD structure */
s3c_mtd->priv = nand;

for (i = 0; i < plat_info->chip_nr; i++) {

//上面s3c_nand.regs = ioremap(res->start, size); 所以是nand的基地址
#define S3C_NFDATA S3C2410_NFREG(0x10)

图片

    nand->IO_ADDR_R        = (char *)(s3c_nand.regs + S3C_NFDATA);
    nand->IO_ADDR_W        = (char *)(s3c_nand.regs + S3C_NFDATA);
    nand->cmd_ctrl        = s3c_nand_hwcontrol;
    nand->dev_ready        = s3c_nand_device_ready;       
    nand->scan_bbt        = s3c_nand_scan_bbt;
    nand->options        = 0;

#if defined(CONFIG_MTD_NAND_S3C_CACHEDPROG)
nand->options |= NAND_CACHEPRG;
#endif

#if defined(CONFIG_MTD_NAND_S3C_HWECC)
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.hwctl = s3c_nand_enable_hwecc;
nand->ecc.calculate = s3c_nand_calculate_ecc;
nand->ecc.correct = s3c_nand_correct_data;

    s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
    s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
    s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);
    s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
    s3c_nand_device_ready(0);

    tmp = readb(nand->IO_ADDR_R); /* Maf. ID */ 制造商ID
    tmp = readb(nand->IO_ADDR_R); /* Device ID */设备ID

    for (j = 0; nand_flash_ids[j].name != NULL; j++) {
        if (tmp == nand_flash_ids[j].id) {
            type = &nand_flash_ids[j];
            break;
        }
    }

    if (!type) {
        printk("Unknown NAND Device.\n");
        goto exit_error;
    }
   
    nand->cellinfo = readb(nand->IO_ADDR_R);    /* the 3rd byte */
    tmp = readb(nand->IO_ADDR_R);            /* the 4th byte */

    if (!type->pagesize) {
        if (((nand->cellinfo >> 2) & 0x3) == 0) {
            nand_type = S3C_NAND_TYPE_SLC;               
            nand->ecc.size = 512;
            nand->ecc.bytes    = 4;

            if ((1024 << (tmp & 0x3)) > 512) {
                nand->ecc.read_page = s3c_nand_read_page_1bit;
                nand->ecc.write_page = s3c_nand_write_page_1bit;
                nand->ecc.read_oob = s3c_nand_read_oob_1bit;
                nand->ecc.write_oob = s3c_nand_write_oob_1bit;
                nand->ecc.layout = &s3c_nand_oob_64;
            } else {
                nand->ecc.layout = &s3c_nand_oob_16;
            }
        } else {
            nand_type = S3C_NAND_TYPE_MLC;
            nand->options |= NAND_NO_SUBPAGE_WRITE;    /* NOP = 1 if MLC */
            nand->ecc.read_page = s3c_nand_read_page_4bit;
            nand->ecc.write_page = s3c_nand_write_page_4bit;
            nand->ecc.size = 512;
            nand->ecc.bytes = 8;    /* really 7 bytes */
            nand->ecc.layout = &s3c_nand_oob_mlc_64;
        }
    } else {
        nand_type = S3C_NAND_TYPE_SLC;
        nand->ecc.size = 512;
        nand->cellinfo = 0;
        nand->ecc.bytes = 4;
        nand->ecc.layout = &s3c_nand_oob_16;
    }

    printk("S3C NAND Driver is using hardware ECC.\n");

#else
nand->ecc.mode = NAND_ECC_SOFT;//软件ECC
printk(“S3C NAND Driver is using software ECC.\n”);
#endif
if (nand_scan(s3c_mtd, 1)) {//以mtd_info为参数调用nand_scan()函数探测NAND Flash的存在
ret = -ENXIO;
goto exit_error;
}

    /* Register the partitions */

//如果要分区,则以mtd_info和mtd_partition为参 数调用add_mtd_partitions(),添加分区信息
add_mtd_partitions(s3c_mtd, partition_info, plat_info->mtd_part_nr);
}

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

exit_error:
kfree(s3c_mtd);

return ret;

}

/drivers/mtd/nand/s3c_nand.c
struct s3c_nand_info {
/* mtd info */
struct nand_hw_control controller;
struct s3c_nand_mtd_info *mtds;
struct s3c2410_platform_nand *platform;

/* device info */
struct device            *device;
struct resource            *area;
struct clk            *clk;
void __iomem            *regs;
void __iomem            *sel_reg;
int                sel_bit;
int                mtd_count;

enum s3c_cpu_type        cpu_type;

};
static struct s3c_nand_info s3c_nand;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xx-xx-xxx-xxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值