brintos

brintos / linux-shallow public Read only

0
0
Text · 11.2 KiB · 919816a Raw
448 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>4 *5 *  Derived from drivers/mtd/nand/toto.c (removed in v2.6.28)6 *    Copyright (c) 2003 Texas Instruments7 *    Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>8 *9 *  Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>10 *  Partially stolen from plat_nand.c11 *12 *  Overview:13 *   This is a device driver for the NAND flash device found on the14 *   Amstrad E3 (Delta).15 */16 17#include <linux/slab.h>18#include <linux/module.h>19#include <linux/delay.h>20#include <linux/gpio/consumer.h>21#include <linux/mtd/mtd.h>22#include <linux/mtd/nand-gpio.h>23#include <linux/mtd/rawnand.h>24#include <linux/mtd/partitions.h>25#include <linux/of.h>26#include <linux/platform_device.h>27#include <linux/sizes.h>28 29/*30 * MTD structure for E3 (Delta)31 */32struct gpio_nand {33	struct nand_controller	base;34	struct nand_chip	nand_chip;35	struct gpio_desc	*gpiod_rdy;36	struct gpio_desc	*gpiod_nce;37	struct gpio_desc	*gpiod_nre;38	struct gpio_desc	*gpiod_nwp;39	struct gpio_desc	*gpiod_nwe;40	struct gpio_desc	*gpiod_ale;41	struct gpio_desc	*gpiod_cle;42	struct gpio_descs	*data_gpiods;43	bool			data_in;44	unsigned int		tRP;45	unsigned int		tWP;46	u8			(*io_read)(struct gpio_nand *this);47	void			(*io_write)(struct gpio_nand *this, u8 byte);48};49 50static void gpio_nand_write_commit(struct gpio_nand *priv)51{52	gpiod_set_value(priv->gpiod_nwe, 1);53	ndelay(priv->tWP);54	gpiod_set_value(priv->gpiod_nwe, 0);55}56 57static void gpio_nand_io_write(struct gpio_nand *priv, u8 byte)58{59	struct gpio_descs *data_gpiods = priv->data_gpiods;60	DECLARE_BITMAP(values, BITS_PER_TYPE(byte)) = { byte, };61 62	gpiod_set_raw_array_value(data_gpiods->ndescs, data_gpiods->desc,63				  data_gpiods->info, values);64 65	gpio_nand_write_commit(priv);66}67 68static void gpio_nand_dir_output(struct gpio_nand *priv, u8 byte)69{70	struct gpio_descs *data_gpiods = priv->data_gpiods;71	DECLARE_BITMAP(values, BITS_PER_TYPE(byte)) = { byte, };72	int i;73 74	for (i = 0; i < data_gpiods->ndescs; i++)75		gpiod_direction_output_raw(data_gpiods->desc[i],76					   test_bit(i, values));77 78	gpio_nand_write_commit(priv);79 80	priv->data_in = false;81}82 83static u8 gpio_nand_io_read(struct gpio_nand *priv)84{85	u8 res;86	struct gpio_descs *data_gpiods = priv->data_gpiods;87	DECLARE_BITMAP(values, BITS_PER_TYPE(res)) = { 0, };88 89	gpiod_set_value(priv->gpiod_nre, 1);90	ndelay(priv->tRP);91 92	gpiod_get_raw_array_value(data_gpiods->ndescs, data_gpiods->desc,93				  data_gpiods->info, values);94 95	gpiod_set_value(priv->gpiod_nre, 0);96 97	res = values[0];98	return res;99}100 101static void gpio_nand_dir_input(struct gpio_nand *priv)102{103	struct gpio_descs *data_gpiods = priv->data_gpiods;104	int i;105 106	for (i = 0; i < data_gpiods->ndescs; i++)107		gpiod_direction_input(data_gpiods->desc[i]);108 109	priv->data_in = true;110}111 112static void gpio_nand_write_buf(struct gpio_nand *priv, const u8 *buf, int len)113{114	int i = 0;115 116	if (len > 0 && priv->data_in)117		gpio_nand_dir_output(priv, buf[i++]);118 119	while (i < len)120		priv->io_write(priv, buf[i++]);121}122 123static void gpio_nand_read_buf(struct gpio_nand *priv, u8 *buf, int len)124{125	int i;126 127	if (priv->data_gpiods && !priv->data_in)128		gpio_nand_dir_input(priv);129 130	for (i = 0; i < len; i++)131		buf[i] = priv->io_read(priv);132}133 134static void gpio_nand_ctrl_cs(struct gpio_nand *priv, bool assert)135{136	gpiod_set_value(priv->gpiod_nce, assert);137}138 139static int gpio_nand_exec_op(struct nand_chip *this,140			     const struct nand_operation *op, bool check_only)141{142	struct gpio_nand *priv = nand_get_controller_data(this);143	const struct nand_op_instr *instr;144	int ret = 0;145 146	if (check_only)147		return 0;148 149	gpio_nand_ctrl_cs(priv, 1);150 151	for (instr = op->instrs; instr < op->instrs + op->ninstrs; instr++) {152		switch (instr->type) {153		case NAND_OP_CMD_INSTR:154			gpiod_set_value(priv->gpiod_cle, 1);155			gpio_nand_write_buf(priv, &instr->ctx.cmd.opcode, 1);156			gpiod_set_value(priv->gpiod_cle, 0);157			break;158 159		case NAND_OP_ADDR_INSTR:160			gpiod_set_value(priv->gpiod_ale, 1);161			gpio_nand_write_buf(priv, instr->ctx.addr.addrs,162					    instr->ctx.addr.naddrs);163			gpiod_set_value(priv->gpiod_ale, 0);164			break;165 166		case NAND_OP_DATA_IN_INSTR:167			gpio_nand_read_buf(priv, instr->ctx.data.buf.in,168					   instr->ctx.data.len);169			break;170 171		case NAND_OP_DATA_OUT_INSTR:172			gpio_nand_write_buf(priv, instr->ctx.data.buf.out,173					    instr->ctx.data.len);174			break;175 176		case NAND_OP_WAITRDY_INSTR:177			ret = priv->gpiod_rdy ?178			      nand_gpio_waitrdy(this, priv->gpiod_rdy,179						instr->ctx.waitrdy.timeout_ms) :180			      nand_soft_waitrdy(this,181						instr->ctx.waitrdy.timeout_ms);182			break;183		}184 185		if (ret)186			break;187	}188 189	gpio_nand_ctrl_cs(priv, 0);190 191	return ret;192}193 194static int gpio_nand_setup_interface(struct nand_chip *this, int csline,195				     const struct nand_interface_config *cf)196{197	struct gpio_nand *priv = nand_get_controller_data(this);198	const struct nand_sdr_timings *sdr = nand_get_sdr_timings(cf);199	struct device *dev = &nand_to_mtd(this)->dev;200 201	if (IS_ERR(sdr))202		return PTR_ERR(sdr);203 204	if (csline == NAND_DATA_IFACE_CHECK_ONLY)205		return 0;206 207	if (priv->gpiod_nre) {208		priv->tRP = DIV_ROUND_UP(sdr->tRP_min, 1000);209		dev_dbg(dev, "using %u ns read pulse width\n", priv->tRP);210	}211 212	priv->tWP = DIV_ROUND_UP(sdr->tWP_min, 1000);213	dev_dbg(dev, "using %u ns write pulse width\n", priv->tWP);214 215	return 0;216}217 218static int gpio_nand_attach_chip(struct nand_chip *chip)219{220	if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&221	    chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)222		chip->ecc.algo = NAND_ECC_ALGO_HAMMING;223 224	return 0;225}226 227static const struct nand_controller_ops gpio_nand_ops = {228	.exec_op = gpio_nand_exec_op,229	.attach_chip = gpio_nand_attach_chip,230	.setup_interface = gpio_nand_setup_interface,231};232 233/*234 * Main initialization routine235 */236static int gpio_nand_probe(struct platform_device *pdev)237{238	struct gpio_nand_platdata *pdata = dev_get_platdata(&pdev->dev);239	const struct mtd_partition *partitions = NULL;240	int num_partitions = 0;241	struct gpio_nand *priv;242	struct nand_chip *this;243	struct mtd_info *mtd;244	int (*probe)(struct platform_device *pdev, struct gpio_nand *priv);245	int err = 0;246 247	if (pdata) {248		partitions = pdata->parts;249		num_partitions = pdata->num_parts;250	}251 252	/* Allocate memory for MTD device structure and private data */253	priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_nand),254			    GFP_KERNEL);255	if (!priv)256		return -ENOMEM;257 258	this = &priv->nand_chip;259 260	mtd = nand_to_mtd(this);261	mtd->dev.parent = &pdev->dev;262 263	nand_set_controller_data(this, priv);264	nand_set_flash_node(this, pdev->dev.of_node);265 266	priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN);267	if (IS_ERR(priv->gpiod_rdy)) {268		err = PTR_ERR(priv->gpiod_rdy);269		dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err);270		return err;271	}272 273	platform_set_drvdata(pdev, priv);274 275	/* Set chip enabled but write protected */276	priv->gpiod_nwp = devm_gpiod_get_optional(&pdev->dev, "nwp",277						  GPIOD_OUT_HIGH);278	if (IS_ERR(priv->gpiod_nwp)) {279		err = PTR_ERR(priv->gpiod_nwp);280		dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err);281		return err;282	}283 284	priv->gpiod_nce = devm_gpiod_get_optional(&pdev->dev, "nce",285						  GPIOD_OUT_LOW);286	if (IS_ERR(priv->gpiod_nce)) {287		err = PTR_ERR(priv->gpiod_nce);288		dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err);289		return err;290	}291 292	priv->gpiod_nre = devm_gpiod_get_optional(&pdev->dev, "nre",293						  GPIOD_OUT_LOW);294	if (IS_ERR(priv->gpiod_nre)) {295		err = PTR_ERR(priv->gpiod_nre);296		dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err);297		return err;298	}299 300	priv->gpiod_nwe = devm_gpiod_get_optional(&pdev->dev, "nwe",301						  GPIOD_OUT_LOW);302	if (IS_ERR(priv->gpiod_nwe)) {303		err = PTR_ERR(priv->gpiod_nwe);304		dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err);305		return err;306	}307 308	priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW);309	if (IS_ERR(priv->gpiod_ale)) {310		err = PTR_ERR(priv->gpiod_ale);311		dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err);312		return err;313	}314 315	priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW);316	if (IS_ERR(priv->gpiod_cle)) {317		err = PTR_ERR(priv->gpiod_cle);318		dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err);319		return err;320	}321 322	/* Request array of data pins, initialize them as input */323	priv->data_gpiods = devm_gpiod_get_array_optional(&pdev->dev, "data",324							  GPIOD_IN);325	if (IS_ERR(priv->data_gpiods)) {326		err = PTR_ERR(priv->data_gpiods);327		dev_err(&pdev->dev, "data GPIO request failed: %d\n", err);328		return err;329	}330	if (priv->data_gpiods) {331		if (!priv->gpiod_nwe) {332			dev_err(&pdev->dev,333				"mandatory NWE pin not provided by platform\n");334			return -ENODEV;335		}336 337		priv->io_read = gpio_nand_io_read;338		priv->io_write = gpio_nand_io_write;339		priv->data_in = true;340	}341 342	if (pdev->id_entry)343		probe = (void *) pdev->id_entry->driver_data;344	else345		probe = of_device_get_match_data(&pdev->dev);346	if (probe)347		err = probe(pdev, priv);348	if (err)349		return err;350 351	if (!priv->io_read || !priv->io_write) {352		dev_err(&pdev->dev, "incomplete device configuration\n");353		return -ENODEV;354	}355 356	/* Initialize the NAND controller object embedded in gpio_nand. */357	priv->base.ops = &gpio_nand_ops;358	nand_controller_init(&priv->base);359	this->controller = &priv->base;360 361	/*362	 * FIXME: We should release write protection only after nand_scan() to363	 * be on the safe side but we can't do that until we have a generic way364	 * to assert/deassert WP from the core.  Even if the core shouldn't365	 * write things in the nand_scan() path, it should have control on this366	 * pin just in case we ever need to disable write protection during367	 * chip detection/initialization.368	 */369	/* Release write protection */370	gpiod_set_value(priv->gpiod_nwp, 0);371 372	/*373	 * This driver assumes that the default ECC engine should be TYPE_SOFT.374	 * Set ->engine_type before registering the NAND devices in order to375	 * provide a driver specific default value.376	 */377	this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;378 379	/* Scan to find existence of the device */380	err = nand_scan(this, 1);381	if (err)382		return err;383 384	/* Register the partitions */385	err = mtd_device_register(mtd, partitions, num_partitions);386	if (err)387		goto err_nand_cleanup;388 389	return 0;390 391err_nand_cleanup:392	nand_cleanup(this);393 394	return err;395}396 397/*398 * Clean up routine399 */400static void gpio_nand_remove(struct platform_device *pdev)401{402	struct gpio_nand *priv = platform_get_drvdata(pdev);403	struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip);404	int ret;405 406	/* Apply write protection */407	gpiod_set_value(priv->gpiod_nwp, 1);408 409	/* Unregister device */410	ret = mtd_device_unregister(mtd);411	WARN_ON(ret);412	nand_cleanup(mtd_to_nand(mtd));413}414 415#ifdef CONFIG_OF416static const struct of_device_id gpio_nand_of_id_table[] = {417	{418		/* sentinel */419	},420};421MODULE_DEVICE_TABLE(of, gpio_nand_of_id_table);422#endif423 424static const struct platform_device_id gpio_nand_plat_id_table[] = {425	{426		.name	= "ams-delta-nand",427	}, {428		/* sentinel */429	},430};431MODULE_DEVICE_TABLE(platform, gpio_nand_plat_id_table);432 433static struct platform_driver gpio_nand_driver = {434	.probe		= gpio_nand_probe,435	.remove_new	= gpio_nand_remove,436	.id_table	= gpio_nand_plat_id_table,437	.driver		= {438		.name	= "ams-delta-nand",439		.of_match_table = of_match_ptr(gpio_nand_of_id_table),440	},441};442 443module_platform_driver(gpio_nand_driver);444 445MODULE_LICENSE("GPL v2");446MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");447MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");448