diff options
Diffstat (limited to 'drivers/mtd/nand/mxc_nand.c')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 168 |
1 files changed, 81 insertions, 87 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 5683604967d7..72e31d86030d 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -43,8 +43,8 @@ | |||
43 | 43 | ||
44 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) | 44 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) |
45 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) | 45 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) |
46 | #define nfc_is_v3_2() (cpu_is_mx51() || cpu_is_mx53()) | 46 | #define nfc_is_v3_2a() cpu_is_mx51() |
47 | #define nfc_is_v3() nfc_is_v3_2() | 47 | #define nfc_is_v3_2b() cpu_is_mx53() |
48 | 48 | ||
49 | /* Addresses for NFC registers */ | 49 | /* Addresses for NFC registers */ |
50 | #define NFC_V1_V2_BUF_SIZE (host->regs + 0x00) | 50 | #define NFC_V1_V2_BUF_SIZE (host->regs + 0x00) |
@@ -122,7 +122,7 @@ | |||
122 | #define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4) | 122 | #define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4) |
123 | #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5) | 123 | #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5) |
124 | #define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6) | 124 | #define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6) |
125 | #define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7) | 125 | #define NFC_V3_CONFIG2_PPB(x, shift) (((x) & 0x3) << shift) |
126 | #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12) | 126 | #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12) |
127 | #define NFC_V3_CONFIG2_INT_MSK (1 << 15) | 127 | #define NFC_V3_CONFIG2_INT_MSK (1 << 15) |
128 | #define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24) | 128 | #define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24) |
@@ -174,6 +174,7 @@ struct mxc_nand_devtype_data { | |||
174 | int spare_len; | 174 | int spare_len; |
175 | int eccbytes; | 175 | int eccbytes; |
176 | int eccsize; | 176 | int eccsize; |
177 | int ppb_shift; | ||
177 | }; | 178 | }; |
178 | 179 | ||
179 | struct mxc_nand_host { | 180 | struct mxc_nand_host { |
@@ -745,14 +746,6 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
745 | host->buf_start += n; | 746 | host->buf_start += n; |
746 | } | 747 | } |
747 | 748 | ||
748 | /* Used by the upper layer to verify the data in NAND Flash | ||
749 | * with the data in the buf. */ | ||
750 | static int mxc_nand_verify_buf(struct mtd_info *mtd, | ||
751 | const u_char *buf, int len) | ||
752 | { | ||
753 | return -EFAULT; | ||
754 | } | ||
755 | |||
756 | /* This function is used by upper layer for select and | 749 | /* This function is used by upper layer for select and |
757 | * deselect of the NAND chip */ | 750 | * deselect of the NAND chip */ |
758 | static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip) | 751 | static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip) |
@@ -784,7 +777,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip) | |||
784 | if (chip == -1) { | 777 | if (chip == -1) { |
785 | /* Disable the NFC clock */ | 778 | /* Disable the NFC clock */ |
786 | if (host->clk_act) { | 779 | if (host->clk_act) { |
787 | clk_disable(host->clk); | 780 | clk_disable_unprepare(host->clk); |
788 | host->clk_act = 0; | 781 | host->clk_act = 0; |
789 | } | 782 | } |
790 | return; | 783 | return; |
@@ -792,7 +785,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip) | |||
792 | 785 | ||
793 | if (!host->clk_act) { | 786 | if (!host->clk_act) { |
794 | /* Enable the NFC clock */ | 787 | /* Enable the NFC clock */ |
795 | clk_enable(host->clk); | 788 | clk_prepare_enable(host->clk); |
796 | host->clk_act = 1; | 789 | host->clk_act = 1; |
797 | } | 790 | } |
798 | 791 | ||
@@ -1021,7 +1014,9 @@ static void preset_v3(struct mtd_info *mtd) | |||
1021 | } | 1014 | } |
1022 | 1015 | ||
1023 | if (mtd->writesize) { | 1016 | if (mtd->writesize) { |
1024 | config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6); | 1017 | config2 |= NFC_V3_CONFIG2_PPB( |
1018 | ffs(mtd->erasesize / mtd->writesize) - 6, | ||
1019 | host->devtype_data->ppb_shift); | ||
1025 | host->eccsize = get_eccsize(mtd); | 1020 | host->eccsize = get_eccsize(mtd); |
1026 | if (host->eccsize == 8) | 1021 | if (host->eccsize == 8) |
1027 | config2 |= NFC_V3_CONFIG2_ECC_MODE_8; | 1022 | config2 |= NFC_V3_CONFIG2_ECC_MODE_8; |
@@ -1234,7 +1229,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { | |||
1234 | .eccsize = 0, | 1229 | .eccsize = 0, |
1235 | }; | 1230 | }; |
1236 | 1231 | ||
1237 | /* v3: i.MX51, i.MX53 */ | 1232 | /* v3.2a: i.MX51 */ |
1238 | static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { | 1233 | static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { |
1239 | .preset = preset_v3, | 1234 | .preset = preset_v3, |
1240 | .send_cmd = send_cmd_v3, | 1235 | .send_cmd = send_cmd_v3, |
@@ -1258,6 +1253,34 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { | |||
1258 | .spare_len = 64, | 1253 | .spare_len = 64, |
1259 | .eccbytes = 0, | 1254 | .eccbytes = 0, |
1260 | .eccsize = 0, | 1255 | .eccsize = 0, |
1256 | .ppb_shift = 7, | ||
1257 | }; | ||
1258 | |||
1259 | /* v3.2b: i.MX53 */ | ||
1260 | static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { | ||
1261 | .preset = preset_v3, | ||
1262 | .send_cmd = send_cmd_v3, | ||
1263 | .send_addr = send_addr_v3, | ||
1264 | .send_page = send_page_v3, | ||
1265 | .send_read_id = send_read_id_v3, | ||
1266 | .get_dev_status = get_dev_status_v3, | ||
1267 | .check_int = check_int_v3, | ||
1268 | .irq_control = irq_control_v3, | ||
1269 | .get_ecc_status = get_ecc_status_v3, | ||
1270 | .ecclayout_512 = &nandv2_hw_eccoob_smallpage, | ||
1271 | .ecclayout_2k = &nandv2_hw_eccoob_largepage, | ||
1272 | .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */ | ||
1273 | .select_chip = mxc_nand_select_chip_v1_v3, | ||
1274 | .correct_data = mxc_nand_correct_data_v2_v3, | ||
1275 | .irqpending_quirk = 0, | ||
1276 | .needs_ip = 1, | ||
1277 | .regs_offset = 0, | ||
1278 | .spare0_offset = 0x1000, | ||
1279 | .axi_offset = 0x1e00, | ||
1280 | .spare_len = 64, | ||
1281 | .eccbytes = 0, | ||
1282 | .eccsize = 0, | ||
1283 | .ppb_shift = 8, | ||
1261 | }; | 1284 | }; |
1262 | 1285 | ||
1263 | #ifdef CONFIG_OF_MTD | 1286 | #ifdef CONFIG_OF_MTD |
@@ -1274,6 +1297,9 @@ static const struct of_device_id mxcnd_dt_ids[] = { | |||
1274 | }, { | 1297 | }, { |
1275 | .compatible = "fsl,imx51-nand", | 1298 | .compatible = "fsl,imx51-nand", |
1276 | .data = &imx51_nand_devtype_data, | 1299 | .data = &imx51_nand_devtype_data, |
1300 | }, { | ||
1301 | .compatible = "fsl,imx53-nand", | ||
1302 | .data = &imx53_nand_devtype_data, | ||
1277 | }, | 1303 | }, |
1278 | { /* sentinel */ } | 1304 | { /* sentinel */ } |
1279 | }; | 1305 | }; |
@@ -1327,15 +1353,17 @@ static int __init mxcnd_probe_pdata(struct mxc_nand_host *host) | |||
1327 | host->devtype_data = &imx27_nand_devtype_data; | 1353 | host->devtype_data = &imx27_nand_devtype_data; |
1328 | } else if (nfc_is_v21()) { | 1354 | } else if (nfc_is_v21()) { |
1329 | host->devtype_data = &imx25_nand_devtype_data; | 1355 | host->devtype_data = &imx25_nand_devtype_data; |
1330 | } else if (nfc_is_v3_2()) { | 1356 | } else if (nfc_is_v3_2a()) { |
1331 | host->devtype_data = &imx51_nand_devtype_data; | 1357 | host->devtype_data = &imx51_nand_devtype_data; |
1358 | } else if (nfc_is_v3_2b()) { | ||
1359 | host->devtype_data = &imx53_nand_devtype_data; | ||
1332 | } else | 1360 | } else |
1333 | BUG(); | 1361 | BUG(); |
1334 | 1362 | ||
1335 | return 0; | 1363 | return 0; |
1336 | } | 1364 | } |
1337 | 1365 | ||
1338 | static int __init mxcnd_probe(struct platform_device *pdev) | 1366 | static int __devinit mxcnd_probe(struct platform_device *pdev) |
1339 | { | 1367 | { |
1340 | struct nand_chip *this; | 1368 | struct nand_chip *this; |
1341 | struct mtd_info *mtd; | 1369 | struct mtd_info *mtd; |
@@ -1344,8 +1372,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1344 | int err = 0; | 1372 | int err = 0; |
1345 | 1373 | ||
1346 | /* Allocate memory for MTD device structure and private data */ | 1374 | /* Allocate memory for MTD device structure and private data */ |
1347 | host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + | 1375 | host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) + |
1348 | NAND_MAX_OOBSIZE, GFP_KERNEL); | 1376 | NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL); |
1349 | if (!host) | 1377 | if (!host) |
1350 | return -ENOMEM; | 1378 | return -ENOMEM; |
1351 | 1379 | ||
@@ -1370,36 +1398,38 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1370 | this->read_word = mxc_nand_read_word; | 1398 | this->read_word = mxc_nand_read_word; |
1371 | this->write_buf = mxc_nand_write_buf; | 1399 | this->write_buf = mxc_nand_write_buf; |
1372 | this->read_buf = mxc_nand_read_buf; | 1400 | this->read_buf = mxc_nand_read_buf; |
1373 | this->verify_buf = mxc_nand_verify_buf; | ||
1374 | 1401 | ||
1375 | host->clk = clk_get(&pdev->dev, "nfc"); | 1402 | host->clk = devm_clk_get(&pdev->dev, NULL); |
1376 | if (IS_ERR(host->clk)) { | 1403 | if (IS_ERR(host->clk)) |
1377 | err = PTR_ERR(host->clk); | 1404 | return PTR_ERR(host->clk); |
1378 | goto eclk; | ||
1379 | } | ||
1380 | 1405 | ||
1381 | clk_prepare_enable(host->clk); | 1406 | err = mxcnd_probe_dt(host); |
1382 | host->clk_act = 1; | 1407 | if (err > 0) |
1408 | err = mxcnd_probe_pdata(host); | ||
1409 | if (err < 0) | ||
1410 | return err; | ||
1383 | 1411 | ||
1384 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1412 | if (host->devtype_data->needs_ip) { |
1385 | if (!res) { | 1413 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1386 | err = -ENODEV; | 1414 | if (!res) |
1387 | goto eres; | 1415 | return -ENODEV; |
1388 | } | 1416 | host->regs_ip = devm_request_and_ioremap(&pdev->dev, res); |
1417 | if (!host->regs_ip) | ||
1418 | return -ENOMEM; | ||
1389 | 1419 | ||
1390 | host->base = ioremap(res->start, resource_size(res)); | 1420 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
1391 | if (!host->base) { | 1421 | } else { |
1392 | err = -ENOMEM; | 1422 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1393 | goto eres; | ||
1394 | } | 1423 | } |
1395 | 1424 | ||
1396 | host->main_area0 = host->base; | 1425 | if (!res) |
1426 | return -ENODEV; | ||
1397 | 1427 | ||
1398 | err = mxcnd_probe_dt(host); | 1428 | host->base = devm_request_and_ioremap(&pdev->dev, res); |
1399 | if (err > 0) | 1429 | if (!host->base) |
1400 | err = mxcnd_probe_pdata(host); | 1430 | return -ENOMEM; |
1401 | if (err < 0) | 1431 | |
1402 | goto eirq; | 1432 | host->main_area0 = host->base; |
1403 | 1433 | ||
1404 | if (host->devtype_data->regs_offset) | 1434 | if (host->devtype_data->regs_offset) |
1405 | host->regs = host->base + host->devtype_data->regs_offset; | 1435 | host->regs = host->base + host->devtype_data->regs_offset; |
@@ -1414,19 +1444,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1414 | this->ecc.size = 512; | 1444 | this->ecc.size = 512; |
1415 | this->ecc.layout = host->devtype_data->ecclayout_512; | 1445 | this->ecc.layout = host->devtype_data->ecclayout_512; |
1416 | 1446 | ||
1417 | if (host->devtype_data->needs_ip) { | ||
1418 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
1419 | if (!res) { | ||
1420 | err = -ENODEV; | ||
1421 | goto eirq; | ||
1422 | } | ||
1423 | host->regs_ip = ioremap(res->start, resource_size(res)); | ||
1424 | if (!host->regs_ip) { | ||
1425 | err = -ENOMEM; | ||
1426 | goto eirq; | ||
1427 | } | ||
1428 | } | ||
1429 | |||
1430 | if (host->pdata.hw_ecc) { | 1447 | if (host->pdata.hw_ecc) { |
1431 | this->ecc.calculate = mxc_nand_calculate_ecc; | 1448 | this->ecc.calculate = mxc_nand_calculate_ecc; |
1432 | this->ecc.hwctl = mxc_nand_enable_hwecc; | 1449 | this->ecc.hwctl = mxc_nand_enable_hwecc; |
@@ -1458,9 +1475,13 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1458 | */ | 1475 | */ |
1459 | host->devtype_data->irq_control(host, 0); | 1476 | host->devtype_data->irq_control(host, 0); |
1460 | 1477 | ||
1461 | err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); | 1478 | err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq, |
1479 | IRQF_DISABLED, DRIVER_NAME, host); | ||
1462 | if (err) | 1480 | if (err) |
1463 | goto eirq; | 1481 | return err; |
1482 | |||
1483 | clk_prepare_enable(host->clk); | ||
1484 | host->clk_act = 1; | ||
1464 | 1485 | ||
1465 | /* | 1486 | /* |
1466 | * Now that we "own" the interrupt make sure the interrupt mask bit is | 1487 | * Now that we "own" the interrupt make sure the interrupt mask bit is |
@@ -1512,15 +1533,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1512 | return 0; | 1533 | return 0; |
1513 | 1534 | ||
1514 | escan: | 1535 | escan: |
1515 | free_irq(host->irq, host); | 1536 | clk_disable_unprepare(host->clk); |
1516 | eirq: | ||
1517 | if (host->regs_ip) | ||
1518 | iounmap(host->regs_ip); | ||
1519 | iounmap(host->base); | ||
1520 | eres: | ||
1521 | clk_put(host->clk); | ||
1522 | eclk: | ||
1523 | kfree(host); | ||
1524 | 1537 | ||
1525 | return err; | 1538 | return err; |
1526 | } | 1539 | } |
@@ -1529,16 +1542,9 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) | |||
1529 | { | 1542 | { |
1530 | struct mxc_nand_host *host = platform_get_drvdata(pdev); | 1543 | struct mxc_nand_host *host = platform_get_drvdata(pdev); |
1531 | 1544 | ||
1532 | clk_put(host->clk); | ||
1533 | |||
1534 | platform_set_drvdata(pdev, NULL); | 1545 | platform_set_drvdata(pdev, NULL); |
1535 | 1546 | ||
1536 | nand_release(&host->mtd); | 1547 | nand_release(&host->mtd); |
1537 | free_irq(host->irq, host); | ||
1538 | if (host->regs_ip) | ||
1539 | iounmap(host->regs_ip); | ||
1540 | iounmap(host->base); | ||
1541 | kfree(host); | ||
1542 | 1548 | ||
1543 | return 0; | 1549 | return 0; |
1544 | } | 1550 | } |
@@ -1549,22 +1555,10 @@ static struct platform_driver mxcnd_driver = { | |||
1549 | .owner = THIS_MODULE, | 1555 | .owner = THIS_MODULE, |
1550 | .of_match_table = of_match_ptr(mxcnd_dt_ids), | 1556 | .of_match_table = of_match_ptr(mxcnd_dt_ids), |
1551 | }, | 1557 | }, |
1558 | .probe = mxcnd_probe, | ||
1552 | .remove = __devexit_p(mxcnd_remove), | 1559 | .remove = __devexit_p(mxcnd_remove), |
1553 | }; | 1560 | }; |
1554 | 1561 | module_platform_driver(mxcnd_driver); | |
1555 | static int __init mxc_nd_init(void) | ||
1556 | { | ||
1557 | return platform_driver_probe(&mxcnd_driver, mxcnd_probe); | ||
1558 | } | ||
1559 | |||
1560 | static void __exit mxc_nd_cleanup(void) | ||
1561 | { | ||
1562 | /* Unregister the device structure */ | ||
1563 | platform_driver_unregister(&mxcnd_driver); | ||
1564 | } | ||
1565 | |||
1566 | module_init(mxc_nd_init); | ||
1567 | module_exit(mxc_nd_cleanup); | ||
1568 | 1562 | ||
1569 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | 1563 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); |
1570 | MODULE_DESCRIPTION("MXC NAND MTD driver"); | 1564 | MODULE_DESCRIPTION("MXC NAND MTD driver"); |