static int mpc5121_nfc_probe()

in nand/raw/mpc5121_nfc.c [618:824]


static int mpc5121_nfc_probe(struct platform_device *op)
{
	struct device_node *dn = op->dev.of_node;
	struct clk *clk;
	struct device *dev = &op->dev;
	struct mpc5121_nfc_prv *prv;
	struct resource res;
	struct mtd_info *mtd;
	struct nand_chip *chip;
	unsigned long regs_paddr, regs_size;
	const __be32 *chips_no;
	int resettime = 0;
	int retval = 0;
	int rev, len;

	/*
	 * Check SoC revision. This driver supports only NFC
	 * in MPC5121 revision 2 and MPC5123 revision 3.
	 */
	rev = (mfspr(SPRN_SVR) >> 4) & 0xF;
	if ((rev != 2) && (rev != 3)) {
		dev_err(dev, "SoC revision %u is not supported!\n", rev);
		return -ENXIO;
	}

	prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
	if (!prv)
		return -ENOMEM;

	chip = &prv->chip;
	mtd = nand_to_mtd(chip);

	nand_controller_init(&prv->controller);
	prv->controller.ops = &mpc5121_nfc_ops;
	chip->controller = &prv->controller;

	mtd->dev.parent = dev;
	nand_set_controller_data(chip, prv);
	nand_set_flash_node(chip, dn);
	prv->dev = dev;

	/* Read NFC configuration from Reset Config Word */
	retval = mpc5121_nfc_read_hw_config(mtd);
	if (retval) {
		dev_err(dev, "Unable to read NFC config!\n");
		return retval;
	}

	prv->irq = irq_of_parse_and_map(dn, 0);
	if (prv->irq == NO_IRQ) {
		dev_err(dev, "Error mapping IRQ!\n");
		return -EINVAL;
	}

	retval = of_address_to_resource(dn, 0, &res);
	if (retval) {
		dev_err(dev, "Error parsing memory region!\n");
		return retval;
	}

	chips_no = of_get_property(dn, "chips", &len);
	if (!chips_no || len != sizeof(*chips_no)) {
		dev_err(dev, "Invalid/missing 'chips' property!\n");
		return -EINVAL;
	}

	regs_paddr = res.start;
	regs_size = resource_size(&res);

	if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
		dev_err(dev, "Error requesting memory region!\n");
		return -EBUSY;
	}

	prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
	if (!prv->regs) {
		dev_err(dev, "Error mapping memory region!\n");
		return -ENOMEM;
	}

	mtd->name = "MPC5121 NAND";
	chip->legacy.dev_ready = mpc5121_nfc_dev_ready;
	chip->legacy.cmdfunc = mpc5121_nfc_command;
	chip->legacy.read_byte = mpc5121_nfc_read_byte;
	chip->legacy.read_buf = mpc5121_nfc_read_buf;
	chip->legacy.write_buf = mpc5121_nfc_write_buf;
	chip->legacy.select_chip = mpc5121_nfc_select_chip;
	chip->legacy.set_features = nand_get_set_features_notsupp;
	chip->legacy.get_features = nand_get_set_features_notsupp;
	chip->bbt_options = NAND_BBT_USE_FLASH;

	/* Support external chip-select logic on ADS5121 board */
	if (of_machine_is_compatible("fsl,mpc5121ads")) {
		retval = ads5121_chipselect_init(mtd);
		if (retval) {
			dev_err(dev, "Chipselect init error!\n");
			return retval;
		}

		chip->legacy.select_chip = ads5121_select_chip;
	}

	/* Enable NFC clock */
	clk = devm_clk_get(dev, "ipg");
	if (IS_ERR(clk)) {
		dev_err(dev, "Unable to acquire NFC clock!\n");
		retval = PTR_ERR(clk);
		goto error;
	}
	retval = clk_prepare_enable(clk);
	if (retval) {
		dev_err(dev, "Unable to enable NFC clock!\n");
		goto error;
	}
	prv->clk = clk;

	/* Reset NAND Flash controller */
	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
	while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
		if (resettime++ >= NFC_RESET_TIMEOUT) {
			dev_err(dev, "Timeout while resetting NFC!\n");
			retval = -EINVAL;
			goto error;
		}

		udelay(1);
	}

	/* Enable write to NFC memory */
	nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);

	/* Enable write to all NAND pages */
	nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
	nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
	nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);

	/*
	 * Setup NFC:
	 *	- Big Endian transfers,
	 *	- Interrupt after full page read/write.
	 */
	nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
							NFC_FULL_PAGE_INT);

	/* Set spare area size */
	nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);

	init_waitqueue_head(&prv->irq_waitq);
	retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME,
									mtd);
	if (retval) {
		dev_err(dev, "Error requesting IRQ!\n");
		goto error;
	}

	/*
	 * This driver assumes that the default ECC engine should be TYPE_SOFT.
	 * Set ->engine_type before registering the NAND devices in order to
	 * provide a driver specific default value.
	 */
	chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;

	/* Detect NAND chips */
	retval = nand_scan(chip, be32_to_cpup(chips_no));
	if (retval) {
		dev_err(dev, "NAND Flash not found !\n");
		goto error;
	}

	/* Set erase block size */
	switch (mtd->erasesize / mtd->writesize) {
	case 32:
		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
		break;

	case 64:
		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
		break;

	case 128:
		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
		break;

	case 256:
		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
		break;

	default:
		dev_err(dev, "Unsupported NAND flash!\n");
		retval = -ENXIO;
		goto error;
	}

	dev_set_drvdata(dev, mtd);

	/* Register device in MTD */
	retval = mtd_device_register(mtd, NULL, 0);
	if (retval) {
		dev_err(dev, "Error adding MTD device!\n");
		goto error;
	}

	return 0;
error:
	mpc5121_nfc_free(dev, mtd);
	return retval;
}