--- linux-4.9.37/drivers/mfd/goke_fmc.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-4.9.y/drivers/mfd/goke_fmc.c 2021-06-07 13:01:33.000000000 +0300 @@ -0,0 +1,121 @@ +/* + * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned char fmc_cs_user[FMC_MAX_CHIP_NUM]; + +DEFINE_MUTEX(fmc_switch_mutex); +EXPORT_SYMBOL_GPL(fmc_switch_mutex); + +/* ------------------------------------------------------------------------ */ +static const struct mfd_cell bsp_fmc_devs[] = { + { + .name = "bsp_spi_nor", + .of_compatible = "goke,fmc-spi-nor", + }, + { + .name = "bsp_spi_nand", + .of_compatible = "goke,fmc-spi-nand", + }, +}; + +static int bsp_fmc_probe(struct platform_device *pdev) +{ + struct bsp_fmc *fmc; + struct resource *res; + struct device *dev = &pdev->dev; + int ret; + + fmc = devm_kzalloc(dev, sizeof(*fmc), GFP_KERNEL); + if (!fmc) { + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control"); + fmc->regbase = devm_ioremap_resource(dev, res); + if (IS_ERR(fmc->regbase)) { + return PTR_ERR(fmc->regbase); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); + fmc->iobase = devm_ioremap_resource(dev, res); + if (IS_ERR(fmc->iobase)) { + return PTR_ERR(fmc->iobase); + } + + fmc->clk = devm_clk_get(dev, NULL); + if (IS_ERR(fmc->clk)) { + return PTR_ERR(fmc->clk); + } + + if (of_property_read_u32(dev->of_node, "max-dma-size", &fmc->dma_len)) { + dev_err(dev, "Please set the suitable max-dma-size value !!!\n"); + return -ENOMEM; + } + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) { + dev_warn(dev, "Unable to set dma mask\n"); + return ret; + } + + fmc->buffer = dmam_alloc_coherent(dev, fmc->dma_len, + &fmc->dma_buffer, GFP_KERNEL); + if (IS_ERR(fmc->buffer)) { + return PTR_ERR(fmc->buffer); + } + + mutex_init(&fmc->lock); + + platform_set_drvdata(pdev, fmc); + + ret = mfd_add_devices(dev, 0, bsp_fmc_devs, + ARRAY_SIZE(bsp_fmc_devs), NULL, 0, NULL); + if (ret) { + dev_err(dev, "add mfd devices failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int bsp_fmc_remove(struct platform_device *pdev) +{ + struct bsp_fmc *fmc = platform_get_drvdata(pdev); + + dmam_free_coherent(&pdev->dev, fmc->dma_len, + fmc->buffer, fmc->dma_buffer); + mfd_remove_devices(&pdev->dev); + mutex_destroy(&fmc->lock); + + return 0; +} + +static const struct of_device_id bsp_fmc_of_match_tbl[] = { + { .compatible = "goke,fmc"}, + { } +}; +MODULE_DEVICE_TABLE(of, bsp_fmc_of_match_tbl); + +static struct platform_driver bsp_fmc_driver = { + .driver = { + .name = "fmc", + .of_match_table = bsp_fmc_of_match_tbl, + }, + .probe = bsp_fmc_probe, + .remove = bsp_fmc_remove, +}; +module_platform_driver(bsp_fmc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Goke Flash Memory Controller Driver");