diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2012-04-23 05:23:34 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-05-14 00:01:17 -0400 |
commit | 8556958af4ef58147c11f772e6171c149efee53c (patch) | |
tree | 5cf13b30e4c217206906a8f39911d01ffe252925 /drivers/mtd | |
parent | 8d1fd16df9e14b29965ed64e120015e481d1fe0a (diff) |
mtd: mxc_nand: use a flag to detect if the mx21 quirk is necessary
This gets rid of several instances of cpu_is_mx21() in the driver.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 98 |
1 files changed, 49 insertions, 49 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 7d82cc44cb26..6f6068043fad 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -173,6 +173,13 @@ struct mxc_nand_host { | |||
173 | uint16_t (*get_dev_status)(struct mxc_nand_host *); | 173 | uint16_t (*get_dev_status)(struct mxc_nand_host *); |
174 | int (*check_int)(struct mxc_nand_host *); | 174 | int (*check_int)(struct mxc_nand_host *); |
175 | void (*irq_control)(struct mxc_nand_host *, int); | 175 | void (*irq_control)(struct mxc_nand_host *, int); |
176 | |||
177 | /* | ||
178 | * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked | ||
179 | * (CONFIG1:INT_MSK is set). To handle this the driver uses | ||
180 | * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK | ||
181 | */ | ||
182 | int irqpending_quirk; | ||
176 | }; | 183 | }; |
177 | 184 | ||
178 | /* OOB placement block for use with hardware ecc generation */ | 185 | /* OOB placement block for use with hardware ecc generation */ |
@@ -244,20 +251,6 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = { | |||
244 | 251 | ||
245 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; | 252 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; |
246 | 253 | ||
247 | static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | ||
248 | { | ||
249 | struct mxc_nand_host *host = dev_id; | ||
250 | |||
251 | if (!host->check_int(host)) | ||
252 | return IRQ_NONE; | ||
253 | |||
254 | host->irq_control(host, 0); | ||
255 | |||
256 | complete(&host->op_completion); | ||
257 | |||
258 | return IRQ_HANDLED; | ||
259 | } | ||
260 | |||
261 | static int check_int_v3(struct mxc_nand_host *host) | 254 | static int check_int_v3(struct mxc_nand_host *host) |
262 | { | 255 | { |
263 | uint32_t tmp; | 256 | uint32_t tmp; |
@@ -280,26 +273,12 @@ static int check_int_v1_v2(struct mxc_nand_host *host) | |||
280 | if (!(tmp & NFC_V1_V2_CONFIG2_INT)) | 273 | if (!(tmp & NFC_V1_V2_CONFIG2_INT)) |
281 | return 0; | 274 | return 0; |
282 | 275 | ||
283 | if (!cpu_is_mx21()) | 276 | if (!host->irqpending_quirk) |
284 | writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); | 277 | writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); |
285 | 278 | ||
286 | return 1; | 279 | return 1; |
287 | } | 280 | } |
288 | 281 | ||
289 | /* | ||
290 | * It has been observed that the i.MX21 cannot read the CONFIG2:INT bit | ||
291 | * if interrupts are masked (CONFIG1:INT_MSK is set). To handle this, the | ||
292 | * driver can enable/disable the irq line rather than simply masking the | ||
293 | * interrupts. | ||
294 | */ | ||
295 | static void irq_control_mx21(struct mxc_nand_host *host, int activate) | ||
296 | { | ||
297 | if (activate) | ||
298 | enable_irq(host->irq); | ||
299 | else | ||
300 | disable_irq_nosync(host->irq); | ||
301 | } | ||
302 | |||
303 | static void irq_control_v1_v2(struct mxc_nand_host *host, int activate) | 282 | static void irq_control_v1_v2(struct mxc_nand_host *host, int activate) |
304 | { | 283 | { |
305 | uint16_t tmp; | 284 | uint16_t tmp; |
@@ -328,6 +307,32 @@ static void irq_control_v3(struct mxc_nand_host *host, int activate) | |||
328 | writel(tmp, NFC_V3_CONFIG2); | 307 | writel(tmp, NFC_V3_CONFIG2); |
329 | } | 308 | } |
330 | 309 | ||
310 | static void irq_control(struct mxc_nand_host *host, int activate) | ||
311 | { | ||
312 | if (host->irqpending_quirk) { | ||
313 | if (activate) | ||
314 | enable_irq(host->irq); | ||
315 | else | ||
316 | disable_irq_nosync(host->irq); | ||
317 | } else { | ||
318 | host->irq_control(host, activate); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | ||
323 | { | ||
324 | struct mxc_nand_host *host = dev_id; | ||
325 | |||
326 | if (!host->check_int(host)) | ||
327 | return IRQ_NONE; | ||
328 | |||
329 | irq_control(host, 0); | ||
330 | |||
331 | complete(&host->op_completion); | ||
332 | |||
333 | return IRQ_HANDLED; | ||
334 | } | ||
335 | |||
331 | /* This function polls the NANDFC to wait for the basic operation to | 336 | /* This function polls the NANDFC to wait for the basic operation to |
332 | * complete by checking the INT bit of config2 register. | 337 | * complete by checking the INT bit of config2 register. |
333 | */ | 338 | */ |
@@ -338,7 +343,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) | |||
338 | if (useirq) { | 343 | if (useirq) { |
339 | if (!host->check_int(host)) { | 344 | if (!host->check_int(host)) { |
340 | INIT_COMPLETION(host->op_completion); | 345 | INIT_COMPLETION(host->op_completion); |
341 | host->irq_control(host, 1); | 346 | irq_control(host, 1); |
342 | wait_for_completion(&host->op_completion); | 347 | wait_for_completion(&host->op_completion); |
343 | } | 348 | } |
344 | } else { | 349 | } else { |
@@ -374,7 +379,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) | |||
374 | writew(cmd, NFC_V1_V2_FLASH_CMD); | 379 | writew(cmd, NFC_V1_V2_FLASH_CMD); |
375 | writew(NFC_CMD, NFC_V1_V2_CONFIG2); | 380 | writew(NFC_CMD, NFC_V1_V2_CONFIG2); |
376 | 381 | ||
377 | if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) { | 382 | if (host->irqpending_quirk && (cmd == NAND_CMD_RESET)) { |
378 | int max_retries = 100; | 383 | int max_retries = 100; |
379 | /* Reset completion is indicated by NFC_CONFIG2 */ | 384 | /* Reset completion is indicated by NFC_CONFIG2 */ |
380 | /* being set to 0 */ | 385 | /* being set to 0 */ |
@@ -812,7 +817,7 @@ static void preset_v1_v2(struct mtd_info *mtd) | |||
812 | if (nfc_is_v21()) | 817 | if (nfc_is_v21()) |
813 | config1 |= NFC_V2_CONFIG1_FP_INT; | 818 | config1 |= NFC_V2_CONFIG1_FP_INT; |
814 | 819 | ||
815 | if (!cpu_is_mx21()) | 820 | if (!host->irqpending_quirk) |
816 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; | 821 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; |
817 | 822 | ||
818 | if (nfc_is_v21() && mtd->writesize) { | 823 | if (nfc_is_v21() && mtd->writesize) { |
@@ -1103,10 +1108,9 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1103 | host->send_read_id = send_read_id_v1_v2; | 1108 | host->send_read_id = send_read_id_v1_v2; |
1104 | host->get_dev_status = get_dev_status_v1_v2; | 1109 | host->get_dev_status = get_dev_status_v1_v2; |
1105 | host->check_int = check_int_v1_v2; | 1110 | host->check_int = check_int_v1_v2; |
1111 | host->irq_control = irq_control_v1_v2; | ||
1106 | if (cpu_is_mx21()) | 1112 | if (cpu_is_mx21()) |
1107 | host->irq_control = irq_control_mx21; | 1113 | host->irqpending_quirk = 1; |
1108 | else | ||
1109 | host->irq_control = irq_control_v1_v2; | ||
1110 | } | 1114 | } |
1111 | 1115 | ||
1112 | if (nfc_is_v21()) { | 1116 | if (nfc_is_v21()) { |
@@ -1182,28 +1186,24 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1182 | host->irq = platform_get_irq(pdev, 0); | 1186 | host->irq = platform_get_irq(pdev, 0); |
1183 | 1187 | ||
1184 | /* | 1188 | /* |
1185 | * mask the interrupt. For i.MX21 explicitely call | 1189 | * Use host->irq_control here instead of irq_control because we must not |
1186 | * irq_control_v1_v2 to use the mask bit. We can't call | 1190 | * disable_irq_nosync without having requested the irq |
1187 | * disable_irq_nosync() for an interrupt we do not own yet. | ||
1188 | */ | 1191 | */ |
1189 | if (cpu_is_mx21()) | 1192 | host->irq_control(host, 0); |
1190 | irq_control_v1_v2(host, 0); | ||
1191 | else | ||
1192 | host->irq_control(host, 0); | ||
1193 | 1193 | ||
1194 | err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); | 1194 | err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); |
1195 | if (err) | 1195 | if (err) |
1196 | goto eirq; | 1196 | goto eirq; |
1197 | 1197 | ||
1198 | host->irq_control(host, 0); | ||
1199 | |||
1200 | /* | 1198 | /* |
1201 | * Now that the interrupt is disabled make sure the interrupt | 1199 | * Now that we "own" the interrupt make sure the interrupt mask bit is |
1202 | * mask bit is cleared on i.MX21. Otherwise we can't read | 1200 | * cleared on i.MX21. Otherwise we can't read the interrupt status bit |
1203 | * the interrupt status bit on this machine. | 1201 | * on this machine. |
1204 | */ | 1202 | */ |
1205 | if (cpu_is_mx21()) | 1203 | if (host->irqpending_quirk) { |
1206 | irq_control_v1_v2(host, 1); | 1204 | disable_irq_nosync(host->irq); |
1205 | host->irq_control(host, 1); | ||
1206 | } | ||
1207 | 1207 | ||
1208 | /* first scan to find the device and get the page size */ | 1208 | /* first scan to find the device and get the page size */ |
1209 | if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) { | 1209 | if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) { |