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");
 |