--- linux-4.9.37/drivers/mtd/nand/gkfmc100/fmc100_os.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-4.9.y/drivers/mtd/nand/gkfmc100/fmc100_os.c 2021-06-07 13:01:33.000000000 +0300 @@ -0,0 +1,223 @@ +/* + * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../mtdcore.h" +#include "fmc100.h" + +/*****************************************************************************/ +static int fmc100_spi_nand_pre_probe(struct nand_chip *chip) +{ + uint8_t nand_maf_id; + struct fmc_host *host = chip->priv; + + /* Reset the chip first */ + host->send_cmd_reset(host); + udelay(1000); + + /* Check the ID */ + host->offset = 0; + memset((unsigned char *)(chip->IO_ADDR_R), 0, 0x10); + host->send_cmd_readid(host); + nand_maf_id = fmc_readb(chip->IO_ADDR_R); + + if (nand_maf_id == 0x00 || nand_maf_id == 0xff) { + printk("Cannot found a valid SPI Nand Device\n"); + return 1; + } + + return 0; +} +/*****************************************************************************/ +static int fmc_nand_scan(struct mtd_info *mtd) +{ + int result = 0; + unsigned char cs, chip_num = CONFIG_SPI_NAND_MAX_CHIP_NUM; + struct nand_chip *chip = mtd_to_nand(mtd); + struct fmc_host *host = chip->priv; + + for (cs = 0; chip_num && (cs < FMC_MAX_CHIP_NUM); cs++) { + if (fmc_cs_user[cs]) { + FMC_PR(BT_DBG, "\t\t*-Current CS(%d) is occupied.\n", + cs); + continue; + } + + host->cmd_op.cs = cs; + + if (fmc100_spi_nand_pre_probe(chip)) { + return -ENODEV; + } + + FMC_PR(BT_DBG, "\t\t*-Scan SPI nand flash on CS: %d\n", cs); + if (nand_scan(mtd, chip_num)) { + continue; + } + chip_num--; + } + + if (chip_num == CONFIG_SPI_NAND_MAX_CHIP_NUM) { + result = -ENXIO; + } else { + result = 0; + } + + return result; +} + +/*****************************************************************************/ +static int bsp_spi_nand_probe(struct platform_device *pltdev) +{ + int len, result = 0; + struct fmc_host *host = NULL; + struct nand_chip *chip = NULL; + struct mtd_info *mtd = NULL; + struct device *dev = &pltdev->dev; + struct device_node *np = NULL; + struct bsp_fmc *fmc = dev_get_drvdata(dev->parent); + + FMC_PR(BT_DBG, "\t*-Start SPI Nand flash driver probe\n"); + + if (!fmc) { + dev_err(dev, "get mfd fmc devices failed\n"); + return -ENXIO; + } + + len = sizeof(struct fmc_host) + sizeof(struct nand_chip) + + sizeof(struct mtd_info); + host = devm_kzalloc(dev, len, GFP_KERNEL); + if (!host) { + return -ENOMEM; + } + memset((char *)host, 0, len); + + platform_set_drvdata(pltdev, host); + host->dev = &pltdev->dev; + + host->chip = chip = (struct nand_chip *)&host[1]; + host->mtd = mtd = nand_to_mtd(chip); + + host->regbase = fmc->regbase; + host->iobase = fmc->iobase; + host->clk = fmc->clk; + host->lock = &fmc->lock; + host->buffer = fmc->buffer; + host->dma_buffer = fmc->dma_buffer; + + memset((char *)host->iobase, 0xff, fmc->dma_len); + chip->IO_ADDR_R = chip->IO_ADDR_W = host->iobase; + + chip->priv = host; + result = fmc100_spi_nand_init(chip); + if (result) { + FMC_PR(BT_DBG, "\t|-SPI Nand init failed, ret: %d\n", result); + result = -ENODEV; + goto fail; + } + + np = of_get_next_available_child(dev->of_node, NULL); + mtd->name = np->name; + mtd->type = MTD_NANDFLASH; + mtd->priv = chip; + mtd->owner = THIS_MODULE; + + result = of_property_read_u32(np, "spi-max-frequency", &host->clkrate); + if (result) { + goto fail; + } + + result = fmc_nand_scan(mtd); + if (result) { + FMC_PR(BT_DBG, "\t|-Scan SPI Nand failed.\n"); + goto fail; + } + + result = mtd_device_register(mtd, NULL, 0); + if (!result) { + FMC_PR(BT_DBG, "\t*-End driver probe !!\n"); + return 0; + } + + result = -ENODEV; +fail: + clk_disable_unprepare(host->clk); + nand_release(mtd); + + DB_MSG("Error: driver probe, result: %d\n", result); + return result; +} + +/*****************************************************************************/ +static int bsp_spi_nand_remove(struct platform_device *pltdev) +{ + struct fmc_host *host = platform_get_drvdata(pltdev); + if (host == NULL){ + FMC_PR(BT_DBG, "\t*host is NULL ,remove err !!\n"); + return 0; + } + clk_disable_unprepare(host->clk); + nand_release(host->mtd); + + return 0; +} + +#ifdef CONFIG_PM +/*****************************************************************************/ +static int fmc100_os_suspend(struct platform_device *pltdev, + pm_message_t state) +{ + struct fmc_host *host = platform_get_drvdata(pltdev); + + if (host && host->suspend) { + return (host->suspend)(pltdev, state); + } + + return 0; +} + +/*****************************************************************************/ +static int fmc100_os_resume(struct platform_device *pltdev) +{ + struct fmc_host *host = platform_get_drvdata(pltdev); + + if (host && host->resume) { + return (host->resume)(pltdev); + } + + return 0; +} +#endif /* End of CONFIG_PM */ +/*****************************************************************************/ +static const struct of_device_id bsp_spi_nand_dt_ids[] = { + { .compatible = "goke,fmc-spi-nand"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bsp_spi_nand_dt_ids); + +static struct platform_driver bsp_spi_nand_driver = { + .driver = { + .name = "bsp_spi_nand", + .of_match_table = bsp_spi_nand_dt_ids, + }, + .probe = bsp_spi_nand_probe, + .remove = bsp_spi_nand_remove, +#ifdef CONFIG_PM + .suspend = fmc100_os_suspend, + .resume = fmc100_os_resume, +#endif +}; +module_platform_driver(bsp_spi_nand_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Goke Flash Memory Controller V100 SPI Nand Driver");