xref: /linux/drivers/mtd/nand/raw/txx9ndfmc.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
264fb65baSAtsushi Nemoto /*
364fb65baSAtsushi Nemoto  * TXx9 NAND flash memory controller driver
464fb65baSAtsushi Nemoto  * Based on RBTX49xx patch from CELF patch archive.
564fb65baSAtsushi Nemoto  *
664fb65baSAtsushi Nemoto  * (C) Copyright TOSHIBA CORPORATION 2004-2007
764fb65baSAtsushi Nemoto  * All Rights Reserved.
864fb65baSAtsushi Nemoto  */
9b0de774cSThierry Reding #include <linux/err.h>
1064fb65baSAtsushi Nemoto #include <linux/init.h>
1164fb65baSAtsushi Nemoto #include <linux/slab.h>
1264fb65baSAtsushi Nemoto #include <linux/module.h>
1364fb65baSAtsushi Nemoto #include <linux/platform_device.h>
1464fb65baSAtsushi Nemoto #include <linux/delay.h>
1564fb65baSAtsushi Nemoto #include <linux/mtd/mtd.h>
16d4092d76SBoris Brezillon #include <linux/mtd/rawnand.h>
1764fb65baSAtsushi Nemoto #include <linux/mtd/partitions.h>
1864fb65baSAtsushi Nemoto #include <linux/io.h>
19dc2865acSBoris Brezillon #include <linux/platform_data/txx9/ndfmc.h>
2064fb65baSAtsushi Nemoto 
2164fb65baSAtsushi Nemoto /* TXX9 NDFMC Registers */
2264fb65baSAtsushi Nemoto #define TXX9_NDFDTR	0x00
2364fb65baSAtsushi Nemoto #define TXX9_NDFMCR	0x04
2464fb65baSAtsushi Nemoto #define TXX9_NDFSR	0x08
2564fb65baSAtsushi Nemoto #define TXX9_NDFISR	0x0c
2664fb65baSAtsushi Nemoto #define TXX9_NDFIMR	0x10
2764fb65baSAtsushi Nemoto #define TXX9_NDFSPR	0x14
2864fb65baSAtsushi Nemoto #define TXX9_NDFRSTR	0x18	/* not TX4939 */
2964fb65baSAtsushi Nemoto 
3064fb65baSAtsushi Nemoto /* NDFMCR : NDFMC Mode Control */
3164fb65baSAtsushi Nemoto #define TXX9_NDFMCR_WE	0x80
3264fb65baSAtsushi Nemoto #define TXX9_NDFMCR_ECC_ALL	0x60
3364fb65baSAtsushi Nemoto #define TXX9_NDFMCR_ECC_RESET	0x60
3464fb65baSAtsushi Nemoto #define TXX9_NDFMCR_ECC_READ	0x40
3564fb65baSAtsushi Nemoto #define TXX9_NDFMCR_ECC_ON	0x20
3664fb65baSAtsushi Nemoto #define TXX9_NDFMCR_ECC_OFF	0x00
3764fb65baSAtsushi Nemoto #define TXX9_NDFMCR_CE	0x10
3864fb65baSAtsushi Nemoto #define TXX9_NDFMCR_BSPRT	0x04	/* TX4925/TX4926 only */
3964fb65baSAtsushi Nemoto #define TXX9_NDFMCR_ALE	0x02
4064fb65baSAtsushi Nemoto #define TXX9_NDFMCR_CLE	0x01
4164fb65baSAtsushi Nemoto /* TX4939 only */
4264fb65baSAtsushi Nemoto #define TXX9_NDFMCR_X16	0x0400
4364fb65baSAtsushi Nemoto #define TXX9_NDFMCR_DMAREQ_MASK	0x0300
4464fb65baSAtsushi Nemoto #define TXX9_NDFMCR_DMAREQ_NODMA	0x0000
4564fb65baSAtsushi Nemoto #define TXX9_NDFMCR_DMAREQ_128	0x0100
4664fb65baSAtsushi Nemoto #define TXX9_NDFMCR_DMAREQ_256	0x0200
4764fb65baSAtsushi Nemoto #define TXX9_NDFMCR_DMAREQ_512	0x0300
4864fb65baSAtsushi Nemoto #define TXX9_NDFMCR_CS_MASK	0x0c
4964fb65baSAtsushi Nemoto #define TXX9_NDFMCR_CS(ch)	((ch) << 2)
5064fb65baSAtsushi Nemoto 
5164fb65baSAtsushi Nemoto /* NDFMCR : NDFMC Status */
5264fb65baSAtsushi Nemoto #define TXX9_NDFSR_BUSY	0x80
5364fb65baSAtsushi Nemoto /* TX4939 only */
5464fb65baSAtsushi Nemoto #define TXX9_NDFSR_DMARUN	0x40
5564fb65baSAtsushi Nemoto 
5664fb65baSAtsushi Nemoto /* NDFMCR : NDFMC Reset */
5764fb65baSAtsushi Nemoto #define TXX9_NDFRSTR_RST	0x01
5864fb65baSAtsushi Nemoto 
5964fb65baSAtsushi Nemoto struct txx9ndfmc_priv {
6064fb65baSAtsushi Nemoto 	struct platform_device *dev;
6164fb65baSAtsushi Nemoto 	struct nand_chip chip;
6264fb65baSAtsushi Nemoto 	int cs;
6381933046SDavid Woodhouse 	const char *mtdname;
6464fb65baSAtsushi Nemoto };
6564fb65baSAtsushi Nemoto 
6664fb65baSAtsushi Nemoto #define MAX_TXX9NDFMC_DEV	4
6764fb65baSAtsushi Nemoto struct txx9ndfmc_drvdata {
6864fb65baSAtsushi Nemoto 	struct mtd_info *mtds[MAX_TXX9NDFMC_DEV];
6964fb65baSAtsushi Nemoto 	void __iomem *base;
7064fb65baSAtsushi Nemoto 	unsigned char hold;	/* in gbusclock */
7164fb65baSAtsushi Nemoto 	unsigned char spw;	/* in gbusclock */
72a001058aSMiquel Raynal 	struct nand_controller controller;
7364fb65baSAtsushi Nemoto };
7464fb65baSAtsushi Nemoto 
7564fb65baSAtsushi Nemoto static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
7664fb65baSAtsushi Nemoto {
774bd4ebccSBoris BREZILLON 	struct nand_chip *chip = mtd_to_nand(mtd);
78d699ed25SBoris BREZILLON 	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
7964fb65baSAtsushi Nemoto 	return txx9_priv->dev;
8064fb65baSAtsushi Nemoto }
8164fb65baSAtsushi Nemoto 
8264fb65baSAtsushi Nemoto static void __iomem *ndregaddr(struct platform_device *dev, unsigned int reg)
8364fb65baSAtsushi Nemoto {
8464fb65baSAtsushi Nemoto 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
85453810b7SJingoo Han 	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
8664fb65baSAtsushi Nemoto 
8764fb65baSAtsushi Nemoto 	return drvdata->base + (reg << plat->shift);
8864fb65baSAtsushi Nemoto }
8964fb65baSAtsushi Nemoto 
9064fb65baSAtsushi Nemoto static u32 txx9ndfmc_read(struct platform_device *dev, unsigned int reg)
9164fb65baSAtsushi Nemoto {
9264fb65baSAtsushi Nemoto 	return __raw_readl(ndregaddr(dev, reg));
9364fb65baSAtsushi Nemoto }
9464fb65baSAtsushi Nemoto 
9564fb65baSAtsushi Nemoto static void txx9ndfmc_write(struct platform_device *dev,
9664fb65baSAtsushi Nemoto 			    u32 val, unsigned int reg)
9764fb65baSAtsushi Nemoto {
9864fb65baSAtsushi Nemoto 	__raw_writel(val, ndregaddr(dev, reg));
9964fb65baSAtsushi Nemoto }
10064fb65baSAtsushi Nemoto 
1017e534323SBoris Brezillon static uint8_t txx9ndfmc_read_byte(struct nand_chip *chip)
10264fb65baSAtsushi Nemoto {
1037e534323SBoris Brezillon 	struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
10464fb65baSAtsushi Nemoto 
10564fb65baSAtsushi Nemoto 	return txx9ndfmc_read(dev, TXX9_NDFDTR);
10664fb65baSAtsushi Nemoto }
10764fb65baSAtsushi Nemoto 
108c0739d85SBoris Brezillon static void txx9ndfmc_write_buf(struct nand_chip *chip, const uint8_t *buf,
10964fb65baSAtsushi Nemoto 				int len)
11064fb65baSAtsushi Nemoto {
111c0739d85SBoris Brezillon 	struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
11264fb65baSAtsushi Nemoto 	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
11364fb65baSAtsushi Nemoto 	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
11464fb65baSAtsushi Nemoto 
11564fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_WE, TXX9_NDFMCR);
11664fb65baSAtsushi Nemoto 	while (len--)
11764fb65baSAtsushi Nemoto 		__raw_writel(*buf++, ndfdtr);
11864fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
11964fb65baSAtsushi Nemoto }
12064fb65baSAtsushi Nemoto 
1217e534323SBoris Brezillon static void txx9ndfmc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
12264fb65baSAtsushi Nemoto {
1237e534323SBoris Brezillon 	struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
12464fb65baSAtsushi Nemoto 	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
12564fb65baSAtsushi Nemoto 
12664fb65baSAtsushi Nemoto 	while (len--)
12764fb65baSAtsushi Nemoto 		*buf++ = __raw_readl(ndfdtr);
12864fb65baSAtsushi Nemoto }
12964fb65baSAtsushi Nemoto 
1300f808c16SBoris Brezillon static void txx9ndfmc_cmd_ctrl(struct nand_chip *chip, int cmd,
13164fb65baSAtsushi Nemoto 			       unsigned int ctrl)
13264fb65baSAtsushi Nemoto {
133d699ed25SBoris BREZILLON 	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
13464fb65baSAtsushi Nemoto 	struct platform_device *dev = txx9_priv->dev;
135453810b7SJingoo Han 	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
13664fb65baSAtsushi Nemoto 
13764fb65baSAtsushi Nemoto 	if (ctrl & NAND_CTRL_CHANGE) {
13864fb65baSAtsushi Nemoto 		u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
13964fb65baSAtsushi Nemoto 
14064fb65baSAtsushi Nemoto 		mcr &= ~(TXX9_NDFMCR_CLE | TXX9_NDFMCR_ALE | TXX9_NDFMCR_CE);
14164fb65baSAtsushi Nemoto 		mcr |= ctrl & NAND_CLE ? TXX9_NDFMCR_CLE : 0;
14264fb65baSAtsushi Nemoto 		mcr |= ctrl & NAND_ALE ? TXX9_NDFMCR_ALE : 0;
14364fb65baSAtsushi Nemoto 		/* TXX9_NDFMCR_CE bit is 0:high 1:low */
14464fb65baSAtsushi Nemoto 		mcr |= ctrl & NAND_NCE ? TXX9_NDFMCR_CE : 0;
14564fb65baSAtsushi Nemoto 		if (txx9_priv->cs >= 0 && (ctrl & NAND_NCE)) {
14664fb65baSAtsushi Nemoto 			mcr &= ~TXX9_NDFMCR_CS_MASK;
14764fb65baSAtsushi Nemoto 			mcr |= TXX9_NDFMCR_CS(txx9_priv->cs);
14864fb65baSAtsushi Nemoto 		}
14964fb65baSAtsushi Nemoto 		txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
15064fb65baSAtsushi Nemoto 	}
15164fb65baSAtsushi Nemoto 	if (cmd != NAND_CMD_NONE)
15264fb65baSAtsushi Nemoto 		txx9ndfmc_write(dev, cmd & 0xff, TXX9_NDFDTR);
15364fb65baSAtsushi Nemoto 	if (plat->flags & NDFMC_PLAT_FLAG_DUMMYWRITE) {
15464fb65baSAtsushi Nemoto 		/* dummy write to update external latch */
15564fb65baSAtsushi Nemoto 		if ((ctrl & NAND_CTRL_CHANGE) && cmd == NAND_CMD_NONE)
15664fb65baSAtsushi Nemoto 			txx9ndfmc_write(dev, 0, TXX9_NDFDTR);
15764fb65baSAtsushi Nemoto 	}
15864fb65baSAtsushi Nemoto }
15964fb65baSAtsushi Nemoto 
16050a487e7SBoris Brezillon static int txx9ndfmc_dev_ready(struct nand_chip *chip)
16164fb65baSAtsushi Nemoto {
16250a487e7SBoris Brezillon 	struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
16364fb65baSAtsushi Nemoto 
16464fb65baSAtsushi Nemoto 	return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY);
16564fb65baSAtsushi Nemoto }
16664fb65baSAtsushi Nemoto 
167af37d2c3SBoris Brezillon static int txx9ndfmc_calculate_ecc(struct nand_chip *chip, const uint8_t *dat,
16864fb65baSAtsushi Nemoto 				   uint8_t *ecc_code)
16964fb65baSAtsushi Nemoto {
170af37d2c3SBoris Brezillon 	struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
171c0cbfd0eSAtsushi Nemoto 	int eccbytes;
17264fb65baSAtsushi Nemoto 	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
17364fb65baSAtsushi Nemoto 
17464fb65baSAtsushi Nemoto 	mcr &= ~TXX9_NDFMCR_ECC_ALL;
17564fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
17664fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR);
177c0cbfd0eSAtsushi Nemoto 	for (eccbytes = chip->ecc.bytes; eccbytes > 0; eccbytes -= 3) {
17864fb65baSAtsushi Nemoto 		ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR);
17964fb65baSAtsushi Nemoto 		ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR);
18064fb65baSAtsushi Nemoto 		ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR);
181c0cbfd0eSAtsushi Nemoto 		ecc_code += 3;
182c0cbfd0eSAtsushi Nemoto 	}
18364fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
18464fb65baSAtsushi Nemoto 	return 0;
18564fb65baSAtsushi Nemoto }
18664fb65baSAtsushi Nemoto 
18700da2ea9SBoris Brezillon static int txx9ndfmc_correct_data(struct nand_chip *chip, unsigned char *buf,
18800da2ea9SBoris Brezillon 				  unsigned char *read_ecc,
18900da2ea9SBoris Brezillon 				  unsigned char *calc_ecc)
190c0cbfd0eSAtsushi Nemoto {
191c0cbfd0eSAtsushi Nemoto 	int eccsize;
192c0cbfd0eSAtsushi Nemoto 	int corrected = 0;
193c0cbfd0eSAtsushi Nemoto 	int stat;
194c0cbfd0eSAtsushi Nemoto 
195c0cbfd0eSAtsushi Nemoto 	for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
196e7f466c5SMiquel Raynal 		stat = rawnand_sw_hamming_correct(chip, buf, read_ecc,
197e7f466c5SMiquel Raynal 						  calc_ecc);
198c0cbfd0eSAtsushi Nemoto 		if (stat < 0)
199c0cbfd0eSAtsushi Nemoto 			return stat;
200c0cbfd0eSAtsushi Nemoto 		corrected += stat;
201c0cbfd0eSAtsushi Nemoto 		buf += 256;
202c0cbfd0eSAtsushi Nemoto 		read_ecc += 3;
203c0cbfd0eSAtsushi Nemoto 		calc_ecc += 3;
204c0cbfd0eSAtsushi Nemoto 	}
205c0cbfd0eSAtsushi Nemoto 	return corrected;
206c0cbfd0eSAtsushi Nemoto }
207c0cbfd0eSAtsushi Nemoto 
208ec47636cSBoris Brezillon static void txx9ndfmc_enable_hwecc(struct nand_chip *chip, int mode)
20964fb65baSAtsushi Nemoto {
210ec47636cSBoris Brezillon 	struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
21164fb65baSAtsushi Nemoto 	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
21264fb65baSAtsushi Nemoto 
21364fb65baSAtsushi Nemoto 	mcr &= ~TXX9_NDFMCR_ECC_ALL;
21464fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_RESET, TXX9_NDFMCR);
21564fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
21664fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_ON, TXX9_NDFMCR);
21764fb65baSAtsushi Nemoto }
21864fb65baSAtsushi Nemoto 
21964fb65baSAtsushi Nemoto static void txx9ndfmc_initialize(struct platform_device *dev)
22064fb65baSAtsushi Nemoto {
221453810b7SJingoo Han 	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
22264fb65baSAtsushi Nemoto 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
22364fb65baSAtsushi Nemoto 	int tmout = 100;
22464fb65baSAtsushi Nemoto 
22564fb65baSAtsushi Nemoto 	if (plat->flags & NDFMC_PLAT_FLAG_NO_RSTR)
22664fb65baSAtsushi Nemoto 		; /* no NDFRSTR.  Write to NDFSPR resets the NDFMC. */
22764fb65baSAtsushi Nemoto 	else {
22864fb65baSAtsushi Nemoto 		/* reset NDFMC */
22964fb65baSAtsushi Nemoto 		txx9ndfmc_write(dev,
23064fb65baSAtsushi Nemoto 				txx9ndfmc_read(dev, TXX9_NDFRSTR) |
23164fb65baSAtsushi Nemoto 				TXX9_NDFRSTR_RST,
23264fb65baSAtsushi Nemoto 				TXX9_NDFRSTR);
23364fb65baSAtsushi Nemoto 		while (txx9ndfmc_read(dev, TXX9_NDFRSTR) & TXX9_NDFRSTR_RST) {
23464fb65baSAtsushi Nemoto 			if (--tmout == 0) {
23564fb65baSAtsushi Nemoto 				dev_err(&dev->dev, "reset failed.\n");
23664fb65baSAtsushi Nemoto 				break;
23764fb65baSAtsushi Nemoto 			}
23864fb65baSAtsushi Nemoto 			udelay(1);
23964fb65baSAtsushi Nemoto 		}
24064fb65baSAtsushi Nemoto 	}
24164fb65baSAtsushi Nemoto 	/* setup Hold Time, Strobe Pulse Width */
24264fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev, (drvdata->hold << 4) | drvdata->spw, TXX9_NDFSPR);
24364fb65baSAtsushi Nemoto 	txx9ndfmc_write(dev,
24464fb65baSAtsushi Nemoto 			(plat->flags & NDFMC_PLAT_FLAG_USE_BSPRT) ?
24564fb65baSAtsushi Nemoto 			TXX9_NDFMCR_BSPRT : 0, TXX9_NDFMCR);
24664fb65baSAtsushi Nemoto }
24764fb65baSAtsushi Nemoto 
24864fb65baSAtsushi Nemoto #define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
24964fb65baSAtsushi Nemoto 	DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
25064fb65baSAtsushi Nemoto 
251ee1af829SMiquel Raynal static int txx9ndfmc_attach_chip(struct nand_chip *chip)
252c0cbfd0eSAtsushi Nemoto {
253ee1af829SMiquel Raynal 	struct mtd_info *mtd = nand_to_mtd(chip);
254c0cbfd0eSAtsushi Nemoto 
2553c3bbf01SMiquel Raynal 	if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
2563c3bbf01SMiquel Raynal 		return 0;
2573c3bbf01SMiquel Raynal 
2583c3bbf01SMiquel Raynal 	chip->ecc.strength = 1;
2593c3bbf01SMiquel Raynal 
260c0cbfd0eSAtsushi Nemoto 	if (mtd->writesize >= 512) {
26124ac9a94SRalf Rösch 		chip->ecc.size = 512;
26224ac9a94SRalf Rösch 		chip->ecc.bytes = 6;
263abe23d1cSMiquel Raynal 	} else {
264abe23d1cSMiquel Raynal 		chip->ecc.size = 256;
265abe23d1cSMiquel Raynal 		chip->ecc.bytes = 3;
266c0cbfd0eSAtsushi Nemoto 	}
267abe23d1cSMiquel Raynal 
2683c3bbf01SMiquel Raynal 	chip->ecc.calculate = txx9ndfmc_calculate_ecc;
2693c3bbf01SMiquel Raynal 	chip->ecc.correct = txx9ndfmc_correct_data;
2703c3bbf01SMiquel Raynal 	chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
2713c3bbf01SMiquel Raynal 
272ee1af829SMiquel Raynal 	return 0;
273c0cbfd0eSAtsushi Nemoto }
274ee1af829SMiquel Raynal 
275ee1af829SMiquel Raynal static const struct nand_controller_ops txx9ndfmc_controller_ops = {
276ee1af829SMiquel Raynal 	.attach_chip = txx9ndfmc_attach_chip,
277ee1af829SMiquel Raynal };
278c0cbfd0eSAtsushi Nemoto 
27964fb65baSAtsushi Nemoto static int __init txx9ndfmc_probe(struct platform_device *dev)
28064fb65baSAtsushi Nemoto {
281453810b7SJingoo Han 	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
28264fb65baSAtsushi Nemoto 	int hold, spw;
28364fb65baSAtsushi Nemoto 	int i;
28464fb65baSAtsushi Nemoto 	struct txx9ndfmc_drvdata *drvdata;
28564fb65baSAtsushi Nemoto 	unsigned long gbusclk = plat->gbus_clock;
28664fb65baSAtsushi Nemoto 
28764fb65baSAtsushi Nemoto 	drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
28864fb65baSAtsushi Nemoto 	if (!drvdata)
28964fb65baSAtsushi Nemoto 		return -ENOMEM;
290524bd02aSCai Huoqing 	drvdata->base = devm_platform_ioremap_resource(dev, 0);
291b0de774cSThierry Reding 	if (IS_ERR(drvdata->base))
292b0de774cSThierry Reding 		return PTR_ERR(drvdata->base);
29364fb65baSAtsushi Nemoto 
29464fb65baSAtsushi Nemoto 	hold = plat->hold ?: 20; /* tDH */
29564fb65baSAtsushi Nemoto 	spw = plat->spw ?: 90; /* max(tREADID, tWP, tRP) */
29664fb65baSAtsushi Nemoto 
29764fb65baSAtsushi Nemoto 	hold = TXX9NDFMC_NS_TO_CYC(gbusclk, hold);
29864fb65baSAtsushi Nemoto 	spw = TXX9NDFMC_NS_TO_CYC(gbusclk, spw);
29964fb65baSAtsushi Nemoto 	if (plat->flags & NDFMC_PLAT_FLAG_HOLDADD)
30064fb65baSAtsushi Nemoto 		hold -= 2;	/* actual hold time : (HOLD + 2) BUSCLK */
30164fb65baSAtsushi Nemoto 	spw -= 1;	/* actual wait time : (SPW + 1) BUSCLK */
30264fb65baSAtsushi Nemoto 	hold = clamp(hold, 1, 15);
30364fb65baSAtsushi Nemoto 	drvdata->hold = hold;
30464fb65baSAtsushi Nemoto 	spw = clamp(spw, 1, 15);
30564fb65baSAtsushi Nemoto 	drvdata->spw = spw;
30664fb65baSAtsushi Nemoto 	dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
30764fb65baSAtsushi Nemoto 		 (gbusclk + 500000) / 1000000, hold, spw);
30864fb65baSAtsushi Nemoto 
309a001058aSMiquel Raynal 	nand_controller_init(&drvdata->controller);
310ee1af829SMiquel Raynal 	drvdata->controller.ops = &txx9ndfmc_controller_ops;
31164fb65baSAtsushi Nemoto 
31264fb65baSAtsushi Nemoto 	platform_set_drvdata(dev, drvdata);
31364fb65baSAtsushi Nemoto 	txx9ndfmc_initialize(dev);
31464fb65baSAtsushi Nemoto 
31564fb65baSAtsushi Nemoto 	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
31664fb65baSAtsushi Nemoto 		struct txx9ndfmc_priv *txx9_priv;
31764fb65baSAtsushi Nemoto 		struct nand_chip *chip;
31864fb65baSAtsushi Nemoto 		struct mtd_info *mtd;
31964fb65baSAtsushi Nemoto 
32064fb65baSAtsushi Nemoto 		if (!(plat->ch_mask & (1 << i)))
32164fb65baSAtsushi Nemoto 			continue;
32264fb65baSAtsushi Nemoto 		txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv),
32364fb65baSAtsushi Nemoto 				    GFP_KERNEL);
324844a72c5SJingoo Han 		if (!txx9_priv)
32564fb65baSAtsushi Nemoto 			continue;
32664fb65baSAtsushi Nemoto 		chip = &txx9_priv->chip;
327a3f54377SBoris BREZILLON 		mtd = nand_to_mtd(chip);
328693ad872SFrans Klaver 		mtd->dev.parent = &dev->dev;
32964fb65baSAtsushi Nemoto 
330716bbbabSBoris Brezillon 		chip->legacy.read_byte = txx9ndfmc_read_byte;
331716bbbabSBoris Brezillon 		chip->legacy.read_buf = txx9ndfmc_read_buf;
332716bbbabSBoris Brezillon 		chip->legacy.write_buf = txx9ndfmc_write_buf;
333bf6065c6SBoris Brezillon 		chip->legacy.cmd_ctrl = txx9ndfmc_cmd_ctrl;
3348395b753SBoris Brezillon 		chip->legacy.dev_ready = txx9ndfmc_dev_ready;
3353cece3abSBoris Brezillon 		chip->legacy.chip_delay = 100;
336a001058aSMiquel Raynal 		chip->controller = &drvdata->controller;
33764fb65baSAtsushi Nemoto 
338d699ed25SBoris BREZILLON 		nand_set_controller_data(chip, txx9_priv);
33964fb65baSAtsushi Nemoto 		txx9_priv->dev = dev;
34064fb65baSAtsushi Nemoto 
34164fb65baSAtsushi Nemoto 		if (plat->ch_mask != 1) {
34264fb65baSAtsushi Nemoto 			txx9_priv->cs = i;
34381933046SDavid Woodhouse 			txx9_priv->mtdname = kasprintf(GFP_KERNEL, "%s.%u",
34464fb65baSAtsushi Nemoto 						       dev_name(&dev->dev), i);
34564fb65baSAtsushi Nemoto 		} else {
34664fb65baSAtsushi Nemoto 			txx9_priv->cs = -1;
347272023dfSAtsushi Nemoto 			txx9_priv->mtdname = kstrdup(dev_name(&dev->dev),
348272023dfSAtsushi Nemoto 						     GFP_KERNEL);
349272023dfSAtsushi Nemoto 		}
350272023dfSAtsushi Nemoto 		if (!txx9_priv->mtdname) {
351272023dfSAtsushi Nemoto 			kfree(txx9_priv);
352272023dfSAtsushi Nemoto 			dev_err(&dev->dev, "Unable to allocate MTD name.\n");
353272023dfSAtsushi Nemoto 			continue;
35464fb65baSAtsushi Nemoto 		}
35564fb65baSAtsushi Nemoto 		if (plat->wide_mask & (1 << i))
35664fb65baSAtsushi Nemoto 			chip->options |= NAND_BUSWIDTH_16;
35764fb65baSAtsushi Nemoto 
35800ad378fSBoris Brezillon 		if (nand_scan(chip, 1)) {
359272023dfSAtsushi Nemoto 			kfree(txx9_priv->mtdname);
36064fb65baSAtsushi Nemoto 			kfree(txx9_priv);
36164fb65baSAtsushi Nemoto 			continue;
36264fb65baSAtsushi Nemoto 		}
36364fb65baSAtsushi Nemoto 		mtd->name = txx9_priv->mtdname;
36464fb65baSAtsushi Nemoto 
36529597ca1SRafał Miłecki 		mtd_device_register(mtd, NULL, 0);
36664fb65baSAtsushi Nemoto 		drvdata->mtds[i] = mtd;
36764fb65baSAtsushi Nemoto 	}
36864fb65baSAtsushi Nemoto 
36964fb65baSAtsushi Nemoto 	return 0;
37064fb65baSAtsushi Nemoto }
37164fb65baSAtsushi Nemoto 
37264fb65baSAtsushi Nemoto static int __exit txx9ndfmc_remove(struct platform_device *dev)
37364fb65baSAtsushi Nemoto {
37464fb65baSAtsushi Nemoto 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
375f6fc7597SMiquel Raynal 	int ret, i;
37664fb65baSAtsushi Nemoto 
37764fb65baSAtsushi Nemoto 	if (!drvdata)
37864fb65baSAtsushi Nemoto 		return 0;
37964fb65baSAtsushi Nemoto 	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
38064fb65baSAtsushi Nemoto 		struct mtd_info *mtd = drvdata->mtds[i];
38164fb65baSAtsushi Nemoto 		struct nand_chip *chip;
38264fb65baSAtsushi Nemoto 		struct txx9ndfmc_priv *txx9_priv;
38364fb65baSAtsushi Nemoto 
38464fb65baSAtsushi Nemoto 		if (!mtd)
38564fb65baSAtsushi Nemoto 			continue;
3864bd4ebccSBoris BREZILLON 		chip = mtd_to_nand(mtd);
387d699ed25SBoris BREZILLON 		txx9_priv = nand_get_controller_data(chip);
38864fb65baSAtsushi Nemoto 
389f6fc7597SMiquel Raynal 		ret = mtd_device_unregister(nand_to_mtd(chip));
390f6fc7597SMiquel Raynal 		WARN_ON(ret);
391f6fc7597SMiquel Raynal 		nand_cleanup(chip);
39281933046SDavid Woodhouse 		kfree(txx9_priv->mtdname);
39364fb65baSAtsushi Nemoto 		kfree(txx9_priv);
39464fb65baSAtsushi Nemoto 	}
39564fb65baSAtsushi Nemoto 	return 0;
39664fb65baSAtsushi Nemoto }
39764fb65baSAtsushi Nemoto 
39864fb65baSAtsushi Nemoto #ifdef CONFIG_PM
39964fb65baSAtsushi Nemoto static int txx9ndfmc_resume(struct platform_device *dev)
40064fb65baSAtsushi Nemoto {
40164fb65baSAtsushi Nemoto 	if (platform_get_drvdata(dev))
40264fb65baSAtsushi Nemoto 		txx9ndfmc_initialize(dev);
40364fb65baSAtsushi Nemoto 	return 0;
40464fb65baSAtsushi Nemoto }
40564fb65baSAtsushi Nemoto #else
40664fb65baSAtsushi Nemoto #define txx9ndfmc_resume NULL
40764fb65baSAtsushi Nemoto #endif
40864fb65baSAtsushi Nemoto 
40964fb65baSAtsushi Nemoto static struct platform_driver txx9ndfmc_driver = {
41064fb65baSAtsushi Nemoto 	.remove		= __exit_p(txx9ndfmc_remove),
41164fb65baSAtsushi Nemoto 	.resume		= txx9ndfmc_resume,
41264fb65baSAtsushi Nemoto 	.driver		= {
41364fb65baSAtsushi Nemoto 		.name	= "txx9ndfmc",
41464fb65baSAtsushi Nemoto 	},
41564fb65baSAtsushi Nemoto };
41664fb65baSAtsushi Nemoto 
4173a2a13faSJingoo Han module_platform_driver_probe(txx9ndfmc_driver, txx9ndfmc_probe);
41864fb65baSAtsushi Nemoto 
41964fb65baSAtsushi Nemoto MODULE_LICENSE("GPL");
42064fb65baSAtsushi Nemoto MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver");
42164fb65baSAtsushi Nemoto MODULE_ALIAS("platform:txx9ndfmc");
422