diff options
Diffstat (limited to 'drivers/mtd/nand/raw/ams-delta.c')
| -rw-r--r-- | drivers/mtd/nand/raw/ams-delta.c | 249 | 
1 files changed, 144 insertions, 105 deletions
| diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index 37a3cc21c7bc..5ba180a291eb 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -20,23 +20,33 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/delay.h> +#include <linux/gpio/consumer.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/rawnand.h>  #include <linux/mtd/partitions.h> -#include <linux/gpio.h>  #include <linux/platform_data/gpio-omap.h>  #include <asm/io.h>  #include <asm/sizes.h> -#include <mach/board-ams-delta.h> -  #include <mach/hardware.h>  /*   * MTD structure for E3 (Delta)   */ -static struct mtd_info *ams_delta_mtd = NULL; + +struct ams_delta_nand { +	struct nand_chip	nand_chip; +	struct gpio_desc	*gpiod_rdy; +	struct gpio_desc	*gpiod_nce; +	struct gpio_desc	*gpiod_nre; +	struct gpio_desc	*gpiod_nwp; +	struct gpio_desc	*gpiod_nwe; +	struct gpio_desc	*gpiod_ale; +	struct gpio_desc	*gpiod_cle; +	void __iomem		*io_base; +	bool			data_in; +};  /*   * Define partitions for flash devices @@ -63,48 +73,64 @@ static const struct mtd_partition partition_info[] = {  	  .size		=  3 * SZ_256K },  }; -static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) +static void ams_delta_io_write(struct ams_delta_nand *priv, u_char byte)  { -	struct nand_chip *this = mtd_to_nand(mtd); -	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this); - -	writew(0, io_base + OMAP_MPUIO_IO_CNTL); -	writew(byte, this->IO_ADDR_W); -	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0); +	writew(byte, priv->nand_chip.legacy.IO_ADDR_W); +	gpiod_set_value(priv->gpiod_nwe, 0);  	ndelay(40); -	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1); +	gpiod_set_value(priv->gpiod_nwe, 1);  } -static u_char ams_delta_read_byte(struct mtd_info *mtd) +static u_char ams_delta_io_read(struct ams_delta_nand *priv)  {  	u_char res; -	struct nand_chip *this = mtd_to_nand(mtd); -	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this); -	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0); +	gpiod_set_value(priv->gpiod_nre, 0);  	ndelay(40); -	writew(~0, io_base + OMAP_MPUIO_IO_CNTL); -	res = readw(this->IO_ADDR_R); -	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1); +	res = readw(priv->nand_chip.legacy.IO_ADDR_R); +	gpiod_set_value(priv->gpiod_nre, 1);  	return res;  } -static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf, +static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in) +{ +	writew(in ? ~0 : 0, priv->io_base + OMAP_MPUIO_IO_CNTL); +	priv->data_in = in; +} + +static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf,  				int len)  { +	struct ams_delta_nand *priv = nand_get_controller_data(this);  	int i; -	for (i=0; i<len; i++) -		ams_delta_write_byte(mtd, buf[i]); +	if (priv->data_in) +		ams_delta_dir_input(priv, false); + +	for (i = 0; i < len; i++) +		ams_delta_io_write(priv, buf[i]);  } -static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len)  { +	struct ams_delta_nand *priv = nand_get_controller_data(this);  	int i; -	for (i=0; i<len; i++) -		buf[i] = ams_delta_read_byte(mtd); +	if (!priv->data_in) +		ams_delta_dir_input(priv, true); + +	for (i = 0; i < len; i++) +		buf[i] = ams_delta_io_read(priv); +} + +static u_char ams_delta_read_byte(struct nand_chip *this) +{ +	u_char res; + +	ams_delta_read_buf(this, &res, 1); + +	return res;  }  /* @@ -115,67 +141,40 @@ static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)   * NAND_CLE: bit 1 -> bit 7   * NAND_ALE: bit 2 -> bit 6   */ -static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd, +static void ams_delta_hwcontrol(struct nand_chip *this, int cmd,  				unsigned int ctrl)  { +	struct ams_delta_nand *priv = nand_get_controller_data(this);  	if (ctrl & NAND_CTRL_CHANGE) { -		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE, -				(ctrl & NAND_NCE) == 0); -		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE, -				(ctrl & NAND_CLE) != 0); -		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE, -				(ctrl & NAND_ALE) != 0); +		gpiod_set_value(priv->gpiod_nce, !(ctrl & NAND_NCE)); +		gpiod_set_value(priv->gpiod_cle, !!(ctrl & NAND_CLE)); +		gpiod_set_value(priv->gpiod_ale, !!(ctrl & NAND_ALE));  	} -	if (cmd != NAND_CMD_NONE) -		ams_delta_write_byte(mtd, cmd); +	if (cmd != NAND_CMD_NONE) { +		u_char byte = cmd; + +		ams_delta_write_buf(this, &byte, 1); +	}  } -static int ams_delta_nand_ready(struct mtd_info *mtd) +static int ams_delta_nand_ready(struct nand_chip *this)  { -	return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB); +	struct ams_delta_nand *priv = nand_get_controller_data(this); + +	return gpiod_get_value(priv->gpiod_rdy);  } -static const struct gpio _mandatory_gpio[] = { -	{ -		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NCE, -		.flags	= GPIOF_OUT_INIT_HIGH, -		.label	= "nand_nce", -	}, -	{ -		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NRE, -		.flags	= GPIOF_OUT_INIT_HIGH, -		.label	= "nand_nre", -	}, -	{ -		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWP, -		.flags	= GPIOF_OUT_INIT_HIGH, -		.label	= "nand_nwp", -	}, -	{ -		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWE, -		.flags	= GPIOF_OUT_INIT_HIGH, -		.label	= "nand_nwe", -	}, -	{ -		.gpio	= AMS_DELTA_GPIO_PIN_NAND_ALE, -		.flags	= GPIOF_OUT_INIT_LOW, -		.label	= "nand_ale", -	}, -	{ -		.gpio	= AMS_DELTA_GPIO_PIN_NAND_CLE, -		.flags	= GPIOF_OUT_INIT_LOW, -		.label	= "nand_cle", -	}, -};  /*   * Main initialization routine   */  static int ams_delta_init(struct platform_device *pdev)  { +	struct ams_delta_nand *priv;  	struct nand_chip *this; +	struct mtd_info *mtd;  	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	void __iomem *io_base;  	int err = 0; @@ -184,15 +183,16 @@ static int ams_delta_init(struct platform_device *pdev)  		return -ENXIO;  	/* Allocate memory for MTD device structure and private data */ -	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); -	if (!this) { +	priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand), +			    GFP_KERNEL); +	if (!priv) {  		pr_warn("Unable to allocate E3 NAND MTD device structure.\n"); -		err = -ENOMEM; -		goto out; +		return -ENOMEM;  	} +	this = &priv->nand_chip; -	ams_delta_mtd = nand_to_mtd(this); -	ams_delta_mtd->owner = THIS_MODULE; +	mtd = nand_to_mtd(this); +	mtd->dev.parent = &pdev->dev;  	/*  	 * Don't try to request the memory region from here, @@ -207,51 +207,93 @@ static int ams_delta_init(struct platform_device *pdev)  		goto out_free;  	} -	nand_set_controller_data(this, (void *)io_base); +	priv->io_base = io_base; +	nand_set_controller_data(this, priv);  	/* Set address of NAND IO lines */ -	this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH; -	this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT; -	this->read_byte = ams_delta_read_byte; -	this->write_buf = ams_delta_write_buf; -	this->read_buf = ams_delta_read_buf; -	this->cmd_ctrl = ams_delta_hwcontrol; -	if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) { -		this->dev_ready = ams_delta_nand_ready; -	} else { -		this->dev_ready = NULL; -		pr_notice("Couldn't request gpio for Delta NAND ready.\n"); +	this->legacy.IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH; +	this->legacy.IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT; +	this->legacy.read_byte = ams_delta_read_byte; +	this->legacy.write_buf = ams_delta_write_buf; +	this->legacy.read_buf = ams_delta_read_buf; +	this->legacy.cmd_ctrl = ams_delta_hwcontrol; + +	priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN); +	if (IS_ERR(priv->gpiod_rdy)) { +		err = PTR_ERR(priv->gpiod_rdy); +		dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err); +		goto out_mtd;  	} + +	if (priv->gpiod_rdy) +		this->legacy.dev_ready = ams_delta_nand_ready; +  	/* 25 us command delay time */ -	this->chip_delay = 30; +	this->legacy.chip_delay = 30;  	this->ecc.mode = NAND_ECC_SOFT;  	this->ecc.algo = NAND_ECC_HAMMING; -	platform_set_drvdata(pdev, io_base); +	platform_set_drvdata(pdev, priv);  	/* Set chip enabled, but  */ -	err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio)); -	if (err) -		goto out_gpio; +	priv->gpiod_nwp = devm_gpiod_get(&pdev->dev, "nwp", GPIOD_OUT_HIGH); +	if (IS_ERR(priv->gpiod_nwp)) { +		err = PTR_ERR(priv->gpiod_nwp); +		dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err); +		goto out_mtd; +	} + +	priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH); +	if (IS_ERR(priv->gpiod_nce)) { +		err = PTR_ERR(priv->gpiod_nce); +		dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err); +		goto out_mtd; +	} + +	priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH); +	if (IS_ERR(priv->gpiod_nre)) { +		err = PTR_ERR(priv->gpiod_nre); +		dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err); +		goto out_mtd; +	} + +	priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH); +	if (IS_ERR(priv->gpiod_nwe)) { +		err = PTR_ERR(priv->gpiod_nwe); +		dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err); +		goto out_mtd; +	} + +	priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW); +	if (IS_ERR(priv->gpiod_ale)) { +		err = PTR_ERR(priv->gpiod_ale); +		dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err); +		goto out_mtd; +	} + +	priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW); +	if (IS_ERR(priv->gpiod_cle)) { +		err = PTR_ERR(priv->gpiod_cle); +		dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err); +		goto out_mtd; +	} + +	/* Initialize data port direction to a known state */ +	ams_delta_dir_input(priv, true);  	/* Scan to find existence of the device */ -	err = nand_scan(ams_delta_mtd, 1); +	err = nand_scan(this, 1);  	if (err)  		goto out_mtd;  	/* Register the partitions */ -	mtd_device_register(ams_delta_mtd, partition_info, -			    ARRAY_SIZE(partition_info)); +	mtd_device_register(mtd, partition_info, ARRAY_SIZE(partition_info));  	goto out;   out_mtd: -	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio)); -out_gpio: -	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);  	iounmap(io_base);  out_free: -	kfree(this);   out:  	return err;  } @@ -261,18 +303,15 @@ out_free:   */  static int ams_delta_cleanup(struct platform_device *pdev)  { -	void __iomem *io_base = platform_get_drvdata(pdev); +	struct ams_delta_nand *priv = platform_get_drvdata(pdev); +	struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip); +	void __iomem *io_base = priv->io_base;  	/* Release resources, unregister device */ -	nand_release(ams_delta_mtd); +	nand_release(mtd_to_nand(mtd)); -	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio)); -	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);  	iounmap(io_base); -	/* Free the MTD device structure */ -	kfree(mtd_to_nand(ams_delta_mtd)); -  	return 0;  } |