|
@@ -130,6 +130,7 @@ struct pxa3xx_nand_host {
|
|
/* page size of attached chip */
|
|
/* page size of attached chip */
|
|
unsigned int page_size;
|
|
unsigned int page_size;
|
|
int use_ecc;
|
|
int use_ecc;
|
|
|
|
+ int cs;
|
|
|
|
|
|
/* calculated from pxa3xx_nand_flash data */
|
|
/* calculated from pxa3xx_nand_flash data */
|
|
unsigned int col_addr_cycles;
|
|
unsigned int col_addr_cycles;
|
|
@@ -165,9 +166,10 @@ struct pxa3xx_nand_info {
|
|
struct pxa_dma_desc *data_desc;
|
|
struct pxa_dma_desc *data_desc;
|
|
dma_addr_t data_desc_addr;
|
|
dma_addr_t data_desc_addr;
|
|
|
|
|
|
- struct pxa3xx_nand_host *host;
|
|
|
|
|
|
+ struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
|
|
unsigned int state;
|
|
unsigned int state;
|
|
|
|
|
|
|
|
+ int cs;
|
|
int use_ecc; /* use HW ECC ? */
|
|
int use_ecc; /* use HW ECC ? */
|
|
int use_dma; /* use DMA ? */
|
|
int use_dma; /* use DMA ? */
|
|
int is_ready;
|
|
int is_ready;
|
|
@@ -226,7 +228,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
|
|
/* Define a default flash type setting serve as flash detecting only */
|
|
/* Define a default flash type setting serve as flash detecting only */
|
|
#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
|
|
#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
|
|
|
|
|
|
-const char *mtd_names[] = {"pxa3xx_nand-0", NULL};
|
|
|
|
|
|
+const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL};
|
|
|
|
|
|
#define NDTR0_tCH(c) (min((c), 7) << 19)
|
|
#define NDTR0_tCH(c) (min((c), 7) << 19)
|
|
#define NDTR0_tCS(c) (min((c), 7) << 16)
|
|
#define NDTR0_tCS(c) (min((c), 7) << 16)
|
|
@@ -268,7 +270,7 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
|
|
|
|
|
|
static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
|
|
static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
|
|
{
|
|
{
|
|
- struct pxa3xx_nand_host *host = info->host;
|
|
|
|
|
|
+ struct pxa3xx_nand_host *host = info->host[info->cs];
|
|
int oob_enable = host->reg_ndcr & NDCR_SPARE_EN;
|
|
int oob_enable = host->reg_ndcr & NDCR_SPARE_EN;
|
|
|
|
|
|
info->data_size = host->page_size;
|
|
info->data_size = host->page_size;
|
|
@@ -295,7 +297,7 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
|
|
*/
|
|
*/
|
|
static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
|
|
static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
|
|
{
|
|
{
|
|
- struct pxa3xx_nand_host *host = info->host;
|
|
|
|
|
|
+ struct pxa3xx_nand_host *host = info->host[info->cs];
|
|
uint32_t ndcr;
|
|
uint32_t ndcr;
|
|
|
|
|
|
ndcr = host->reg_ndcr;
|
|
ndcr = host->reg_ndcr;
|
|
@@ -420,6 +422,15 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
|
|
{
|
|
{
|
|
struct pxa3xx_nand_info *info = devid;
|
|
struct pxa3xx_nand_info *info = devid;
|
|
unsigned int status, is_completed = 0;
|
|
unsigned int status, is_completed = 0;
|
|
|
|
+ unsigned int ready, cmd_done;
|
|
|
|
+
|
|
|
|
+ if (info->cs == 0) {
|
|
|
|
+ ready = NDSR_FLASH_RDY;
|
|
|
|
+ cmd_done = NDSR_CS0_CMDD;
|
|
|
|
+ } else {
|
|
|
|
+ ready = NDSR_RDY;
|
|
|
|
+ cmd_done = NDSR_CS1_CMDD;
|
|
|
|
+ }
|
|
|
|
|
|
status = nand_readl(info, NDSR);
|
|
status = nand_readl(info, NDSR);
|
|
|
|
|
|
@@ -441,11 +452,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
|
|
handle_data_pio(info);
|
|
handle_data_pio(info);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- if (status & NDSR_CS0_CMDD) {
|
|
|
|
|
|
+ if (status & cmd_done) {
|
|
info->state = STATE_CMD_DONE;
|
|
info->state = STATE_CMD_DONE;
|
|
is_completed = 1;
|
|
is_completed = 1;
|
|
}
|
|
}
|
|
- if (status & NDSR_FLASH_RDY) {
|
|
|
|
|
|
+ if (status & ready) {
|
|
info->is_ready = 1;
|
|
info->is_ready = 1;
|
|
info->state = STATE_READY;
|
|
info->state = STATE_READY;
|
|
}
|
|
}
|
|
@@ -480,9 +491,11 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
|
|
{
|
|
{
|
|
uint16_t cmd;
|
|
uint16_t cmd;
|
|
int addr_cycle, exec_cmd;
|
|
int addr_cycle, exec_cmd;
|
|
- struct pxa3xx_nand_host *host = info->host;
|
|
|
|
- struct mtd_info *mtd = host->mtd;
|
|
|
|
|
|
+ struct pxa3xx_nand_host *host;
|
|
|
|
+ struct mtd_info *mtd;
|
|
|
|
|
|
|
|
+ host = info->host[info->cs];
|
|
|
|
+ mtd = host->mtd;
|
|
addr_cycle = 0;
|
|
addr_cycle = 0;
|
|
exec_cmd = 1;
|
|
exec_cmd = 1;
|
|
|
|
|
|
@@ -492,8 +505,11 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
|
|
info->oob_size = 0;
|
|
info->oob_size = 0;
|
|
info->use_ecc = 0;
|
|
info->use_ecc = 0;
|
|
info->is_ready = 0;
|
|
info->is_ready = 0;
|
|
- info->ndcb0 = 0;
|
|
|
|
info->retcode = ERR_NONE;
|
|
info->retcode = ERR_NONE;
|
|
|
|
+ if (info->cs != 0)
|
|
|
|
+ info->ndcb0 = NDCB0_CSEL;
|
|
|
|
+ else
|
|
|
|
+ info->ndcb0 = 0;
|
|
|
|
|
|
switch (command) {
|
|
switch (command) {
|
|
case NAND_CMD_READ0:
|
|
case NAND_CMD_READ0:
|
|
@@ -637,6 +653,17 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
|
if (host->reg_ndcr & NDCR_DWIDTH_M)
|
|
if (host->reg_ndcr & NDCR_DWIDTH_M)
|
|
column /= 2;
|
|
column /= 2;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * There may be different NAND chip hooked to
|
|
|
|
+ * different chip select, so check whether
|
|
|
|
+ * chip select has been changed, if yes, reset the timing
|
|
|
|
+ */
|
|
|
|
+ if (info->cs != host->cs) {
|
|
|
|
+ info->cs = host->cs;
|
|
|
|
+ nand_writel(info, NDTR0CS0, host->ndtr0cs0);
|
|
|
|
+ nand_writel(info, NDTR1CS0, host->ndtr1cs0);
|
|
|
|
+ }
|
|
|
|
+
|
|
info->state = STATE_PREPARED;
|
|
info->state = STATE_PREPARED;
|
|
exec_cmd = prepare_command_pool(info, command, column, page_addr);
|
|
exec_cmd = prepare_command_pool(info, command, column, page_addr);
|
|
if (exec_cmd) {
|
|
if (exec_cmd) {
|
|
@@ -778,7 +805,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
|
|
{
|
|
{
|
|
struct platform_device *pdev = info->pdev;
|
|
struct platform_device *pdev = info->pdev;
|
|
struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
|
|
struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
|
|
- struct pxa3xx_nand_host *host = info->host;
|
|
|
|
|
|
+ struct pxa3xx_nand_host *host = info->host[info->cs];
|
|
uint32_t ndcr = 0x0; /* enable all interrupts */
|
|
uint32_t ndcr = 0x0; /* enable all interrupts */
|
|
|
|
|
|
if (f->page_size != 2048 && f->page_size != 512) {
|
|
if (f->page_size != 2048 && f->page_size != 512) {
|
|
@@ -822,7 +849,11 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
|
|
|
|
|
|
static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
|
|
static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
|
|
{
|
|
{
|
|
- struct pxa3xx_nand_host *host = info->host;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * We set 0 by hard coding here, for we don't support keep_config
|
|
|
|
+ * when there is more than one chip attached to the controller
|
|
|
|
+ */
|
|
|
|
+ struct pxa3xx_nand_host *host = info->host[0];
|
|
uint32_t ndcr = nand_readl(info, NDCR);
|
|
uint32_t ndcr = nand_readl(info, NDCR);
|
|
|
|
|
|
if (ndcr & NDCR_PAGE_SZ) {
|
|
if (ndcr & NDCR_PAGE_SZ) {
|
|
@@ -884,9 +915,9 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
|
|
|
|
|
|
static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
|
|
static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
|
|
{
|
|
{
|
|
- struct mtd_info *mtd = info->host->mtd;
|
|
|
|
|
|
+ struct mtd_info *mtd;
|
|
int ret;
|
|
int ret;
|
|
-
|
|
|
|
|
|
+ mtd = info->host[info->cs]->mtd;
|
|
/* use the common timing to make a try */
|
|
/* use the common timing to make a try */
|
|
ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
|
|
ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
|
|
if (ret)
|
|
if (ret)
|
|
@@ -917,7 +948,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
|
|
|
|
|
|
ret = pxa3xx_nand_sensing(info);
|
|
ret = pxa3xx_nand_sensing(info);
|
|
if (ret) {
|
|
if (ret) {
|
|
- dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n");
|
|
|
|
|
|
+ dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
|
|
|
|
+ info->cs);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -996,41 +1028,47 @@ KEEP_CONFIG:
|
|
|
|
|
|
static int alloc_nand_resource(struct platform_device *pdev)
|
|
static int alloc_nand_resource(struct platform_device *pdev)
|
|
{
|
|
{
|
|
|
|
+ struct pxa3xx_nand_platform_data *pdata;
|
|
struct pxa3xx_nand_info *info;
|
|
struct pxa3xx_nand_info *info;
|
|
struct pxa3xx_nand_host *host;
|
|
struct pxa3xx_nand_host *host;
|
|
struct nand_chip *chip;
|
|
struct nand_chip *chip;
|
|
struct mtd_info *mtd;
|
|
struct mtd_info *mtd;
|
|
struct resource *r;
|
|
struct resource *r;
|
|
- int ret, irq;
|
|
|
|
|
|
+ int ret, irq, cs;
|
|
|
|
|
|
- info = kzalloc(sizeof(*info) + sizeof(*mtd) + sizeof(*host),
|
|
|
|
- GFP_KERNEL);
|
|
|
|
|
|
+ pdata = pdev->dev.platform_data;
|
|
|
|
+ info = kzalloc(sizeof(*info) + (sizeof(*mtd) +
|
|
|
|
+ sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
|
|
if (!info) {
|
|
if (!info) {
|
|
dev_err(&pdev->dev, "failed to allocate memory\n");
|
|
dev_err(&pdev->dev, "failed to allocate memory\n");
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
- mtd = (struct mtd_info *)(&info[1]);
|
|
|
|
- chip = (struct nand_chip *)(&mtd[1]);
|
|
|
|
- host = (struct pxa3xx_nand_host *)chip;
|
|
|
|
info->pdev = pdev;
|
|
info->pdev = pdev;
|
|
- info->host = host;
|
|
|
|
- host->mtd = mtd;
|
|
|
|
- host->info_data = info;
|
|
|
|
- mtd->priv = host;
|
|
|
|
- mtd->owner = THIS_MODULE;
|
|
|
|
-
|
|
|
|
- chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
|
|
|
|
- chip->ecc.write_page = pxa3xx_nand_write_page_hwecc;
|
|
|
|
- chip->controller = &info->controller;
|
|
|
|
- chip->waitfunc = pxa3xx_nand_waitfunc;
|
|
|
|
- chip->select_chip = pxa3xx_nand_select_chip;
|
|
|
|
- chip->cmdfunc = pxa3xx_nand_cmdfunc;
|
|
|
|
- chip->read_word = pxa3xx_nand_read_word;
|
|
|
|
- chip->read_byte = pxa3xx_nand_read_byte;
|
|
|
|
- chip->read_buf = pxa3xx_nand_read_buf;
|
|
|
|
- chip->write_buf = pxa3xx_nand_write_buf;
|
|
|
|
- chip->verify_buf = pxa3xx_nand_verify_buf;
|
|
|
|
|
|
+ for (cs = 0; cs < pdata->num_cs; cs++) {
|
|
|
|
+ mtd = (struct mtd_info *)((unsigned int)&info[1] +
|
|
|
|
+ (sizeof(*mtd) + sizeof(*host)) * cs);
|
|
|
|
+ chip = (struct nand_chip *)(&mtd[1]);
|
|
|
|
+ host = (struct pxa3xx_nand_host *)chip;
|
|
|
|
+ info->host[cs] = host;
|
|
|
|
+ host->mtd = mtd;
|
|
|
|
+ host->cs = cs;
|
|
|
|
+ host->info_data = info;
|
|
|
|
+ mtd->priv = host;
|
|
|
|
+ mtd->owner = THIS_MODULE;
|
|
|
|
+
|
|
|
|
+ chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
|
|
|
|
+ chip->ecc.write_page = pxa3xx_nand_write_page_hwecc;
|
|
|
|
+ chip->controller = &info->controller;
|
|
|
|
+ chip->waitfunc = pxa3xx_nand_waitfunc;
|
|
|
|
+ chip->select_chip = pxa3xx_nand_select_chip;
|
|
|
|
+ chip->cmdfunc = pxa3xx_nand_cmdfunc;
|
|
|
|
+ chip->read_word = pxa3xx_nand_read_word;
|
|
|
|
+ chip->read_byte = pxa3xx_nand_read_byte;
|
|
|
|
+ chip->read_buf = pxa3xx_nand_read_buf;
|
|
|
|
+ chip->write_buf = pxa3xx_nand_write_buf;
|
|
|
|
+ chip->verify_buf = pxa3xx_nand_verify_buf;
|
|
|
|
+ }
|
|
|
|
|
|
spin_lock_init(&chip->controller->lock);
|
|
spin_lock_init(&chip->controller->lock);
|
|
init_waitqueue_head(&chip->controller->wq);
|
|
init_waitqueue_head(&chip->controller->wq);
|
|
@@ -1128,12 +1166,14 @@ fail_free_mtd:
|
|
static int pxa3xx_nand_remove(struct platform_device *pdev)
|
|
static int pxa3xx_nand_remove(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
|
|
+ struct pxa3xx_nand_platform_data *pdata;
|
|
struct resource *r;
|
|
struct resource *r;
|
|
- int irq;
|
|
|
|
|
|
+ int irq, cs;
|
|
|
|
|
|
if (!info)
|
|
if (!info)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ pdata = pdev->dev.platform_data;
|
|
platform_set_drvdata(pdev, NULL);
|
|
platform_set_drvdata(pdev, NULL);
|
|
|
|
|
|
irq = platform_get_irq(pdev, 0);
|
|
irq = platform_get_irq(pdev, 0);
|
|
@@ -1153,7 +1193,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
|
|
clk_disable(info->clk);
|
|
clk_disable(info->clk);
|
|
clk_put(info->clk);
|
|
clk_put(info->clk);
|
|
|
|
|
|
- nand_release(info->host->mtd);
|
|
|
|
|
|
+ for (cs = 0; cs < pdata->num_cs; cs++)
|
|
|
|
+ nand_release(info->host[cs]->mtd);
|
|
kfree(info);
|
|
kfree(info);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -1162,7 +1203,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct pxa3xx_nand_platform_data *pdata;
|
|
struct pxa3xx_nand_platform_data *pdata;
|
|
struct pxa3xx_nand_info *info;
|
|
struct pxa3xx_nand_info *info;
|
|
- int ret;
|
|
|
|
|
|
+ int ret, cs, probe_success;
|
|
|
|
|
|
pdata = pdev->dev.platform_data;
|
|
pdata = pdev->dev.platform_data;
|
|
if (!pdata) {
|
|
if (!pdata) {
|
|
@@ -1177,41 +1218,69 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
|
|
}
|
|
}
|
|
|
|
|
|
info = platform_get_drvdata(pdev);
|
|
info = platform_get_drvdata(pdev);
|
|
- if (pxa3xx_nand_scan(info->host->mtd)) {
|
|
|
|
- dev_err(&pdev->dev, "failed to scan nand\n");
|
|
|
|
|
|
+ probe_success = 0;
|
|
|
|
+ for (cs = 0; cs < pdata->num_cs; cs++) {
|
|
|
|
+ info->cs = cs;
|
|
|
|
+ ret = pxa3xx_nand_scan(info->host[cs]->mtd);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
|
|
|
|
+ cs);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0,
|
|
|
|
+ pdata->parts[cs], pdata->nr_parts[cs]);
|
|
|
|
+ if (!ret)
|
|
|
|
+ probe_success = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!probe_success) {
|
|
pxa3xx_nand_remove(pdev);
|
|
pxa3xx_nand_remove(pdev);
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
- return mtd_device_parse_register(info->host->mtd, NULL, 0,
|
|
|
|
- pdata->parts, pdata->nr_parts);
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
#ifdef CONFIG_PM
|
|
static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
|
|
static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
|
|
{
|
|
{
|
|
struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
- struct mtd_info *mtd = info->mtd;
|
|
|
|
|
|
+ struct pxa3xx_nand_platform_data *pdata;
|
|
|
|
+ struct mtd_info *mtd;
|
|
|
|
+ int cs;
|
|
|
|
|
|
|
|
+ pdata = pdev->dev.platform_data;
|
|
if (info->state) {
|
|
if (info->state) {
|
|
dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
|
|
dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
}
|
|
}
|
|
|
|
|
|
- mtd->suspend(mtd);
|
|
|
|
|
|
+ for (cs = 0; cs < pdata->num_cs; cs++) {
|
|
|
|
+ mtd = info->host[cs]->mtd;
|
|
|
|
+ mtd->suspend(mtd);
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int pxa3xx_nand_resume(struct platform_device *pdev)
|
|
static int pxa3xx_nand_resume(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
- struct mtd_info *mtd = info->mtd;
|
|
|
|
|
|
+ struct pxa3xx_nand_platform_data *pdata;
|
|
|
|
+ struct mtd_info *mtd;
|
|
|
|
+ int cs;
|
|
|
|
|
|
|
|
+ pdata = pdev->dev.platform_data;
|
|
/* We don't want to handle interrupt without calling mtd routine */
|
|
/* We don't want to handle interrupt without calling mtd routine */
|
|
disable_int(info, NDCR_INT_MASK);
|
|
disable_int(info, NDCR_INT_MASK);
|
|
|
|
|
|
- nand_writel(info, NDTR0CS0, info->host->ndtr0cs0);
|
|
|
|
- nand_writel(info, NDTR1CS0, info->host->ndtr1cs0);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Directly set the chip select to a invalid value,
|
|
|
|
+ * then the driver would reset the timing according
|
|
|
|
+ * to current chip select at the beginning of cmdfunc
|
|
|
|
+ */
|
|
|
|
+ info->cs = 0xff;
|
|
|
|
|
|
/*
|
|
/*
|
|
* As the spec says, the NDSR would be updated to 0x1800 when
|
|
* As the spec says, the NDSR would be updated to 0x1800 when
|
|
@@ -1220,7 +1289,11 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
|
|
* all status before resume
|
|
* all status before resume
|
|
*/
|
|
*/
|
|
nand_writel(info, NDSR, NDSR_MASK);
|
|
nand_writel(info, NDSR, NDSR_MASK);
|
|
- mtd->resume(mtd);
|
|
|
|
|
|
+ for (cs = 0; cs < pdata->num_cs; cs++) {
|
|
|
|
+ mtd = info->host[cs]->mtd;
|
|
|
|
+ mtd->resume(mtd);
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
#else
|
|
#else
|