This patch moves common used resources (registers base, clocks, ...) in stm32_fmc2 structure. Signed-off-by: Christophe Kerello <christophe.kerello@xxxxxx> --- drivers/mtd/nand/raw/Kconfig | 1 + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 218 ++++++++++++++++++++++----------- 2 files changed, 150 insertions(+), 69 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 12b715a..ad7d887 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -421,6 +421,7 @@ config MTD_NAND_STM32_FMC2 depends on MACH_STM32MP157 || COMPILE_TEST select REGMAP select REGMAP_MMIO + select MFD_STM32_FMC2 help Enables support for NAND Flash chips on SoCs containing the FMC2 NAND controller. This controller is found on STM32MP SoCs. diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index bc16614..1dc568f 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -97,14 +97,12 @@ static inline struct stm32_fmc2_nand *to_fmc2_nand(struct nand_chip *chip) struct stm32_fmc2_nfc { struct nand_controller base; struct stm32_fmc2_nand nand; + struct stm32_fmc2 *fmc2; struct device *dev; - struct regmap *regmap; void __iomem *data_base[FMC2_MAX_CE]; void __iomem *cmd_base[FMC2_MAX_CE]; void __iomem *addr_base[FMC2_MAX_CE]; - phys_addr_t io_phys_addr; phys_addr_t data_phys_addr[FMC2_MAX_CE]; - struct clk *clk; u8 irq_state; struct dma_chan *dma_tx_ch; @@ -133,10 +131,11 @@ static void stm32_fmc2_nfc_timings_init(struct nand_chip *chip) struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); struct stm32_fmc2_timings *timings = &nand->timings; + struct stm32_fmc2 *fmc2 = nfc->fmc2; u32 pmem, patt; /* Set tclr/tar timings */ - regmap_update_bits(nfc->regmap, FMC2_PCR, + regmap_update_bits(fmc2->regmap, FMC2_PCR, FMC2_PCR_TCLR | FMC2_PCR_TAR, FIELD_PREP(FMC2_PCR_TCLR, timings->tclr) | FIELD_PREP(FMC2_PCR_TAR, timings->tar)); @@ -146,19 +145,20 @@ static void stm32_fmc2_nfc_timings_init(struct nand_chip *chip) pmem |= FIELD_PREP(FMC2_PMEM_MEMWAIT, timings->twait); pmem |= FIELD_PREP(FMC2_PMEM_MEMHOLD, timings->thold_mem); pmem |= FIELD_PREP(FMC2_PMEM_MEMHIZ, timings->thiz); - regmap_write(nfc->regmap, FMC2_PMEM, pmem); + regmap_write(fmc2->regmap, FMC2_PMEM, pmem); /* Set tset/twait/thold/thiz timings in attribut bank */ patt = FIELD_PREP(FMC2_PATT_ATTSET, timings->tset_att); patt |= FIELD_PREP(FMC2_PATT_ATTWAIT, timings->twait); patt |= FIELD_PREP(FMC2_PATT_ATTHOLD, timings->thold_att); patt |= FIELD_PREP(FMC2_PATT_ATTHIZ, timings->thiz); - regmap_write(nfc->regmap, FMC2_PATT, patt); + regmap_write(fmc2->regmap, FMC2_PATT, patt); } static void stm32_fmc2_nfc_setup(struct nand_chip *chip) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2 *fmc2 = nfc->fmc2; u32 pcr = 0, pcr_mask; /* Configure ECC algorithm (default configuration is Hamming) */ @@ -180,13 +180,14 @@ static void stm32_fmc2_nfc_setup(struct nand_chip *chip) pcr_mask |= FMC2_PCR_ECCSS; pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_512); - regmap_update_bits(nfc->regmap, FMC2_PCR, pcr_mask, pcr); + regmap_update_bits(fmc2->regmap, FMC2_PCR, pcr_mask, pcr); } static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); + struct stm32_fmc2 *fmc2 = nfc->fmc2; struct dma_slave_config dma_cfg; int ret; @@ -225,7 +226,7 @@ static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr) * BCH4/BCH8: we read BCHDSRSx registers */ memset(&dma_cfg, 0, sizeof(dma_cfg)); - dma_cfg.src_addr = nfc->io_phys_addr; + dma_cfg.src_addr = fmc2->reg_phys_addr; dma_cfg.src_addr += chip->ecc.strength == FMC2_ECC_HAM ? FMC2_HECCR : FMC2_BCHDSR0; dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -246,55 +247,68 @@ static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr) static void stm32_fmc2_nfc_set_buswidth_16(struct stm32_fmc2_nfc *nfc, bool set) { + struct stm32_fmc2 *fmc2 = nfc->fmc2; u32 pcr; pcr = set ? FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16) : FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_8); - regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_PWID, pcr); + regmap_update_bits(fmc2->regmap, FMC2_PCR, FMC2_PCR_PWID, pcr); } static void stm32_fmc2_nfc_set_ecc(struct stm32_fmc2_nfc *nfc, bool enable) { - regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_ECCEN, + struct stm32_fmc2 *fmc2 = nfc->fmc2; + + regmap_update_bits(fmc2->regmap, FMC2_PCR, FMC2_PCR_ECCEN, enable ? FMC2_PCR_ECCEN : 0); } static void stm32_fmc2_nfc_enable_seq_irq(struct stm32_fmc2_nfc *nfc) { + struct stm32_fmc2 *fmc2 = nfc->fmc2; + nfc->irq_state = FMC2_IRQ_SEQ; - regmap_update_bits(nfc->regmap, FMC2_CSQIER, + regmap_update_bits(fmc2->regmap, FMC2_CSQIER, FMC2_CSQIER_TCIE, FMC2_CSQIER_TCIE); } static void stm32_fmc2_nfc_disable_seq_irq(struct stm32_fmc2_nfc *nfc) { - regmap_update_bits(nfc->regmap, FMC2_CSQIER, FMC2_CSQIER_TCIE, 0); + struct stm32_fmc2 *fmc2 = nfc->fmc2; + + regmap_update_bits(fmc2->regmap, FMC2_CSQIER, FMC2_CSQIER_TCIE, 0); nfc->irq_state = FMC2_IRQ_UNKNOWN; } static void stm32_fmc2_nfc_clear_seq_irq(struct stm32_fmc2_nfc *nfc) { - regmap_write(nfc->regmap, FMC2_CSQICR, FMC2_CSQICR_CLEAR_IRQ); + struct stm32_fmc2 *fmc2 = nfc->fmc2; + + regmap_write(fmc2->regmap, FMC2_CSQICR, FMC2_CSQICR_CLEAR_IRQ); } static void stm32_fmc2_nfc_enable_bch_irq(struct stm32_fmc2_nfc *nfc, int mode) { + struct stm32_fmc2 *fmc2 = nfc->fmc2; + nfc->irq_state = FMC2_IRQ_BCH; if (mode == NAND_ECC_WRITE) - regmap_update_bits(nfc->regmap, FMC2_BCHIER, + regmap_update_bits(fmc2->regmap, FMC2_BCHIER, FMC2_BCHIER_EPBRIE, FMC2_BCHIER_EPBRIE); else - regmap_update_bits(nfc->regmap, FMC2_BCHIER, + regmap_update_bits(fmc2->regmap, FMC2_BCHIER, FMC2_BCHIER_DERIE, FMC2_BCHIER_DERIE); } static void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc) { - regmap_update_bits(nfc->regmap, FMC2_BCHIER, + struct stm32_fmc2 *fmc2 = nfc->fmc2; + + regmap_update_bits(fmc2->regmap, FMC2_BCHIER, FMC2_BCHIER_DERIE | FMC2_BCHIER_EPBRIE, 0); nfc->irq_state = FMC2_IRQ_UNKNOWN; @@ -302,7 +316,9 @@ static void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc) static void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc) { - regmap_write(nfc->regmap, FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ); + struct stm32_fmc2 *fmc2 = nfc->fmc2; + + regmap_write(fmc2->regmap, FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ); } /* @@ -312,11 +328,12 @@ static void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc) static void stm32_fmc2_nfc_hwctl(struct nand_chip *chip, int mode) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2 *fmc2 = nfc->fmc2; stm32_fmc2_nfc_set_ecc(nfc, false); if (chip->ecc.strength != FMC2_ECC_HAM) { - regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN, + regmap_update_bits(fmc2->regmap, FMC2_PCR, FMC2_PCR_WEN, mode == NAND_ECC_WRITE ? FMC2_PCR_WEN : 0); reinit_completion(&nfc->complete); @@ -343,10 +360,11 @@ static int stm32_fmc2_nfc_ham_calculate(struct nand_chip *chip, const u8 *data, u8 *ecc) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2 *fmc2 = nfc->fmc2; u32 sr, heccr; int ret; - ret = regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr, + ret = regmap_read_poll_timeout(fmc2->regmap, FMC2_SR, sr, sr & FMC2_SR_NWRF, 1, 1000 * FMC2_TIMEOUT_MS); if (ret) { @@ -354,7 +372,7 @@ static int stm32_fmc2_nfc_ham_calculate(struct nand_chip *chip, const u8 *data, return ret; } - regmap_read(nfc->regmap, FMC2_HECCR, &heccr); + regmap_read(fmc2->regmap, FMC2_HECCR, &heccr); stm32_fmc2_nfc_ham_set_ecc(heccr, ecc); stm32_fmc2_nfc_set_ecc(nfc, false); @@ -422,6 +440,7 @@ static int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data, u8 *ecc) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2 *fmc2 = nfc->fmc2; u32 bchpbr; /* Wait until the BCH code is ready */ @@ -433,13 +452,13 @@ static int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data, } /* Read parity bits */ - regmap_read(nfc->regmap, FMC2_BCHPBR1, &bchpbr); + regmap_read(fmc2->regmap, FMC2_BCHPBR1, &bchpbr); ecc[0] = bchpbr; ecc[1] = bchpbr >> 8; ecc[2] = bchpbr >> 16; ecc[3] = bchpbr >> 24; - regmap_read(nfc->regmap, FMC2_BCHPBR2, &bchpbr); + regmap_read(fmc2->regmap, FMC2_BCHPBR2, &bchpbr); ecc[4] = bchpbr; ecc[5] = bchpbr >> 8; ecc[6] = bchpbr >> 16; @@ -447,13 +466,13 @@ static int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data, if (chip->ecc.strength == FMC2_ECC_BCH8) { ecc[7] = bchpbr >> 24; - regmap_read(nfc->regmap, FMC2_BCHPBR3, &bchpbr); + regmap_read(fmc2->regmap, FMC2_BCHPBR3, &bchpbr); ecc[8] = bchpbr; ecc[9] = bchpbr >> 8; ecc[10] = bchpbr >> 16; ecc[11] = bchpbr >> 24; - regmap_read(nfc->regmap, FMC2_BCHPBR4, &bchpbr); + regmap_read(fmc2->regmap, FMC2_BCHPBR4, &bchpbr); ecc[12] = bchpbr; } @@ -505,6 +524,7 @@ static int stm32_fmc2_nfc_bch_correct(struct nand_chip *chip, u8 *dat, u8 *read_ecc, u8 *calc_ecc) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2 *fmc2 = nfc->fmc2; u32 ecc_sta[5]; /* Wait until the decoding error is ready */ @@ -515,11 +535,11 @@ static int stm32_fmc2_nfc_bch_correct(struct nand_chip *chip, u8 *dat, return -ETIMEDOUT; } - regmap_read(nfc->regmap, FMC2_BCHDSR0, &ecc_sta[0]); - regmap_read(nfc->regmap, FMC2_BCHDSR1, &ecc_sta[1]); - regmap_read(nfc->regmap, FMC2_BCHDSR2, &ecc_sta[2]); - regmap_read(nfc->regmap, FMC2_BCHDSR3, &ecc_sta[3]); - regmap_read(nfc->regmap, FMC2_BCHDSR4, &ecc_sta[4]); + regmap_read(fmc2->regmap, FMC2_BCHDSR0, &ecc_sta[0]); + regmap_read(fmc2->regmap, FMC2_BCHDSR1, &ecc_sta[1]); + regmap_read(fmc2->regmap, FMC2_BCHDSR2, &ecc_sta[2]); + regmap_read(fmc2->regmap, FMC2_BCHDSR3, &ecc_sta[3]); + regmap_read(fmc2->regmap, FMC2_BCHDSR4, &ecc_sta[4]); stm32_fmc2_nfc_set_ecc(nfc, false); @@ -593,12 +613,13 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page, int raw, bool write_data) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2 *fmc2 = nfc->fmc2; struct mtd_info *mtd = nand_to_mtd(chip); u32 csqcfgr1, csqcfgr2, csqcfgr3; u32 csqar1, csqar2; u32 ecc_offset = mtd->writesize + FMC2_BBM_LEN; - regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN, + regmap_update_bits(fmc2->regmap, FMC2_PCR, FMC2_PCR_WEN, write_data ? FMC2_PCR_WEN : 0); /* @@ -674,11 +695,11 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page, csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 4); } - regmap_write(nfc->regmap, FMC2_CSQCFGR1, csqcfgr1); - regmap_write(nfc->regmap, FMC2_CSQCFGR2, csqcfgr2); - regmap_write(nfc->regmap, FMC2_CSQCFGR3, csqcfgr3); - regmap_write(nfc->regmap, FMC2_CSQAR1, csqar1); - regmap_write(nfc->regmap, FMC2_CSQAR2, csqar2); + regmap_write(fmc2->regmap, FMC2_CSQCFGR1, csqcfgr1); + regmap_write(fmc2->regmap, FMC2_CSQCFGR2, csqcfgr2); + regmap_write(fmc2->regmap, FMC2_CSQCFGR3, csqcfgr3); + regmap_write(fmc2->regmap, FMC2_CSQAR1, csqar1); + regmap_write(fmc2->regmap, FMC2_CSQAR2, csqar2); } static void stm32_fmc2_nfc_dma_callback(void *arg) @@ -691,6 +712,7 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, int raw, bool write_data) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2 *fmc2 = nfc->fmc2; struct dma_async_tx_descriptor *desc_data, *desc_ecc; struct scatterlist *sg; struct dma_chan *dma_ch = nfc->dma_rx_ch; @@ -773,7 +795,7 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, stm32_fmc2_nfc_enable_seq_irq(nfc); /* Start the transfer */ - regmap_update_bits(nfc->regmap, FMC2_CSQCR, + regmap_update_bits(fmc2->regmap, FMC2_CSQCR, FMC2_CSQCR_CSQSTART, FMC2_CSQCR_CSQSTART); /* Wait end of sequencer transfer */ @@ -869,9 +891,10 @@ static int stm32_fmc2_nfc_seq_write_page_raw(struct nand_chip *chip, /* Get a status indicating which sectors have errors */ static u16 stm32_fmc2_nfc_get_mapping_status(struct stm32_fmc2_nfc *nfc) { + struct stm32_fmc2 *fmc2 = nfc->fmc2; u32 csqemsr; - regmap_read(nfc->regmap, FMC2_CSQEMSR, &csqemsr); + regmap_read(fmc2->regmap, FMC2_CSQEMSR, &csqemsr); return FIELD_GET(FMC2_CSQEMSR_SEM, csqemsr); } @@ -1125,11 +1148,12 @@ static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2 *fmc2 = nfc->fmc2; const struct nand_sdr_timings *timings; u32 isr, sr; /* Check if there is no pending requests to the NAND flash */ - if (regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr, + if (regmap_read_poll_timeout(fmc2->regmap, FMC2_SR, sr, sr & FMC2_SR_NWRF, 1, 1000 * FMC2_TIMEOUT_MS)) dev_warn(nfc->dev, "Waitrdy timeout\n"); @@ -1139,10 +1163,10 @@ static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip, ndelay(PSEC_TO_NSEC(timings->tWB_max)); /* R/B# signal is low, clear high level flag */ - regmap_write(nfc->regmap, FMC2_ICR, FMC2_ICR_CIHLF); + regmap_write(fmc2->regmap, FMC2_ICR, FMC2_ICR_CIHLF); /* Wait R/B# signal is high */ - return regmap_read_poll_timeout(nfc->regmap, FMC2_ISR, isr, + return regmap_read_poll_timeout(fmc2->regmap, FMC2_ISR, isr, isr & FMC2_ISR_IHLF, 5, 1000 * FMC2_TIMEOUT_MS); } @@ -1202,9 +1226,10 @@ static int stm32_fmc2_nfc_exec_op(struct nand_chip *chip, static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc) { + struct stm32_fmc2 *fmc2 = nfc->fmc2; u32 pcr; - regmap_read(nfc->regmap, FMC2_PCR, &pcr); + regmap_read(fmc2->regmap, FMC2_PCR, &pcr); /* Set CS used to undefined */ nfc->cs_sel = -1; @@ -1234,13 +1259,9 @@ static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc) pcr &= ~FMC2_PCR_TAR; 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); - - regmap_write(nfc->regmap, FMC2_PCR, pcr); - regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT); - regmap_write(nfc->regmap, FMC2_PATT, FMC2_PATT_DEFAULT); + regmap_write(fmc2->regmap, FMC2_PCR, pcr); + regmap_write(fmc2->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT); + regmap_write(fmc2->regmap, FMC2_PATT, FMC2_PATT_DEFAULT); } static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip, @@ -1249,7 +1270,8 @@ static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip, struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); struct stm32_fmc2_timings *tims = &nand->timings; - unsigned long hclk = clk_get_rate(nfc->clk); + struct stm32_fmc2 *fmc2 = nfc->fmc2; + unsigned long hclk = clk_get_rate(fmc2->clk); unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000); unsigned long timing, tar, tclr, thiz, twait; unsigned long tset_mem, tset_att, thold_mem, thold_att; @@ -1666,17 +1688,57 @@ static int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc) return ret; } +static void stm32_fmc2_nfc_enable(struct stm32_fmc2 *fmc2) +{ + regmap_update_bits(fmc2->regmap, FMC2_BCR1, + FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); +} + +static void stm32_fmc2_nfc_disable(struct stm32_fmc2 *fmc2) +{ + regmap_update_bits(fmc2->regmap, FMC2_BCR1, FMC2_BCR1_FMC2EN, 0); +} + +static int stm32_fmc2_nfc_set_mmio_clk(struct platform_device *pdev, + struct stm32_fmc2 *fmc2) +{ + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *mmio; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(mmio)) + return PTR_ERR(mmio); + + fmc2->regmap = devm_regmap_init_mmio(dev, mmio, &stm32_fmc2_regmap_cfg); + if (IS_ERR(fmc2->regmap)) + return PTR_ERR(fmc2->regmap); + + fmc2->reg_phys_addr = res->start; + + fmc2->clk = devm_clk_get(dev, NULL); + if (IS_ERR(fmc2->clk)) + return PTR_ERR(fmc2->clk); + + fmc2->enable = stm32_fmc2_nfc_enable; + fmc2->disable = stm32_fmc2_nfc_disable; + + return 0; +} + static int stm32_fmc2_nfc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct reset_control *rstc; + struct stm32_fmc2 *fmc2; struct stm32_fmc2_nfc *nfc; struct stm32_fmc2_nand *nand; struct resource *res; struct mtd_info *mtd; struct nand_chip *chip; - void __iomem *mmio; int chip_cs, mem_region, ret, irq; + int num_region = 0; nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); if (!nfc) @@ -1690,18 +1752,27 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) 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); + fmc2 = dev_get_drvdata(dev->parent); + if (!fmc2) { + num_region = 1; - nfc->regmap = devm_regmap_init_mmio(dev, mmio, &stm32_fmc2_regmap_cfg); - if (IS_ERR(nfc->regmap)) - return PTR_ERR(nfc->regmap); + fmc2 = devm_kzalloc(dev, sizeof(*fmc2), GFP_KERNEL); + if (!fmc2) + return -ENOMEM; - nfc->io_phys_addr = res->start; + ret = stm32_fmc2_nfc_set_mmio_clk(pdev, fmc2); + if (ret) + return ret; + } + nfc->fmc2 = fmc2; - for (chip_cs = 0, mem_region = 1; chip_cs < FMC2_MAX_CE; + if (atomic_inc_return(&fmc2->nwait_is_used) > 1) { + dev_err(dev, "NWAIT signal in used by a FMC controller\n"); + atomic_dec(&fmc2->nwait_is_used); + return -EINVAL; + } + + for (chip_cs = 0, mem_region = num_region; chip_cs < FMC2_MAX_CE; chip_cs++, mem_region += 3) { if (!(nfc->cs_assigned & BIT(chip_cs))) continue; @@ -1739,11 +1810,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) init_completion(&nfc->complete); - nfc->clk = devm_clk_get(dev, NULL); - if (IS_ERR(nfc->clk)) - return PTR_ERR(nfc->clk); - - ret = clk_prepare_enable(nfc->clk); + ret = clk_prepare_enable(fmc2->clk); if (ret) { dev_err(dev, "can not enable the clock\n"); return ret; @@ -1763,6 +1830,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) if (ret) goto err_dma_setup; + fmc2->enable(fmc2); stm32_fmc2_nfc_init(nfc); nand = &nfc->nand; @@ -1782,7 +1850,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) /* Scan to find existence of the device */ ret = nand_scan(chip, nand->ncs); if (ret) - goto err_dma_setup; + goto err_nand_scan; ret = mtd_device_register(mtd, NULL, 0); if (ret) @@ -1795,6 +1863,10 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) err_device_register: nand_cleanup(chip); +err_nand_scan: + regmap_update_bits(fmc2->regmap, FMC2_PCR, FMC2_PCR_PBKEN, 0); + fmc2->disable(fmc2); + err_dma_setup: if (nfc->dma_ecc_ch) dma_release_channel(nfc->dma_ecc_ch); @@ -1807,7 +1879,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) sg_free_table(&nfc->dma_ecc_sg); err_clk_disable: - clk_disable_unprepare(nfc->clk); + clk_disable_unprepare(fmc2->clk); return ret; } @@ -1816,7 +1888,11 @@ static int stm32_fmc2_nfc_remove(struct platform_device *pdev) { struct stm32_fmc2_nfc *nfc = platform_get_drvdata(pdev); struct stm32_fmc2_nand *nand = &nfc->nand; + struct stm32_fmc2 *fmc2 = nfc->fmc2; + regmap_update_bits(fmc2->regmap, FMC2_PCR, FMC2_PCR_PBKEN, 0); + atomic_dec(&fmc2->nwait_is_used); + fmc2->disable(fmc2); nand_release(&nand->chip); if (nfc->dma_ecc_ch) @@ -1829,7 +1905,7 @@ static int stm32_fmc2_nfc_remove(struct platform_device *pdev) sg_free_table(&nfc->dma_data_sg); sg_free_table(&nfc->dma_ecc_sg); - clk_disable_unprepare(nfc->clk); + clk_disable_unprepare(fmc2->clk); return 0; } @@ -1837,8 +1913,10 @@ static int stm32_fmc2_nfc_remove(struct platform_device *pdev) static int __maybe_unused stm32_fmc2_nfc_suspend(struct device *dev) { struct stm32_fmc2_nfc *nfc = dev_get_drvdata(dev); + struct stm32_fmc2 *fmc2 = nfc->fmc2; - clk_disable_unprepare(nfc->clk); + fmc2->disable(fmc2); + clk_disable_unprepare(fmc2->clk); pinctrl_pm_select_sleep_state(dev); @@ -1849,16 +1927,18 @@ static int __maybe_unused stm32_fmc2_nfc_resume(struct device *dev) { struct stm32_fmc2_nfc *nfc = dev_get_drvdata(dev); struct stm32_fmc2_nand *nand = &nfc->nand; + struct stm32_fmc2 *fmc2 = nfc->fmc2; int chip_cs, ret; pinctrl_pm_select_default_state(dev); - ret = clk_prepare_enable(nfc->clk); + ret = clk_prepare_enable(fmc2->clk); if (ret) { dev_err(dev, "can not enable the clock\n"); return ret; } + fmc2->enable(fmc2); stm32_fmc2_nfc_init(nfc); for (chip_cs = 0; chip_cs < FMC2_MAX_CE; chip_cs++) { -- 1.9.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/