drivers/mtd/nand/spi/core.c

Source file repositories/reference/linux-study-clean/drivers/mtd/nand/spi/core.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/nand/spi/core.c
Extension
.c
Size
54277 bytes
Lines
2113
Domain
Driver Families
Bucket
drivers/mtd
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!buf) {
			buf = spinand->oobbuf;
			column = nanddev_page_size(nand);
		}
	}

	rdesc = spinand->dirmaps[req->pos.plane].rdesc;

	if (spinand->op_templates->cont_read_cache && req->continuous)
		rdesc->info.op_tmpl = &rdesc->info.secondary_op_tmpl;
	else
		rdesc->info.op_tmpl = &rdesc->info.primary_op_tmpl;

	if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED &&
	    req->mode != MTD_OPS_RAW)
		rdesc->info.op_tmpl->data.ecc = true;
	else
		rdesc->info.op_tmpl->data.ecc = false;

	if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT)
		column |= req->pos.plane << fls(nanddev_page_size(nand));

	while (nbytes) {
		ret = spi_mem_dirmap_read(rdesc, column, nbytes, buf);
		if (ret < 0)
			return ret;

		if (!ret || ret > nbytes)
			return -EIO;

		nbytes -= ret;
		column += ret;
		buf += ret;

		/*
		 * Dirmap accesses are allowed to toggle the CS.
		 * Toggling the CS during a continuous read is forbidden.
		 */
		if (nbytes && req->continuous) {
			/*
			 * Spi controller with broken support of continuous
			 * reading was detected. Disable future use of
			 * continuous reading and return -EAGAIN to retry
			 * reading within regular mode.
			 */
			spinand->cont_read_possible = false;
			return -EAGAIN;
		}
	}

	if (req->datalen)
		memcpy(req->databuf.in, spinand->databuf + req->dataoffs,
		       req->datalen);

	if (req->ooblen) {
		if (req->mode == MTD_OPS_AUTO_OOB)
			mtd_ooblayout_get_databytes(mtd, req->oobbuf.in,
						    spinand->oobbuf,
						    req->ooboffs,
						    req->ooblen);
		else
			memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
			       req->ooblen);
	}

	return 0;
}

static int spinand_write_to_cache_op(struct spinand_device *spinand,
				     const struct nand_page_io_req *req)
{
	struct nand_device *nand = spinand_to_nand(spinand);
	struct mtd_info *mtd = spinand_to_mtd(spinand);
	struct spi_mem_dirmap_desc *wdesc;
	unsigned int nbytes, column = 0;
	void *buf = spinand->databuf;
	ssize_t ret;

	/*
	 * Looks like PROGRAM LOAD (AKA write cache) does not necessarily reset
	 * the cache content to 0xFF (depends on vendor implementation), so we
	 * must fill the page cache entirely even if we only want to program
	 * the data portion of the page, otherwise we might corrupt the BBM or
	 * user data previously programmed in OOB area.
	 *
	 * Only reset the data buffer manually, the OOB buffer is prepared by
	 * ECC engines ->prepare_io_req() callback.
	 */
	nbytes = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
	memset(spinand->databuf, 0xff, nanddev_page_size(nand));

Annotation

Implementation Notes