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;
}