Commit 8556958a authored by Uwe Kleine-König's avatar Uwe Kleine-König Committed by David Woodhouse

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: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 8d1fd16d
...@@ -173,6 +173,13 @@ struct mxc_nand_host { ...@@ -173,6 +173,13 @@ struct mxc_nand_host {
uint16_t (*get_dev_status)(struct mxc_nand_host *); uint16_t (*get_dev_status)(struct mxc_nand_host *);
int (*check_int)(struct mxc_nand_host *); int (*check_int)(struct mxc_nand_host *);
void (*irq_control)(struct mxc_nand_host *, int); void (*irq_control)(struct mxc_nand_host *, int);
/*
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
* (CONFIG1:INT_MSK is set). To handle this the driver uses
* enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
*/
int irqpending_quirk;
}; };
/* OOB placement block for use with hardware ecc generation */ /* OOB placement block for use with hardware ecc generation */
...@@ -244,20 +251,6 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = { ...@@ -244,20 +251,6 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
{
struct mxc_nand_host *host = dev_id;
if (!host->check_int(host))
return IRQ_NONE;
host->irq_control(host, 0);
complete(&host->op_completion);
return IRQ_HANDLED;
}
static int check_int_v3(struct mxc_nand_host *host) static int check_int_v3(struct mxc_nand_host *host)
{ {
uint32_t tmp; uint32_t tmp;
...@@ -280,26 +273,12 @@ static int check_int_v1_v2(struct mxc_nand_host *host) ...@@ -280,26 +273,12 @@ static int check_int_v1_v2(struct mxc_nand_host *host)
if (!(tmp & NFC_V1_V2_CONFIG2_INT)) if (!(tmp & NFC_V1_V2_CONFIG2_INT))
return 0; return 0;
if (!cpu_is_mx21()) if (!host->irqpending_quirk)
writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
return 1; return 1;
} }
/*
* It has been observed that the i.MX21 cannot read the CONFIG2:INT bit
* if interrupts are masked (CONFIG1:INT_MSK is set). To handle this, the
* driver can enable/disable the irq line rather than simply masking the
* interrupts.
*/
static void irq_control_mx21(struct mxc_nand_host *host, int activate)
{
if (activate)
enable_irq(host->irq);
else
disable_irq_nosync(host->irq);
}
static void irq_control_v1_v2(struct mxc_nand_host *host, int activate) static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
{ {
uint16_t tmp; uint16_t tmp;
...@@ -328,6 +307,32 @@ static void irq_control_v3(struct mxc_nand_host *host, int activate) ...@@ -328,6 +307,32 @@ static void irq_control_v3(struct mxc_nand_host *host, int activate)
writel(tmp, NFC_V3_CONFIG2); writel(tmp, NFC_V3_CONFIG2);
} }
static void irq_control(struct mxc_nand_host *host, int activate)
{
if (host->irqpending_quirk) {
if (activate)
enable_irq(host->irq);
else
disable_irq_nosync(host->irq);
} else {
host->irq_control(host, activate);
}
}
static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
{
struct mxc_nand_host *host = dev_id;
if (!host->check_int(host))
return IRQ_NONE;
irq_control(host, 0);
complete(&host->op_completion);
return IRQ_HANDLED;
}
/* This function polls the NANDFC to wait for the basic operation to /* This function polls the NANDFC to wait for the basic operation to
* complete by checking the INT bit of config2 register. * complete by checking the INT bit of config2 register.
*/ */
...@@ -338,7 +343,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) ...@@ -338,7 +343,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq)
if (useirq) { if (useirq) {
if (!host->check_int(host)) { if (!host->check_int(host)) {
INIT_COMPLETION(host->op_completion); INIT_COMPLETION(host->op_completion);
host->irq_control(host, 1); irq_control(host, 1);
wait_for_completion(&host->op_completion); wait_for_completion(&host->op_completion);
} }
} else { } else {
...@@ -374,7 +379,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) ...@@ -374,7 +379,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
writew(cmd, NFC_V1_V2_FLASH_CMD); writew(cmd, NFC_V1_V2_FLASH_CMD);
writew(NFC_CMD, NFC_V1_V2_CONFIG2); writew(NFC_CMD, NFC_V1_V2_CONFIG2);
if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) { if (host->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
int max_retries = 100; int max_retries = 100;
/* Reset completion is indicated by NFC_CONFIG2 */ /* Reset completion is indicated by NFC_CONFIG2 */
/* being set to 0 */ /* being set to 0 */
...@@ -812,7 +817,7 @@ static void preset_v1_v2(struct mtd_info *mtd) ...@@ -812,7 +817,7 @@ static void preset_v1_v2(struct mtd_info *mtd)
if (nfc_is_v21()) if (nfc_is_v21())
config1 |= NFC_V2_CONFIG1_FP_INT; config1 |= NFC_V2_CONFIG1_FP_INT;
if (!cpu_is_mx21()) if (!host->irqpending_quirk)
config1 |= NFC_V1_V2_CONFIG1_INT_MSK; config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
if (nfc_is_v21() && mtd->writesize) { if (nfc_is_v21() && mtd->writesize) {
...@@ -1103,10 +1108,9 @@ static int __init mxcnd_probe(struct platform_device *pdev) ...@@ -1103,10 +1108,9 @@ static int __init mxcnd_probe(struct platform_device *pdev)
host->send_read_id = send_read_id_v1_v2; host->send_read_id = send_read_id_v1_v2;
host->get_dev_status = get_dev_status_v1_v2; host->get_dev_status = get_dev_status_v1_v2;
host->check_int = check_int_v1_v2; host->check_int = check_int_v1_v2;
host->irq_control = irq_control_v1_v2;
if (cpu_is_mx21()) if (cpu_is_mx21())
host->irq_control = irq_control_mx21; host->irqpending_quirk = 1;
else
host->irq_control = irq_control_v1_v2;
} }
if (nfc_is_v21()) { if (nfc_is_v21()) {
...@@ -1182,28 +1186,24 @@ static int __init mxcnd_probe(struct platform_device *pdev) ...@@ -1182,28 +1186,24 @@ static int __init mxcnd_probe(struct platform_device *pdev)
host->irq = platform_get_irq(pdev, 0); host->irq = platform_get_irq(pdev, 0);
/* /*
* mask the interrupt. For i.MX21 explicitely call * Use host->irq_control here instead of irq_control because we must not
* irq_control_v1_v2 to use the mask bit. We can't call * disable_irq_nosync without having requested the irq
* disable_irq_nosync() for an interrupt we do not own yet.
*/ */
if (cpu_is_mx21()) host->irq_control(host, 0);
irq_control_v1_v2(host, 0);
else
host->irq_control(host, 0);
err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
if (err) if (err)
goto eirq; goto eirq;
host->irq_control(host, 0);
/* /*
* Now that the interrupt is disabled make sure the interrupt * Now that we "own" the interrupt make sure the interrupt mask bit is
* mask bit is cleared on i.MX21. Otherwise we can't read * cleared on i.MX21. Otherwise we can't read the interrupt status bit
* the interrupt status bit on this machine. * on this machine.
*/ */
if (cpu_is_mx21()) if (host->irqpending_quirk) {
irq_control_v1_v2(host, 1); disable_irq_nosync(host->irq);
host->irq_control(host, 1);
}
/* first scan to find the device and get the page size */ /* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) { if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment