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

📄 omap2.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
	INIT_COMPLETION(c->dma_done);	omap_start_dma(c->dma_channel);	timeout = jiffies + msecs_to_jiffies(20);	done = &c->dma_done.done;	while (time_before(jiffies, timeout))		if (*done)			break;	dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);	if (!*done) {		dev_err(&c->pdev->dev, "timeout waiting for DMA\n");		goto out_copy;	}	return 0;out_copy:	memcpy(this->base + bram_offset, buf, count);	return 0;}#elseint omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,				 unsigned char *buffer, int offset,				 size_t count);int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,				  const unsigned char *buffer,				  int offset, size_t count);#endif#if defined(CONFIG_ARCH_OMAP2) || defined(MULTI_OMAP2)static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,					unsigned char *buffer, int offset,					size_t count){	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);	struct onenand_chip *this = mtd->priv;	dma_addr_t dma_src, dma_dst;	int bram_offset;	bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;	/* DMA is not used.  Revisit PM requirements before enabling it. */	if (1 || (c->dma_channel < 0) ||	    ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) ||	    (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) {		memcpy(buffer, (__force void *)(this->base + bram_offset),		       count);		return 0;	}	dma_src = c->phys_base + bram_offset;	dma_dst = dma_map_single(&c->pdev->dev, buffer, count,				 DMA_FROM_DEVICE);	if (dma_mapping_error(&c->pdev->dev, dma_dst)) {		dev_err(&c->pdev->dev,			"Couldn't DMA map a %d byte buffer\n",			count);		return -1;	}	omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,				     count / 4, 1, 0, 0, 0);	omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,				dma_src, 0, 0);	omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,				 dma_dst, 0, 0);	INIT_COMPLETION(c->dma_done);	omap_start_dma(c->dma_channel);	wait_for_completion(&c->dma_done);	dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);	return 0;}static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,					 const unsigned char *buffer,					 int offset, size_t count){	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);	struct onenand_chip *this = mtd->priv;	dma_addr_t dma_src, dma_dst;	int bram_offset;	bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;	/* DMA is not used.  Revisit PM requirements before enabling it. */	if (1 || (c->dma_channel < 0) ||	    ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) ||	    (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) {		memcpy((__force void *)(this->base + bram_offset), buffer,		       count);		return 0;	}	dma_src = dma_map_single(&c->pdev->dev, (void *) buffer, count,				 DMA_TO_DEVICE);	dma_dst = c->phys_base + bram_offset;	if (dma_mapping_error(&c->pdev->dev, dma_dst)) {		dev_err(&c->pdev->dev,			"Couldn't DMA map a %d byte buffer\n",			count);		return -1;	}	omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S16,				     count / 2, 1, 0, 0, 0);	omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,				dma_src, 0, 0);	omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,				 dma_dst, 0, 0);	INIT_COMPLETION(c->dma_done);	omap_start_dma(c->dma_channel);	wait_for_completion(&c->dma_done);	dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);	return 0;}#elseint omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,				 unsigned char *buffer, int offset,				 size_t count);int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,				  const unsigned char *buffer,				  int offset, size_t count);#endifstatic struct platform_driver omap2_onenand_driver;static int __adjust_timing(struct device *dev, void *data){	int ret = 0;	struct omap2_onenand *c;	c = dev_get_drvdata(dev);	BUG_ON(c->setup == NULL);	/* DMA is not in use so this is all that is needed */	/* Revisit for OMAP3! */	ret = c->setup(c->onenand.base, c->freq);	return ret;}int omap2_onenand_rephase(void){	return driver_for_each_device(&omap2_onenand_driver.driver, NULL,				      NULL, __adjust_timing);}static void __devexit omap2_onenand_shutdown(struct platform_device *pdev){	struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);	/* With certain content in the buffer RAM, the OMAP boot ROM code	 * can recognize the flash chip incorrectly. Zero it out before	 * soft reset.	 */	memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);}static int __devinit omap2_onenand_probe(struct platform_device *pdev){	struct omap_onenand_platform_data *pdata;	struct omap2_onenand *c;	int r;	pdata = pdev->dev.platform_data;	if (pdata == NULL) {		dev_err(&pdev->dev, "platform data missing\n");		return -ENODEV;	}	c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL);	if (!c)		return -ENOMEM;	init_completion(&c->irq_done);	init_completion(&c->dma_done);	c->gpmc_cs = pdata->cs;	c->gpio_irq = pdata->gpio_irq;	c->dma_channel = pdata->dma_channel;	if (c->dma_channel < 0) {		/* if -1, don't use DMA */		c->gpio_irq = 0;	}	r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base);	if (r < 0) {		dev_err(&pdev->dev, "Cannot request GPMC CS\n");		goto err_kfree;	}	if (request_mem_region(c->phys_base, ONENAND_IO_SIZE,			       pdev->dev.driver->name) == NULL) {		dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, "			"size: 0x%x\n",	c->phys_base, ONENAND_IO_SIZE);		r = -EBUSY;		goto err_free_cs;	}	c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE);	if (c->onenand.base == NULL) {		r = -ENOMEM;		goto err_release_mem_region;	}	if (pdata->onenand_setup != NULL) {		r = pdata->onenand_setup(c->onenand.base, c->freq);		if (r < 0) {			dev_err(&pdev->dev, "Onenand platform setup failed: "				"%d\n", r);			goto err_iounmap;		}		c->setup = pdata->onenand_setup;	}	if (c->gpio_irq) {		if ((r = omap_request_gpio(c->gpio_irq)) < 0) {			dev_err(&pdev->dev,  "Failed to request GPIO%d for "				"OneNAND\n", c->gpio_irq);			goto err_iounmap;	}	omap_set_gpio_direction(c->gpio_irq, 1);	if ((r = request_irq(OMAP_GPIO_IRQ(c->gpio_irq),			     omap2_onenand_interrupt, IRQF_TRIGGER_RISING,			     pdev->dev.driver->name, c)) < 0)		goto err_release_gpio;	}	if (c->dma_channel >= 0) {		r = omap_request_dma(0, pdev->dev.driver->name,				     omap2_onenand_dma_cb, (void *) c,				     &c->dma_channel);		if (r == 0) {			omap_set_dma_write_mode(c->dma_channel,						OMAP_DMA_WRITE_NON_POSTED);			omap_set_dma_src_data_pack(c->dma_channel, 1);			omap_set_dma_src_burst_mode(c->dma_channel,						    OMAP_DMA_DATA_BURST_8);			omap_set_dma_dest_data_pack(c->dma_channel, 1);			omap_set_dma_dest_burst_mode(c->dma_channel,						     OMAP_DMA_DATA_BURST_8);		} else {			dev_info(&pdev->dev,				 "failed to allocate DMA for OneNAND, "				 "using PIO instead\n");			c->dma_channel = -1;		}	}	dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual "		 "base %p\n", c->gpmc_cs, c->phys_base,		 c->onenand.base);	c->pdev = pdev;	c->mtd.name = pdev->dev.bus_id;	c->mtd.priv = &c->onenand;	c->mtd.owner = THIS_MODULE;	if (c->dma_channel >= 0) {		struct onenand_chip *this = &c->onenand;		this->wait = omap2_onenand_wait;		if (cpu_is_omap34xx()) {			this->read_bufferram = omap3_onenand_read_bufferram;			this->write_bufferram = omap3_onenand_write_bufferram;		} else {			this->read_bufferram = omap2_onenand_read_bufferram;			this->write_bufferram = omap2_onenand_write_bufferram;		}	}	if ((r = onenand_scan(&c->mtd, 1)) < 0)		goto err_release_dma;	switch ((c->onenand.version_id >> 4) & 0xf) {	case 0:		c->freq = 40;		break;	case 1:		c->freq = 54;		break;	case 2:		c->freq = 66;		break;	case 3:		c->freq = 83;		break;	}#ifdef CONFIG_MTD_PARTITIONS	if (pdata->parts != NULL)		r = add_mtd_partitions(&c->mtd, pdata->parts,				       pdata->nr_parts);	else#endif		r = add_mtd_device(&c->mtd);	if (r < 0)		goto err_release_onenand;	platform_set_drvdata(pdev, c);	return 0;err_release_onenand:	onenand_release(&c->mtd);err_release_dma:	if (c->dma_channel != -1)		omap_free_dma(c->dma_channel);	if (c->gpio_irq)		free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);err_release_gpio:	if (c->gpio_irq)		omap_free_gpio(c->gpio_irq);err_iounmap:	iounmap(c->onenand.base);err_release_mem_region:	release_mem_region(c->phys_base, ONENAND_IO_SIZE);err_free_cs:	gpmc_cs_free(c->gpmc_cs);err_kfree:	kfree(c);	return r;}static int __devexit omap2_onenand_remove(struct platform_device *pdev){	struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);	BUG_ON(c == NULL);#ifdef CONFIG_MTD_PARTITIONS	if (c->parts)		del_mtd_partitions(&c->mtd);	else		del_mtd_device(&c->mtd);#else	del_mtd_device(&c->mtd);#endif	onenand_release(&c->mtd);	if (c->dma_channel != -1)		omap_free_dma(c->dma_channel);	omap2_onenand_shutdown(pdev);	platform_set_drvdata(pdev, NULL);	if (c->gpio_irq) {		free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);		omap_free_gpio(c->gpio_irq);	}	iounmap(c->onenand.base);	release_mem_region(c->phys_base, ONENAND_IO_SIZE);	kfree(c);	return 0;}static struct platform_driver omap2_onenand_driver = {	.probe		= omap2_onenand_probe,	.remove		= omap2_onenand_remove,	.shutdown	= omap2_onenand_shutdown,	.driver		= {		.name	= DRIVER_NAME,		.owner  = THIS_MODULE,	},};static int __init omap2_onenand_init(void){	printk(KERN_INFO "OneNAND driver initializing\n");	return platform_driver_register(&omap2_onenand_driver);}static void __exit omap2_onenand_exit(void){	platform_driver_unregister(&omap2_onenand_driver);}module_init(omap2_onenand_init);module_exit(omap2_onenand_exit);MODULE_ALIAS(DRIVER_NAME);MODULE_LICENSE("GPL");MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>");MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3");

⌨️ 快捷键说明

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