drivers/mtd/nand/raw/plat_nand.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mtd/nand/raw/plat_nand.c
Extension
.c
Size
4683 bytes
Lines
182
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 plat_nand_data {
	struct nand_controller	controller;
	struct nand_chip	chip;
	void __iomem		*io_base;
	struct gpio_desc	*ready_gpio;
};

static int plat_nand_attach_chip(struct nand_chip *chip)
{
	if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
	    chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
		chip->ecc.algo = NAND_ECC_ALGO_HAMMING;

	return 0;
}

static const struct nand_controller_ops plat_nand_ops = {
	.attach_chip = plat_nand_attach_chip,
};

/* Resources and device for NAND */
static int plat_nand_gpio_dev_ready(struct nand_chip *chip)
{
	struct plat_nand_data *data = nand_get_controller_data(chip);

	return gpiod_get_value(data->ready_gpio);
}

/*
 * Probe for the NAND device.
 */
static int plat_nand_probe(struct platform_device *pdev)
{
	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
	struct plat_nand_data *data;
	struct mtd_info *mtd;
	const char **part_types;
	struct nand_chip *chip;
	int err = 0;

	if (!pdata) {
		dev_err(&pdev->dev, "platform_nand_data is missing\n");
		return -EINVAL;
	}

	if (pdata->chip.nr_chips < 1) {
		dev_err(&pdev->dev, "invalid number of chips specified\n");
		return -EINVAL;
	}

	/* Allocate memory for the device structure (and zero it) */
	data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data),
			    GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->ready_gpio = devm_gpiod_get_optional(&pdev->dev, "ready",
						   GPIOD_IN);
	if (IS_ERR(data->ready_gpio))
		return dev_err_probe(&pdev->dev, PTR_ERR(data->ready_gpio),
				     "could not get READY GPIO\n");

	data->controller.ops = &plat_nand_ops;
	nand_controller_init(&data->controller);
	data->chip.controller = &data->controller;
	chip = &data->chip;
	nand_set_controller_data(chip, data);

	data->io_base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(data->io_base))
		return PTR_ERR(data->io_base);

	nand_set_flash_node(&data->chip, pdev->dev.of_node);
	mtd = nand_to_mtd(&data->chip);
	mtd->dev.parent = &pdev->dev;

	data->chip.legacy.IO_ADDR_R = data->io_base;
	data->chip.legacy.IO_ADDR_W = data->io_base;
	data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl;
	if (data->ready_gpio)
		data->chip.legacy.dev_ready = plat_nand_gpio_dev_ready;
	else
		data->chip.legacy.dev_ready = pdata->ctrl.dev_ready;
	data->chip.legacy.select_chip = pdata->ctrl.select_chip;
	data->chip.legacy.write_buf = pdata->ctrl.write_buf;
	data->chip.legacy.read_buf = pdata->ctrl.read_buf;
	data->chip.legacy.chip_delay = pdata->chip.chip_delay;
	data->chip.options |= pdata->chip.options;
	data->chip.bbt_options |= pdata->chip.bbt_options;

Annotation

Implementation Notes