mirror of https://github.com/OpenIPC/firmware.git
227 lines
5.8 KiB
Diff
227 lines
5.8 KiB
Diff
--- 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 <linux/kernel.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include <linux/mtd/nand.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/of_platform.h>
|
|
+#include <asm/setup.h>
|
|
+
|
|
+#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");
|