Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 211536
b: refs/heads/master
c: 63f1474
h: refs/heads/master
v: v3
  • Loading branch information
Sascha Hauer authored and Linus Torvalds committed Oct 18, 2010
1 parent 53b5061 commit df8646c
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 10 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f68c834b045afc8c80ec167cccf48934c8970022
refs/heads/master: 63f1474c69c061f923068a25f136dca0c49cd478
92 changes: 83 additions & 9 deletions trunk/drivers/mtd/nand/mxc_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/completion.h>

#include <asm/mach/flash.h>
#include <mach/mxc_nand.h>
Expand Down Expand Up @@ -151,7 +153,7 @@ struct mxc_nand_host {
int irq;
int eccsize;

wait_queue_head_t irq_waitq;
struct completion op_completion;

uint8_t *data_buf;
unsigned int buf_start;
Expand All @@ -164,6 +166,7 @@ struct mxc_nand_host {
void (*send_read_id)(struct mxc_nand_host *);
uint16_t (*get_dev_status)(struct mxc_nand_host *);
int (*check_int)(struct mxc_nand_host *);
void (*irq_control)(struct mxc_nand_host *, int);
};

/* OOB placement block for use with hardware ecc generation */
Expand Down Expand Up @@ -216,9 +219,12 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
{
struct mxc_nand_host *host = dev_id;

disable_irq_nosync(irq);
if (!host->check_int(host))
return IRQ_NONE;

wake_up(&host->irq_waitq);
host->irq_control(host, 0);

complete(&host->op_completion);

return IRQ_HANDLED;
}
Expand All @@ -245,11 +251,54 @@ static int check_int_v1_v2(struct mxc_nand_host *host)
if (!(tmp & NFC_V1_V2_CONFIG2_INT))
return 0;

writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
if (!cpu_is_mx21())
writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);

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)
{
uint16_t tmp;

tmp = readw(NFC_V1_V2_CONFIG1);

if (activate)
tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
else
tmp |= NFC_V1_V2_CONFIG1_INT_MSK;

writew(tmp, NFC_V1_V2_CONFIG1);
}

static void irq_control_v3(struct mxc_nand_host *host, int activate)
{
uint32_t tmp;

tmp = readl(NFC_V3_CONFIG2);

if (activate)
tmp &= ~NFC_V3_CONFIG2_INT_MSK;
else
tmp |= NFC_V3_CONFIG2_INT_MSK;

writel(tmp, NFC_V3_CONFIG2);
}

/* This function polls the NANDFC to wait for the basic operation to
* complete by checking the INT bit of config2 register.
*/
Expand All @@ -259,10 +308,9 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq)

if (useirq) {
if (!host->check_int(host)) {

enable_irq(host->irq);

wait_event(host->irq_waitq, host->check_int(host));
INIT_COMPLETION(host->op_completion);
host->irq_control(host, 1);
wait_for_completion(&host->op_completion);
}
} else {
while (max_retries-- > 0) {
Expand Down Expand Up @@ -799,6 +847,7 @@ static void preset_v3(struct mtd_info *mtd)
NFC_V3_CONFIG2_2CMD_PHASES |
NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
NFC_V3_CONFIG2_ST_CMD(0x70) |
NFC_V3_CONFIG2_INT_MSK |
NFC_V3_CONFIG2_NUM_ADDR_PHASE0;

if (chip->ecc.mode == NAND_ECC_HW)
Expand Down Expand Up @@ -1024,6 +1073,10 @@ static int __init mxcnd_probe(struct platform_device *pdev)
host->send_read_id = send_read_id_v1_v2;
host->get_dev_status = get_dev_status_v1_v2;
host->check_int = check_int_v1_v2;
if (cpu_is_mx21())
host->irq_control = irq_control_mx21;
else
host->irq_control = irq_control_v1_v2;
}

if (nfc_is_v21()) {
Expand Down Expand Up @@ -1062,6 +1115,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
host->send_read_id = send_read_id_v3;
host->check_int = check_int_v3;
host->get_dev_status = get_dev_status_v3;
host->irq_control = irq_control_v3;
oob_smallpage = &nandv2_hw_eccoob_smallpage;
oob_largepage = &nandv2_hw_eccoob_largepage;
} else
Expand Down Expand Up @@ -1093,14 +1147,34 @@ static int __init mxcnd_probe(struct platform_device *pdev)
this->options |= NAND_USE_FLASH_BBT;
}

init_waitqueue_head(&host->irq_waitq);
init_completion(&host->op_completion);

host->irq = platform_get_irq(pdev, 0);

/*
* mask the interrupt. For i.MX21 explicitely call
* irq_control_v1_v2 to use the mask bit. We can't call
* disable_irq_nosync() for an interrupt we do not own yet.
*/
if (cpu_is_mx21())
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);
if (err)
goto eirq;

host->irq_control(host, 0);

/*
* Now that the interrupt is disabled make sure the interrupt
* mask bit is cleared on i.MX21. Otherwise we can't read
* the interrupt status bit on this machine.
*/
if (cpu_is_mx21())
irq_control_v1_v2(host, 1);

/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, 1, NULL)) {
err = -ENXIO;
Expand Down

0 comments on commit df8646c

Please sign in to comment.