aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/mxc_nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/mxc_nand.c')
-rw-r--r--drivers/mtd/nand/mxc_nand.c92
1 files changed, 83 insertions, 9 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index b2828e84d243..214b03afdd48 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -30,6 +30,8 @@
30#include <linux/clk.h> 30#include <linux/clk.h>
31#include <linux/err.h> 31#include <linux/err.h>
32#include <linux/io.h> 32#include <linux/io.h>
33#include <linux/irq.h>
34#include <linux/completion.h>
33 35
34#include <asm/mach/flash.h> 36#include <asm/mach/flash.h>
35#include <mach/mxc_nand.h> 37#include <mach/mxc_nand.h>
@@ -151,7 +153,7 @@ struct mxc_nand_host {
151 int irq; 153 int irq;
152 int eccsize; 154 int eccsize;
153 155
154 wait_queue_head_t irq_waitq; 156 struct completion op_completion;
155 157
156 uint8_t *data_buf; 158 uint8_t *data_buf;
157 unsigned int buf_start; 159 unsigned int buf_start;
@@ -164,6 +166,7 @@ struct mxc_nand_host {
164 void (*send_read_id)(struct mxc_nand_host *); 166 void (*send_read_id)(struct mxc_nand_host *);
165 uint16_t (*get_dev_status)(struct mxc_nand_host *); 167 uint16_t (*get_dev_status)(struct mxc_nand_host *);
166 int (*check_int)(struct mxc_nand_host *); 168 int (*check_int)(struct mxc_nand_host *);
169 void (*irq_control)(struct mxc_nand_host *, int);
167}; 170};
168 171
169/* OOB placement block for use with hardware ecc generation */ 172/* OOB placement block for use with hardware ecc generation */
@@ -216,9 +219,12 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
216{ 219{
217 struct mxc_nand_host *host = dev_id; 220 struct mxc_nand_host *host = dev_id;
218 221
219 disable_irq_nosync(irq); 222 if (!host->check_int(host))
223 return IRQ_NONE;
220 224
221 wake_up(&host->irq_waitq); 225 host->irq_control(host, 0);
226
227 complete(&host->op_completion);
222 228
223 return IRQ_HANDLED; 229 return IRQ_HANDLED;
224} 230}
@@ -245,11 +251,54 @@ static int check_int_v1_v2(struct mxc_nand_host *host)
245 if (!(tmp & NFC_V1_V2_CONFIG2_INT)) 251 if (!(tmp & NFC_V1_V2_CONFIG2_INT))
246 return 0; 252 return 0;
247 253
248 writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); 254 if (!cpu_is_mx21())
255 writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
249 256
250 return 1; 257 return 1;
251} 258}
252 259
260/*
261 * It has been observed that the i.MX21 cannot read the CONFIG2:INT bit
262 * if interrupts are masked (CONFIG1:INT_MSK is set). To handle this, the
263 * driver can enable/disable the irq line rather than simply masking the
264 * interrupts.
265 */
266static void irq_control_mx21(struct mxc_nand_host *host, int activate)
267{
268 if (activate)
269 enable_irq(host->irq);
270 else
271 disable_irq_nosync(host->irq);
272}
273
274static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
275{
276 uint16_t tmp;
277
278 tmp = readw(NFC_V1_V2_CONFIG1);
279
280 if (activate)
281 tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
282 else
283 tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
284
285 writew(tmp, NFC_V1_V2_CONFIG1);
286}
287
288static void irq_control_v3(struct mxc_nand_host *host, int activate)
289{
290 uint32_t tmp;
291
292 tmp = readl(NFC_V3_CONFIG2);
293
294 if (activate)
295 tmp &= ~NFC_V3_CONFIG2_INT_MSK;
296 else
297 tmp |= NFC_V3_CONFIG2_INT_MSK;
298
299 writel(tmp, NFC_V3_CONFIG2);
300}
301
253/* This function polls the NANDFC to wait for the basic operation to 302/* This function polls the NANDFC to wait for the basic operation to
254 * complete by checking the INT bit of config2 register. 303 * complete by checking the INT bit of config2 register.
255 */ 304 */
@@ -259,10 +308,9 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq)
259 308
260 if (useirq) { 309 if (useirq) {
261 if (!host->check_int(host)) { 310 if (!host->check_int(host)) {
262 311 INIT_COMPLETION(host->op_completion);
263 enable_irq(host->irq); 312 host->irq_control(host, 1);
264 313 wait_for_completion(&host->op_completion);
265 wait_event(host->irq_waitq, host->check_int(host));
266 } 314 }
267 } else { 315 } else {
268 while (max_retries-- > 0) { 316 while (max_retries-- > 0) {
@@ -799,6 +847,7 @@ static void preset_v3(struct mtd_info *mtd)
799 NFC_V3_CONFIG2_2CMD_PHASES | 847 NFC_V3_CONFIG2_2CMD_PHASES |
800 NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) | 848 NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
801 NFC_V3_CONFIG2_ST_CMD(0x70) | 849 NFC_V3_CONFIG2_ST_CMD(0x70) |
850 NFC_V3_CONFIG2_INT_MSK |
802 NFC_V3_CONFIG2_NUM_ADDR_PHASE0; 851 NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
803 852
804 if (chip->ecc.mode == NAND_ECC_HW) 853 if (chip->ecc.mode == NAND_ECC_HW)
@@ -1024,6 +1073,10 @@ static int __init mxcnd_probe(struct platform_device *pdev)
1024 host->send_read_id = send_read_id_v1_v2; 1073 host->send_read_id = send_read_id_v1_v2;
1025 host->get_dev_status = get_dev_status_v1_v2; 1074 host->get_dev_status = get_dev_status_v1_v2;
1026 host->check_int = check_int_v1_v2; 1075 host->check_int = check_int_v1_v2;
1076 if (cpu_is_mx21())
1077 host->irq_control = irq_control_mx21;
1078 else
1079 host->irq_control = irq_control_v1_v2;
1027 } 1080 }
1028 1081
1029 if (nfc_is_v21()) { 1082 if (nfc_is_v21()) {
@@ -1062,6 +1115,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
1062 host->send_read_id = send_read_id_v3; 1115 host->send_read_id = send_read_id_v3;
1063 host->check_int = check_int_v3; 1116 host->check_int = check_int_v3;
1064 host->get_dev_status = get_dev_status_v3; 1117 host->get_dev_status = get_dev_status_v3;
1118 host->irq_control = irq_control_v3;
1065 oob_smallpage = &nandv2_hw_eccoob_smallpage; 1119 oob_smallpage = &nandv2_hw_eccoob_smallpage;
1066 oob_largepage = &nandv2_hw_eccoob_largepage; 1120 oob_largepage = &nandv2_hw_eccoob_largepage;
1067 } else 1121 } else
@@ -1093,14 +1147,34 @@ static int __init mxcnd_probe(struct platform_device *pdev)
1093 this->options |= NAND_USE_FLASH_BBT; 1147 this->options |= NAND_USE_FLASH_BBT;
1094 } 1148 }
1095 1149
1096 init_waitqueue_head(&host->irq_waitq); 1150 init_completion(&host->op_completion);
1097 1151
1098 host->irq = platform_get_irq(pdev, 0); 1152 host->irq = platform_get_irq(pdev, 0);
1099 1153
1154 /*
1155 * mask the interrupt. For i.MX21 explicitely call
1156 * irq_control_v1_v2 to use the mask bit. We can't call
1157 * disable_irq_nosync() for an interrupt we do not own yet.
1158 */
1159 if (cpu_is_mx21())
1160 irq_control_v1_v2(host, 0);
1161 else
1162 host->irq_control(host, 0);
1163
1100 err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); 1164 err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
1101 if (err) 1165 if (err)
1102 goto eirq; 1166 goto eirq;
1103 1167
1168 host->irq_control(host, 0);
1169
1170 /*
1171 * Now that the interrupt is disabled make sure the interrupt
1172 * mask bit is cleared on i.MX21. Otherwise we can't read
1173 * the interrupt status bit on this machine.
1174 */
1175 if (cpu_is_mx21())
1176 irq_control_v1_v2(host, 1);
1177
1104 /* first scan to find the device and get the page size */ 1178 /* first scan to find the device and get the page size */
1105 if (nand_scan_ident(mtd, 1, NULL)) { 1179 if (nand_scan_ident(mtd, 1, NULL)) {
1106 err = -ENXIO; 1180 err = -ENXIO;