|
@@ -126,6 +126,7 @@ struct pxa3xx_nand_info {
|
|
|
unsigned int buf_start;
|
|
|
unsigned int buf_count;
|
|
|
|
|
|
+ struct mtd_info *mtd;
|
|
|
/* DMA information */
|
|
|
int drcmr_dat;
|
|
|
int drcmr_cmd;
|
|
@@ -1044,34 +1045,27 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
|
|
|
this->chip_delay = 25;
|
|
|
}
|
|
|
|
|
|
-static int pxa3xx_nand_probe(struct platform_device *pdev)
|
|
|
+static
|
|
|
+struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct pxa3xx_nand_platform_data *pdata;
|
|
|
+ struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
|
|
|
struct pxa3xx_nand_info *info;
|
|
|
- struct nand_chip *this;
|
|
|
struct mtd_info *mtd;
|
|
|
struct resource *r;
|
|
|
- int ret = 0, irq;
|
|
|
-
|
|
|
- pdata = pdev->dev.platform_data;
|
|
|
-
|
|
|
- if (!pdata) {
|
|
|
- dev_err(&pdev->dev, "no platform data defined\n");
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
+ int ret, irq;
|
|
|
|
|
|
mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info),
|
|
|
GFP_KERNEL);
|
|
|
if (!mtd) {
|
|
|
dev_err(&pdev->dev, "failed to allocate memory\n");
|
|
|
- return -ENOMEM;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
info = (struct pxa3xx_nand_info *)(&mtd[1]);
|
|
|
info->pdev = pdev;
|
|
|
|
|
|
- this = &info->nand_chip;
|
|
|
mtd->priv = info;
|
|
|
+ info->mtd = mtd;
|
|
|
mtd->owner = THIS_MODULE;
|
|
|
|
|
|
info->clk = clk_get(&pdev->dev, NULL);
|
|
@@ -1149,31 +1143,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
|
|
|
}
|
|
|
|
|
|
pxa3xx_nand_init_mtd(mtd, info);
|
|
|
+ platform_set_drvdata(pdev, info);
|
|
|
|
|
|
- platform_set_drvdata(pdev, mtd);
|
|
|
-
|
|
|
- if (nand_scan(mtd, 1)) {
|
|
|
- dev_err(&pdev->dev, "failed to scan nand\n");
|
|
|
- ret = -ENXIO;
|
|
|
- goto fail_free_irq;
|
|
|
- }
|
|
|
-
|
|
|
-#ifdef CONFIG_MTD_PARTITIONS
|
|
|
- if (mtd_has_cmdlinepart()) {
|
|
|
- static const char *probes[] = { "cmdlinepart", NULL };
|
|
|
- struct mtd_partition *parts;
|
|
|
- int nr_parts;
|
|
|
-
|
|
|
- nr_parts = parse_mtd_partitions(mtd, probes, &parts, 0);
|
|
|
-
|
|
|
- if (nr_parts)
|
|
|
- return add_mtd_partitions(mtd, parts, nr_parts);
|
|
|
- }
|
|
|
-
|
|
|
- return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
|
|
|
-#else
|
|
|
- return 0;
|
|
|
-#endif
|
|
|
+ return info;
|
|
|
|
|
|
fail_free_irq:
|
|
|
free_irq(irq, info);
|
|
@@ -1193,13 +1165,13 @@ fail_put_clk:
|
|
|
clk_put(info->clk);
|
|
|
fail_free_mtd:
|
|
|
kfree(mtd);
|
|
|
- return ret;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
static int pxa3xx_nand_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct mtd_info *mtd = platform_get_drvdata(pdev);
|
|
|
- struct pxa3xx_nand_info *info = mtd->priv;
|
|
|
+ struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
|
+ struct mtd_info *mtd = info->mtd;
|
|
|
struct resource *r;
|
|
|
int irq;
|
|
|
|
|
@@ -1230,11 +1202,50 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int pxa3xx_nand_probe(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct pxa3xx_nand_platform_data *pdata;
|
|
|
+ struct pxa3xx_nand_info *info;
|
|
|
+
|
|
|
+ pdata = pdev->dev.platform_data;
|
|
|
+ if (!pdata) {
|
|
|
+ dev_err(&pdev->dev, "no platform data defined\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ info = alloc_nand_resource(pdev);
|
|
|
+ if (info == NULL)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (nand_scan(info->mtd, 1)) {
|
|
|
+ dev_err(&pdev->dev, "failed to scan nand\n");
|
|
|
+ pxa3xx_nand_remove(pdev);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef CONFIG_MTD_PARTITIONS
|
|
|
+ if (mtd_has_cmdlinepart()) {
|
|
|
+ const char *probes[] = { "cmdlinepart", NULL };
|
|
|
+ struct mtd_partition *parts;
|
|
|
+ int nr_parts;
|
|
|
+
|
|
|
+ nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0);
|
|
|
+
|
|
|
+ if (nr_parts)
|
|
|
+ return add_mtd_partitions(mtd, parts, nr_parts);
|
|
|
+ }
|
|
|
+
|
|
|
+ return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
|
|
|
+#else
|
|
|
+ return 0;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_PM
|
|
|
static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
|
|
|
{
|
|
|
- struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
|
|
|
- struct pxa3xx_nand_info *info = mtd->priv;
|
|
|
+ struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
|
+ struct mtd_info *mtd = info->mtd;
|
|
|
|
|
|
if (info->state != STATE_READY) {
|
|
|
dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
|
|
@@ -1246,8 +1257,8 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
|
|
|
|
|
|
static int pxa3xx_nand_resume(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
|
|
|
- struct pxa3xx_nand_info *info = mtd->priv;
|
|
|
+ struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
|
|
|
+ struct mtd_info *mtd = info->mtd;
|
|
|
|
|
|
nand_writel(info, NDTR0CS0, info->ndtr0cs0);
|
|
|
nand_writel(info, NDTR1CS0, info->ndtr1cs0);
|