diff options
author | Ivo Clarysse <ivo.clarysse@gmail.com> | 2010-04-08 10:16:51 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-05-13 20:02:53 -0400 |
commit | a47bfd2eb66837653dc3b42541dfe4283dd41251 (patch) | |
tree | ce4199d6c78acb4d9332af55f6415d74e1d3d862 /drivers/mtd | |
parent | d484018056816178abffacb84b8c16628e880c83 (diff) |
mtd: mxc_nand: support i.MX21
On i.MX21 SoCs, if the NFC_CONFIG1:NFC_INT_MASK bit is set,
NFC_CONFIG2:NFC_INT always reads out zero, even if an
operation is completed. This patch uses enable_irq and
disable_irq_nosync instead of NFC_CONFIG1:NFC_INT_MASK to
mask NFC interrupts. This allows NFC_CONFIG2:NFC_INT to also
be used to detect operation completion on i.MX21.
The i.MX21 NFC does not signal reset completion using
NFC_CONFIG1:NFC_INT_MASK, so instead reset completion is
tested by checking if NFC_CONFIG2 becomes 0.
Signed-off-by: Ivo Clarysse <ivo.clarysse@gmail.com>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index b527aa2d687d..35da3dc4bd17 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #define DRIVER_NAME "mxc_nand" | 38 | #define DRIVER_NAME "mxc_nand" |
39 | 39 | ||
40 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) | 40 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) |
41 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27()) | 41 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) |
42 | 42 | ||
43 | /* Addresses for NFC registers */ | 43 | /* Addresses for NFC registers */ |
44 | #define NFC_BUF_SIZE 0xE00 | 44 | #define NFC_BUF_SIZE 0xE00 |
@@ -168,11 +168,7 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | |||
168 | { | 168 | { |
169 | struct mxc_nand_host *host = dev_id; | 169 | struct mxc_nand_host *host = dev_id; |
170 | 170 | ||
171 | uint16_t tmp; | 171 | disable_irq_nosync(irq); |
172 | |||
173 | tmp = readw(host->regs + NFC_CONFIG1); | ||
174 | tmp |= NFC_INT_MSK; /* Disable interrupt */ | ||
175 | writew(tmp, host->regs + NFC_CONFIG1); | ||
176 | 172 | ||
177 | wake_up(&host->irq_waitq); | 173 | wake_up(&host->irq_waitq); |
178 | 174 | ||
@@ -184,15 +180,13 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | |||
184 | */ | 180 | */ |
185 | static void wait_op_done(struct mxc_nand_host *host, int useirq) | 181 | static void wait_op_done(struct mxc_nand_host *host, int useirq) |
186 | { | 182 | { |
187 | uint32_t tmp; | 183 | uint16_t tmp; |
188 | int max_retries = 2000; | 184 | int max_retries = 8000; |
189 | 185 | ||
190 | if (useirq) { | 186 | if (useirq) { |
191 | if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { | 187 | if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { |
192 | 188 | ||
193 | tmp = readw(host->regs + NFC_CONFIG1); | 189 | enable_irq(host->irq); |
194 | tmp &= ~NFC_INT_MSK; /* Enable interrupt */ | ||
195 | writew(tmp, host->regs + NFC_CONFIG1); | ||
196 | 190 | ||
197 | wait_event(host->irq_waitq, | 191 | wait_event(host->irq_waitq, |
198 | readw(host->regs + NFC_CONFIG2) & NFC_INT); | 192 | readw(host->regs + NFC_CONFIG2) & NFC_INT); |
@@ -226,8 +220,23 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq) | |||
226 | writew(cmd, host->regs + NFC_FLASH_CMD); | 220 | writew(cmd, host->regs + NFC_FLASH_CMD); |
227 | writew(NFC_CMD, host->regs + NFC_CONFIG2); | 221 | writew(NFC_CMD, host->regs + NFC_CONFIG2); |
228 | 222 | ||
229 | /* Wait for operation to complete */ | 223 | if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) { |
230 | wait_op_done(host, useirq); | 224 | int max_retries = 100; |
225 | /* Reset completion is indicated by NFC_CONFIG2 */ | ||
226 | /* being set to 0 */ | ||
227 | while (max_retries-- > 0) { | ||
228 | if (readw(host->regs + NFC_CONFIG2) == 0) { | ||
229 | break; | ||
230 | } | ||
231 | udelay(1); | ||
232 | } | ||
233 | if (max_retries < 0) | ||
234 | DEBUG(MTD_DEBUG_LEVEL0, "%s: RESET failed\n", | ||
235 | __func__); | ||
236 | } else { | ||
237 | /* Wait for operation to complete */ | ||
238 | wait_op_done(host, useirq); | ||
239 | } | ||
231 | } | 240 | } |
232 | 241 | ||
233 | /* This function sends an address (or partial address) to the | 242 | /* This function sends an address (or partial address) to the |
@@ -548,9 +557,9 @@ static void preset(struct mtd_info *mtd) | |||
548 | struct mxc_nand_host *host = nand_chip->priv; | 557 | struct mxc_nand_host *host = nand_chip->priv; |
549 | uint16_t tmp; | 558 | uint16_t tmp; |
550 | 559 | ||
551 | /* disable interrupt, disable spare enable */ | 560 | /* enable interrupt, disable spare enable */ |
552 | tmp = readw(host->regs + NFC_CONFIG1); | 561 | tmp = readw(host->regs + NFC_CONFIG1); |
553 | tmp |= NFC_INT_MSK; | 562 | tmp &= ~NFC_INT_MSK; |
554 | tmp &= ~NFC_SP_EN; | 563 | tmp &= ~NFC_SP_EN; |
555 | if (nand_chip->ecc.mode == NAND_ECC_HW) { | 564 | if (nand_chip->ecc.mode == NAND_ECC_HW) { |
556 | tmp |= NFC_ECC_EN; | 565 | tmp |= NFC_ECC_EN; |
@@ -820,7 +829,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
820 | 829 | ||
821 | host->irq = platform_get_irq(pdev, 0); | 830 | host->irq = platform_get_irq(pdev, 0); |
822 | 831 | ||
823 | err = request_irq(host->irq, mxc_nfc_irq, 0, DRIVER_NAME, host); | 832 | err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); |
824 | if (err) | 833 | if (err) |
825 | goto eirq; | 834 | goto eirq; |
826 | 835 | ||