diff options
Diffstat (limited to 'drivers/mtd/nand/gpio.c')
| -rw-r--r-- | drivers/mtd/nand/gpio.c | 231 | 
1 files changed, 61 insertions, 170 deletions
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 89065dd83d6..e826f898241 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -17,6 +17,7 @@   */  #include <linux/kernel.h> +#include <linux/err.h>  #include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h> @@ -86,59 +87,11 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)  	gpio_nand_dosync(gpiomtd);  } -static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len) -{ -	struct nand_chip *this = mtd->priv; - -	iowrite8_rep(this->IO_ADDR_W, buf, len); -} - -static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len) -{ -	struct nand_chip *this = mtd->priv; - -	ioread8_rep(this->IO_ADDR_R, buf, len); -} - -static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf, -				 int len) -{ -	struct nand_chip *this = mtd->priv; - -	if (IS_ALIGNED((unsigned long)buf, 2)) { -		iowrite16_rep(this->IO_ADDR_W, buf, len>>1); -	} else { -		int i; -		unsigned short *ptr = (unsigned short *)buf; - -		for (i = 0; i < len; i += 2, ptr++) -			writew(*ptr, this->IO_ADDR_W); -	} -} - -static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len) -{ -	struct nand_chip *this = mtd->priv; - -	if (IS_ALIGNED((unsigned long)buf, 2)) { -		ioread16_rep(this->IO_ADDR_R, buf, len>>1); -	} else { -		int i; -		unsigned short *ptr = (unsigned short *)buf; - -		for (i = 0; i < len; i += 2, ptr++) -			*ptr = readw(this->IO_ADDR_R); -	} -} -  static int gpio_nand_devready(struct mtd_info *mtd)  {  	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); -	if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) -		return gpio_get_value(gpiomtd->plat.gpio_rdy); - -	return 1; +	return gpio_get_value(gpiomtd->plat.gpio_rdy);  }  #ifdef CONFIG_OF @@ -153,6 +106,9 @@ static int gpio_nand_get_config_of(const struct device *dev,  {  	u32 val; +	if (!dev->of_node) +		return -ENODEV; +  	if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {  		if (val == 2) {  			plat->options |= NAND_BUSWIDTH_16; @@ -211,8 +167,8 @@ static inline int gpio_nand_get_config(const struct device *dev,  	if (!ret)  		return ret; -	if (dev->platform_data) { -		memcpy(plat, dev->platform_data, sizeof(*plat)); +	if (dev_get_platdata(dev)) { +		memcpy(plat, dev_get_platdata(dev), sizeof(*plat));  		return 0;  	} @@ -230,145 +186,100 @@ gpio_nand_get_io_sync(struct platform_device *pdev)  	return platform_get_resource(pdev, IORESOURCE_MEM, 1);  } -static int gpio_nand_remove(struct platform_device *dev) +static int gpio_nand_remove(struct platform_device *pdev)  { -	struct gpiomtd *gpiomtd = platform_get_drvdata(dev); -	struct resource *res; +	struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);  	nand_release(&gpiomtd->mtd_info); -	res = gpio_nand_get_io_sync(dev); -	iounmap(gpiomtd->io_sync); -	if (res) -		release_mem_region(res->start, resource_size(res)); - -	res = platform_get_resource(dev, IORESOURCE_MEM, 0); -	iounmap(gpiomtd->nand_chip.IO_ADDR_R); -	release_mem_region(res->start, resource_size(res)); -  	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))  		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);  	gpio_set_value(gpiomtd->plat.gpio_nce, 1); -	gpio_free(gpiomtd->plat.gpio_cle); -	gpio_free(gpiomtd->plat.gpio_ale); -	gpio_free(gpiomtd->plat.gpio_nce); -	if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) -		gpio_free(gpiomtd->plat.gpio_nwp); -	if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) -		gpio_free(gpiomtd->plat.gpio_rdy); -  	return 0;  } -static void __iomem *request_and_remap(struct resource *res, size_t size, -					const char *name, int *err) -{ -	void __iomem *ptr; - -	if (!request_mem_region(res->start, resource_size(res), name)) { -		*err = -EBUSY; -		return NULL; -	} - -	ptr = ioremap(res->start, size); -	if (!ptr) { -		release_mem_region(res->start, resource_size(res)); -		*err = -ENOMEM; -	} -	return ptr; -} - -static int gpio_nand_probe(struct platform_device *dev) +static int gpio_nand_probe(struct platform_device *pdev)  {  	struct gpiomtd *gpiomtd; -	struct nand_chip *this; -	struct resource *res0, *res1; +	struct nand_chip *chip; +	struct resource *res;  	struct mtd_part_parser_data ppdata = {};  	int ret = 0; -	if (!dev->dev.of_node && !dev->dev.platform_data) -		return -EINVAL; - -	res0 = platform_get_resource(dev, IORESOURCE_MEM, 0); -	if (!res0) +	if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev))  		return -EINVAL; -	gpiomtd = devm_kzalloc(&dev->dev, sizeof(*gpiomtd), GFP_KERNEL); -	if (gpiomtd == NULL) { -		dev_err(&dev->dev, "failed to create NAND MTD\n"); +	gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL); +	if (!gpiomtd) { +		dev_err(&pdev->dev, "failed to create NAND MTD\n");  		return -ENOMEM;  	} -	this = &gpiomtd->nand_chip; -	this->IO_ADDR_R = request_and_remap(res0, 2, "NAND", &ret); -	if (!this->IO_ADDR_R) { -		dev_err(&dev->dev, "unable to map NAND\n"); -		goto err_map; -	} +	chip = &gpiomtd->nand_chip; -	res1 = gpio_nand_get_io_sync(dev); -	if (res1) { -		gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret); -		if (!gpiomtd->io_sync) { -			dev_err(&dev->dev, "unable to map sync NAND\n"); -			goto err_sync; -		} +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(chip->IO_ADDR_R)) +		return PTR_ERR(chip->IO_ADDR_R); + +	res = gpio_nand_get_io_sync(pdev); +	if (res) { +		gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res); +		if (IS_ERR(gpiomtd->io_sync)) +			return PTR_ERR(gpiomtd->io_sync);  	} -	ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat); +	ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat);  	if (ret) -		goto err_nce; +		return ret; -	ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); +	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, "NAND NCE");  	if (ret) -		goto err_nce; +		return ret;  	gpio_direction_output(gpiomtd->plat.gpio_nce, 1); +  	if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) { -		ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP"); +		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp, +					"NAND NWP");  		if (ret) -			goto err_nwp; -		gpio_direction_output(gpiomtd->plat.gpio_nwp, 1); +			return ret;  	} -	ret = gpio_request(gpiomtd->plat.gpio_ale, "NAND ALE"); + +	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE");  	if (ret) -		goto err_ale; +		return ret;  	gpio_direction_output(gpiomtd->plat.gpio_ale, 0); -	ret = gpio_request(gpiomtd->plat.gpio_cle, "NAND CLE"); + +	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE");  	if (ret) -		goto err_cle; +		return ret;  	gpio_direction_output(gpiomtd->plat.gpio_cle, 0); +  	if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) { -		ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY"); +		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy, +					"NAND RDY");  		if (ret) -			goto err_rdy; +			return ret;  		gpio_direction_input(gpiomtd->plat.gpio_rdy); +		chip->dev_ready = gpio_nand_devready;  	} +	chip->IO_ADDR_W		= chip->IO_ADDR_R; +	chip->ecc.mode		= NAND_ECC_SOFT; +	chip->options		= gpiomtd->plat.options; +	chip->chip_delay	= gpiomtd->plat.chip_delay; +	chip->cmd_ctrl		= gpio_nand_cmd_ctrl; -	this->IO_ADDR_W  = this->IO_ADDR_R; -	this->ecc.mode   = NAND_ECC_SOFT; -	this->options    = gpiomtd->plat.options; -	this->chip_delay = gpiomtd->plat.chip_delay; - -	/* install our routines */ -	this->cmd_ctrl   = gpio_nand_cmd_ctrl; -	this->dev_ready  = gpio_nand_devready; +	gpiomtd->mtd_info.priv	= chip; +	gpiomtd->mtd_info.owner	= THIS_MODULE; -	if (this->options & NAND_BUSWIDTH_16) { -		this->read_buf   = gpio_nand_readbuf16; -		this->write_buf  = gpio_nand_writebuf16; -	} else { -		this->read_buf   = gpio_nand_readbuf; -		this->write_buf  = gpio_nand_writebuf; -	} +	platform_set_drvdata(pdev, gpiomtd); -	/* set the mtd private data for the nand driver */ -	gpiomtd->mtd_info.priv = this; -	gpiomtd->mtd_info.owner = THIS_MODULE; +	if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) +		gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);  	if (nand_scan(&gpiomtd->mtd_info, 1)) { -		dev_err(&dev->dev, "no nand chips found?\n");  		ret = -ENXIO;  		goto err_wp;  	} @@ -377,38 +288,17 @@ static int gpio_nand_probe(struct platform_device *dev)  		gpiomtd->plat.adjust_parts(&gpiomtd->plat,  					   gpiomtd->mtd_info.size); -	ppdata.of_node = dev->dev.of_node; +	ppdata.of_node = pdev->dev.of_node;  	ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,  					gpiomtd->plat.parts,  					gpiomtd->plat.num_parts); -	if (ret) -		goto err_wp; -	platform_set_drvdata(dev, gpiomtd); - -	return 0; +	if (!ret) +		return 0;  err_wp:  	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))  		gpio_set_value(gpiomtd->plat.gpio_nwp, 0); -	if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) -		gpio_free(gpiomtd->plat.gpio_rdy); -err_rdy: -	gpio_free(gpiomtd->plat.gpio_cle); -err_cle: -	gpio_free(gpiomtd->plat.gpio_ale); -err_ale: -	if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) -		gpio_free(gpiomtd->plat.gpio_nwp); -err_nwp: -	gpio_free(gpiomtd->plat.gpio_nce); -err_nce: -	iounmap(gpiomtd->io_sync); -	if (res1) -		release_mem_region(res1->start, resource_size(res1)); -err_sync: -	iounmap(gpiomtd->nand_chip.IO_ADDR_R); -	release_mem_region(res0->start, resource_size(res0)); -err_map: +  	return ret;  } @@ -417,6 +307,7 @@ static struct platform_driver gpio_nand_driver = {  	.remove		= gpio_nand_remove,  	.driver		= {  		.name	= "gpio-nand", +		.owner	= THIS_MODULE,  		.of_match_table = of_match_ptr(gpio_nand_id_table),  	},  };  |