drivers/mtd/spi-nor/otp.c

Source file repositories/reference/linux-study-clean/drivers/mtd/spi-nor/otp.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/spi-nor/otp.c
Extension
.c
Size
12442 bytes
Lines
509
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 (locked < 0) {
			ret = locked;
			goto out;
		}

		buf->locked = !!locked;
		buf++;
	}

	*retlen = n_regions * sizeof(*buf);

out:
	spi_nor_unlock_and_unprep(nor);

	return ret;
}

static int spi_nor_mtd_otp_range_is_locked(struct spi_nor *nor, loff_t ofs,
					   size_t len)
{
	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
	unsigned int region;
	int locked;

	/*
	 * If any of the affected OTP regions are locked the entire range is
	 * considered locked.
	 */
	for (region = spi_nor_otp_offset_to_region(nor, ofs);
	     region <= spi_nor_otp_offset_to_region(nor, ofs + len - 1);
	     region++) {
		locked = ops->is_locked(nor, region);
		/* take the branch it is locked or in case of an error */
		if (locked)
			return locked;
	}

	return 0;
}

static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs,
				      size_t total_len, size_t *retlen,
				      const u8 *buf, bool is_write)
{
	struct spi_nor *nor = mtd_to_spi_nor(mtd);
	const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
	const size_t rlen = spi_nor_otp_region_len(nor);
	loff_t rstart, rofs;
	unsigned int region;
	size_t len;
	int ret;

	if (ofs < 0 || ofs >= spi_nor_otp_size(nor))
		return 0;

	/* don't access beyond the end */
	total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs);

	if (!total_len)
		return 0;

	ret = spi_nor_prep_and_lock(nor);
	if (ret)
		return ret;

	if (is_write) {
		ret = spi_nor_mtd_otp_range_is_locked(nor, ofs, total_len);
		if (ret < 0) {
			goto out;
		} else if (ret) {
			ret = -EROFS;
			goto out;
		}
	}

	while (total_len) {
		/*
		 * The OTP regions are mapped into a contiguous area starting
		 * at 0 as expected by the MTD layer. This will map the MTD
		 * file offsets to the address of an OTP region as used in the
		 * actual SPI commands.
		 */
		region = spi_nor_otp_offset_to_region(nor, ofs);
		rstart = spi_nor_otp_region_start(nor, region);

		/*
		 * The size of a OTP region is expected to be a power of two,
		 * thus we can just mask the lower bits and get the offset into
		 * a region.
		 */

Annotation

Implementation Notes