mtd: rawnand: stm32_fmc2: get resources from parent node
FMC2 EBI support has been added. Common resources (registers base address and clock) can now be shared between the 2 drivers using "st,stm32mp1-fmc2-nfc" compatible string. It means that the common resources should now be found in the parent device when EBI node is available. Signed-off-by: Christophe Kerello <christophe.kerello@st.com> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/linux-mtd/1591975362-22009-7-git-send-email-christophe.kerello@st.com
This commit is contained in:
parent
51c88a8d3b
commit
fbd9b5437b
|
@ -415,8 +415,7 @@ config MTD_NAND_TEGRA
|
|||
config MTD_NAND_STM32_FMC2
|
||||
tristate "Support for NAND controller on STM32MP SoCs"
|
||||
depends on MACH_STM32MP157 || COMPILE_TEST
|
||||
select REGMAP
|
||||
select REGMAP_MMIO
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Enables support for NAND Flash chips on SoCs containing the FMC2
|
||||
NAND controller. This controller is found on STM32MP SoCs.
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
@ -204,16 +206,6 @@
|
|||
#define FMC2_BCHDSR4_EBP7 GENMASK(12, 0)
|
||||
#define FMC2_BCHDSR4_EBP8 GENMASK(28, 16)
|
||||
|
||||
/* Regmap registers configuration */
|
||||
#define FMC2_MAX_REGISTER 0x3fc
|
||||
|
||||
static const struct regmap_config stm32_fmc2_regmap_cfg = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = sizeof(u32),
|
||||
.max_register = FMC2_MAX_REGISTER,
|
||||
};
|
||||
|
||||
enum stm32_fmc2_ecc {
|
||||
FMC2_ECC_HAM = 1,
|
||||
FMC2_ECC_BCH4 = 4,
|
||||
|
@ -253,6 +245,7 @@ struct stm32_fmc2_nfc {
|
|||
struct nand_controller base;
|
||||
struct stm32_fmc2_nand nand;
|
||||
struct device *dev;
|
||||
struct device *cdev;
|
||||
struct regmap *regmap;
|
||||
void __iomem *data_base[FMC2_MAX_CE];
|
||||
void __iomem *cmd_base[FMC2_MAX_CE];
|
||||
|
@ -1384,8 +1377,9 @@ static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc)
|
|||
pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT);
|
||||
|
||||
/* Enable FMC2 controller */
|
||||
regmap_update_bits(nfc->regmap, FMC2_BCR1,
|
||||
FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN);
|
||||
if (nfc->dev == nfc->cdev)
|
||||
regmap_update_bits(nfc->regmap, FMC2_BCR1,
|
||||
FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN);
|
||||
|
||||
regmap_write(nfc->regmap, FMC2_PCR, pcr);
|
||||
regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT);
|
||||
|
@ -1815,6 +1809,33 @@ static int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_fmc2_nfc_set_cdev(struct stm32_fmc2_nfc *nfc)
|
||||
{
|
||||
struct device *dev = nfc->dev;
|
||||
bool ebi_found = false;
|
||||
|
||||
if (dev->parent && of_device_is_compatible(dev->parent->of_node,
|
||||
"st,stm32mp1-fmc2-ebi"))
|
||||
ebi_found = true;
|
||||
|
||||
if (of_device_is_compatible(dev->of_node, "st,stm32mp1-fmc2-nfc")) {
|
||||
if (ebi_found) {
|
||||
nfc->cdev = dev->parent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ebi_found)
|
||||
return -EINVAL;
|
||||
|
||||
nfc->cdev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -1824,8 +1845,9 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip *chip;
|
||||
void __iomem *mmio;
|
||||
struct resource cres;
|
||||
int chip_cs, mem_region, ret, irq;
|
||||
int start_region = 0;
|
||||
|
||||
nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
|
||||
if (!nfc)
|
||||
|
@ -1835,22 +1857,28 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
|
|||
nand_controller_init(&nfc->base);
|
||||
nfc->base.ops = &stm32_fmc2_nfc_controller_ops;
|
||||
|
||||
ret = stm32_fmc2_nfc_set_cdev(nfc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = stm32_fmc2_nfc_parse_dt(nfc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mmio = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(mmio))
|
||||
return PTR_ERR(mmio);
|
||||
ret = of_address_to_resource(nfc->cdev->of_node, 0, &cres);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nfc->regmap = devm_regmap_init_mmio(dev, mmio, &stm32_fmc2_regmap_cfg);
|
||||
nfc->io_phys_addr = cres.start;
|
||||
|
||||
nfc->regmap = device_node_to_regmap(nfc->cdev->of_node);
|
||||
if (IS_ERR(nfc->regmap))
|
||||
return PTR_ERR(nfc->regmap);
|
||||
|
||||
nfc->io_phys_addr = res->start;
|
||||
if (nfc->dev == nfc->cdev)
|
||||
start_region = 1;
|
||||
|
||||
for (chip_cs = 0, mem_region = 1; chip_cs < FMC2_MAX_CE;
|
||||
for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE;
|
||||
chip_cs++, mem_region += 3) {
|
||||
if (!(nfc->cs_assigned & BIT(chip_cs)))
|
||||
continue;
|
||||
|
@ -1888,7 +1916,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
|
|||
|
||||
init_completion(&nfc->complete);
|
||||
|
||||
nfc->clk = devm_clk_get(dev, NULL);
|
||||
nfc->clk = devm_clk_get(nfc->cdev, NULL);
|
||||
if (IS_ERR(nfc->clk))
|
||||
return PTR_ERR(nfc->clk);
|
||||
|
||||
|
@ -2029,6 +2057,7 @@ static SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend,
|
|||
|
||||
static const struct of_device_id stm32_fmc2_nfc_match[] = {
|
||||
{.compatible = "st,stm32mp15-fmc2"},
|
||||
{.compatible = "st,stm32mp1-fmc2-nfc"},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match);
|
||||
|
|
Loading…
Reference in New Issue