⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2410.c

📁 老版本的mtd-snap
💻 C
📖 第 1 页 / 共 2 页
字号:
	writel(ctrl, info->regs + S3C2410_NFCONF);}static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode){	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);	unsigned long ctrl;	ctrl = readl(info->regs + S3C2440_NFCONT);	writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);}static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,				      const u_char *dat, u_char *ecc_code){	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);	ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);	ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);	ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);	pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n",		 ecc_code[0], ecc_code[1], ecc_code[2]);	return 0;}static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd,				      const u_char *dat, u_char *ecc_code){	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);	unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);	ecc_code[0] = ecc;	ecc_code[1] = ecc >> 8;	ecc_code[2] = ecc >> 16;	pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n",		 ecc_code[0], ecc_code[1], ecc_code[2]);	return 0;}/* over-ride the standard functions for a little more speed. We can * use read/write block to move the data buffers to/from the controller*/static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len){	struct nand_chip *this = mtd->priv;	readsb(this->IO_ADDR_R, buf, len);}static void s3c2410_nand_write_buf(struct mtd_info *mtd,				   const u_char *buf, int len){	struct nand_chip *this = mtd->priv;	writesb(this->IO_ADDR_W, buf, len);}/* device management functions */static int s3c2410_nand_remove(struct device *dev){	struct s3c2410_nand_info *info = to_nand_info(dev);	dev_set_drvdata(dev, NULL);	if (info == NULL) 		return 0;	/* first thing we need to do is release all our mtds	 * and their partitions, then go through freeing the	 * resources used 	 */		if (info->mtds != NULL) {		struct s3c2410_nand_mtd *ptr = info->mtds;		int mtdno;		for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {			pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);			nand_release(&ptr->mtd);		}		kfree(info->mtds);	}	/* free the common resources */	if (info->clk != NULL && !IS_ERR(info->clk)) {		clk_disable(info->clk);		clk_unuse(info->clk);		clk_put(info->clk);	}	if (info->regs != NULL) {		iounmap(info->regs);		info->regs = NULL;	}	if (info->area != NULL) {		release_resource(info->area);		kfree(info->area);		info->area = NULL;	}	kfree(info);	return 0;}#ifdef CONFIG_MTD_PARTITIONSstatic int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,				      struct s3c2410_nand_mtd *mtd,				      struct s3c2410_nand_set *set){	if (set == NULL)		return add_mtd_device(&mtd->mtd);	if (set->nr_partitions > 0 && set->partitions != NULL) {		return add_mtd_partitions(&mtd->mtd,					  set->partitions,					  set->nr_partitions);	}	return add_mtd_device(&mtd->mtd);}#elsestatic int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,				      struct s3c2410_nand_mtd *mtd,				      struct s3c2410_nand_set *set){	return add_mtd_device(&mtd->mtd);}#endif/* s3c2410_nand_init_chip * * init a single instance of an chip */static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,				   struct s3c2410_nand_mtd *nmtd,				   struct s3c2410_nand_set *set){	struct nand_chip *chip = &nmtd->chip;	chip->IO_ADDR_R	   = info->regs + S3C2410_NFDATA;	chip->IO_ADDR_W    = info->regs + S3C2410_NFDATA;	chip->hwcontrol    = s3c2410_nand_hwcontrol;	chip->dev_ready    = s3c2410_nand_devready;	chip->write_buf    = s3c2410_nand_write_buf;	chip->read_buf     = s3c2410_nand_read_buf;	chip->select_chip  = s3c2410_nand_select_chip;	chip->chip_delay   = 50;	chip->priv	   = nmtd;	chip->options	   = 0;	chip->controller   = &info->controller;	if (info->is_s3c2440) {		chip->IO_ADDR_R	 = info->regs + S3C2440_NFDATA;		chip->IO_ADDR_W  = info->regs + S3C2440_NFDATA;		chip->hwcontrol  = s3c2440_nand_hwcontrol;	}	nmtd->info	   = info;	nmtd->mtd.priv	   = chip;	nmtd->set	   = set;	if (hardware_ecc) {		chip->correct_data  = s3c2410_nand_correct_data;		chip->enable_hwecc  = s3c2410_nand_enable_hwecc;		chip->calculate_ecc = s3c2410_nand_calculate_ecc;		chip->eccmode	    = NAND_ECC_HW3_512;		chip->autooob       = &nand_hw_eccoob;		if (info->is_s3c2440) {			chip->enable_hwecc  = s3c2440_nand_enable_hwecc;			chip->calculate_ecc = s3c2440_nand_calculate_ecc;		}	} else {		chip->eccmode	    = NAND_ECC_SOFT;	}}/* 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 device *dev, int is_s3c2440){	struct platform_device *pdev = to_platform_device(dev);	struct s3c2410_platform_nand *plat = to_nand_plat(dev);	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", dev);	info = kmalloc(sizeof(*info), GFP_KERNEL);	if (info == NULL) {		printk(KERN_ERR PFX "no memory for flash info\n");		err = -ENOMEM;		goto exit_error;	}	memzero(info, sizeof(*info));	dev_set_drvdata(dev, info);	spin_lock_init(&info->controller.lock);	init_waitqueue_head(&info->controller.wq);	/* get the clock source and enable it */	info->clk = clk_get(dev, "nand");	if (IS_ERR(info->clk)) {		printk(KERN_ERR PFX "failed to get clock");		err = -ENOENT;		goto exit_error;	}	clk_use(info->clk);	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;	info->area = request_mem_region(res->start, size, pdev->name);	if (info->area == NULL) {		printk(KERN_ERR PFX "cannot reserve register region\n");		err = -ENOENT;		goto exit_error;	}	info->device     = dev;	info->platform   = plat;	info->regs       = ioremap(res->start, size);	info->is_s3c2440 = is_s3c2440;	if (info->regs == NULL) {		printk(KERN_ERR PFX "cannot reserve register region\n");		err = -EIO;		goto exit_error;	}			printk(KERN_INFO PFX "mapped registers at %p\n", info->regs);	/* initialise the hardware */	err = s3c2410_nand_inithw(info, dev);	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;	/* allocate our information */	size = nr_sets * sizeof(*info->mtds);	info->mtds = kmalloc(size, GFP_KERNEL);	if (info->mtds == NULL) {		printk(KERN_ERR PFX "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);				s3c2410_nand_init_chip(info, nmtd, sets);		nmtd->scan_res = nand_scan(&nmtd->mtd,					   (sets) ? sets->nr_chips : 1);		if (nmtd->scan_res == 0) {			s3c2410_nand_add_partition(info, nmtd, sets);		}		if (sets != NULL)			sets++;	}		pr_debug("initialised ok\n");	return 0; exit_error:	s3c2410_nand_remove(dev);	if (err == 0)		err = -EINVAL;	return err;}/* driver device registration */static int s3c2410_nand_probe(struct device *dev){	return s3c24xx_nand_probe(dev, 0);}static int s3c2440_nand_probe(struct device *dev){	return s3c24xx_nand_probe(dev, 1);}static struct device_driver s3c2410_nand_driver = {	.name		= "s3c2410-nand",	.bus		= &platform_bus_type,	.probe		= s3c2410_nand_probe,	.remove		= s3c2410_nand_remove,};static struct device_driver s3c2440_nand_driver = {	.name		= "s3c2440-nand",	.bus		= &platform_bus_type,	.probe		= s3c2440_nand_probe,	.remove		= s3c2410_nand_remove,};static int __init s3c2410_nand_init(void){	printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");	driver_register(&s3c2440_nand_driver);	return driver_register(&s3c2410_nand_driver);}static void __exit s3c2410_nand_exit(void){	driver_unregister(&s3c2440_nand_driver);	driver_unregister(&s3c2410_nand_driver);}module_init(s3c2410_nand_init);module_exit(s3c2410_nand_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");MODULE_DESCRIPTION("S3C24XX MTD NAND driver");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -