drivers/mtd/nand/raw/fsl_upm.c

Source file repositories/reference/linux-study-clean/drivers/mtd/nand/raw/fsl_upm.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/nand/raw/fsl_upm.c
Extension
.c
Size
6625 bytes
Lines
271
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

struct fsl_upm_nand {
	struct nand_controller base;
	struct device *dev;
	struct nand_chip chip;
	struct fsl_upm upm;
	uint8_t upm_addr_offset;
	uint8_t upm_cmd_offset;
	void __iomem *io_base;
	struct gpio_desc *rnb_gpio[NAND_MAX_CHIPS];
	uint32_t mchip_offsets[NAND_MAX_CHIPS];
	uint32_t mchip_count;
	uint32_t mchip_number;
};

static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
{
	return container_of(mtd_to_nand(mtdinfo), struct fsl_upm_nand,
			    chip);
}

static int fun_chip_init(struct fsl_upm_nand *fun,
			 const struct device_node *upm_np,
			 const struct resource *io_res)
{
	struct mtd_info *mtd = nand_to_mtd(&fun->chip);
	int ret;
	struct device_node *flash_np;

	fun->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
	fun->chip.ecc.algo = NAND_ECC_ALGO_HAMMING;
	fun->chip.controller = &fun->base;
	mtd->dev.parent = fun->dev;

	flash_np = of_get_next_child(upm_np, NULL);
	if (!flash_np)
		return -ENODEV;

	nand_set_flash_node(&fun->chip, flash_np);
	mtd->name = devm_kasprintf(fun->dev, GFP_KERNEL, "0x%llx.%pOFn",
				   (u64)io_res->start,
				   flash_np);
	if (!mtd->name) {
		ret = -ENOMEM;
		goto err;
	}

	ret = nand_scan(&fun->chip, fun->mchip_count);
	if (ret)
		goto err;

	ret = mtd_device_register(mtd, NULL, 0);
err:
	of_node_put(flash_np);
	return ret;
}

static int func_exec_instr(struct nand_chip *chip,
			   const struct nand_op_instr *instr)
{
	struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
	u32 mar, reg_offs = fun->mchip_offsets[fun->mchip_number];
	unsigned int i;
	const u8 *out;
	u8 *in;

	switch (instr->type) {
	case NAND_OP_CMD_INSTR:
		fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
		mar = (instr->ctx.cmd.opcode << (32 - fun->upm.width)) |
		      reg_offs;
		fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar);
		fsl_upm_end_pattern(&fun->upm);
		return 0;

	case NAND_OP_ADDR_INSTR:
		fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
		for (i = 0; i < instr->ctx.addr.naddrs; i++) {
			mar = (instr->ctx.addr.addrs[i] << (32 - fun->upm.width)) |
			      reg_offs;
			fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar);
		}
		fsl_upm_end_pattern(&fun->upm);
		return 0;

	case NAND_OP_DATA_IN_INSTR:
		in = instr->ctx.data.buf.in;
		for (i = 0; i < instr->ctx.data.len; i++)
			in[i] = in_8(fun->io_base + reg_offs);
		return 0;

Annotation

Implementation Notes