aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/mxc_nand.c
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2012-04-23 05:23:41 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-05-14 00:03:08 -0400
commit6436356ba156b909c34a72e2905d9a9a874ca8e1 (patch)
tree7c19d41ca3c8695b7d950abe13c432bbeee7803c /drivers/mtd/nand/mxc_nand.c
parentf48d0f9aa93c8f1d38f21d2531d572cf96205d58 (diff)
mtd: mxc_nand: implement device tree probing
This is tested on i.MX27. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand/mxc_nand.c')
-rw-r--r--drivers/mtd/nand/mxc_nand.c114
1 files changed, 95 insertions, 19 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 35c928ac1901..1041bb134628 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -32,6 +32,8 @@
32#include <linux/io.h> 32#include <linux/io.h>
33#include <linux/irq.h> 33#include <linux/irq.h>
34#include <linux/completion.h> 34#include <linux/completion.h>
35#include <linux/of_device.h>
36#include <linux/of_mtd.h>
35 37
36#include <asm/mach/flash.h> 38#include <asm/mach/flash.h>
37#include <mach/mxc_nand.h> 39#include <mach/mxc_nand.h>
@@ -199,6 +201,7 @@ struct mxc_nand_host {
199 unsigned int buf_start; 201 unsigned int buf_start;
200 202
201 const struct mxc_nand_devtype_data *devtype_data; 203 const struct mxc_nand_devtype_data *devtype_data;
204 struct mxc_nand_platform_data pdata;
202}; 205};
203 206
204/* OOB placement block for use with hardware ecc generation */ 207/* OOB placement block for use with hardware ecc generation */
@@ -268,7 +271,7 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
268 } 271 }
269}; 272};
270 273
271static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; 274static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL };
272 275
273static int check_int_v3(struct mxc_nand_host *host) 276static int check_int_v3(struct mxc_nand_host *host)
274{ 277{
@@ -1236,11 +1239,85 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
1236 .eccsize = 0, 1239 .eccsize = 0,
1237}; 1240};
1238 1241
1242#ifdef CONFIG_OF_MTD
1243static const struct of_device_id mxcnd_dt_ids[] = {
1244 {
1245 .compatible = "fsl,imx21-nand",
1246 .data = &imx21_nand_devtype_data,
1247 }, {
1248 .compatible = "fsl,imx27-nand",
1249 .data = &imx27_nand_devtype_data,
1250 }, {
1251 .compatible = "fsl,imx25-nand",
1252 .data = &imx25_nand_devtype_data,
1253 }, {
1254 .compatible = "fsl,imx51-nand",
1255 .data = &imx51_nand_devtype_data,
1256 },
1257 { /* sentinel */ }
1258};
1259
1260static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
1261{
1262 struct device_node *np = host->dev->of_node;
1263 struct mxc_nand_platform_data *pdata = &host->pdata;
1264 const struct of_device_id *of_id =
1265 of_match_device(mxcnd_dt_ids, host->dev);
1266 int buswidth;
1267
1268 if (!np)
1269 return 1;
1270
1271 if (of_get_nand_ecc_mode(np) >= 0)
1272 pdata->hw_ecc = 1;
1273
1274 pdata->flash_bbt = of_get_nand_on_flash_bbt(np);
1275
1276 buswidth = of_get_nand_bus_width(np);
1277 if (buswidth < 0)
1278 return buswidth;
1279
1280 pdata->width = buswidth / 8;
1281
1282 host->devtype_data = of_id->data;
1283
1284 return 0;
1285}
1286#else
1287static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
1288{
1289 return 1;
1290}
1291#endif
1292
1293static int __init mxcnd_probe_pdata(struct mxc_nand_host *host)
1294{
1295 struct mxc_nand_platform_data *pdata = host->dev->platform_data;
1296
1297 if (!pdata)
1298 return -ENODEV;
1299
1300 host->pdata = *pdata;
1301
1302 if (nfc_is_v1()) {
1303 if (cpu_is_mx21())
1304 host->devtype_data = &imx21_nand_devtype_data;
1305 else
1306 host->devtype_data = &imx27_nand_devtype_data;
1307 } else if (nfc_is_v21()) {
1308 host->devtype_data = &imx25_nand_devtype_data;
1309 } else if (nfc_is_v3_2()) {
1310 host->devtype_data = &imx51_nand_devtype_data;
1311 } else
1312 BUG();
1313
1314 return 0;
1315}
1316
1239static int __init mxcnd_probe(struct platform_device *pdev) 1317static int __init mxcnd_probe(struct platform_device *pdev)
1240{ 1318{
1241 struct nand_chip *this; 1319 struct nand_chip *this;
1242 struct mtd_info *mtd; 1320 struct mtd_info *mtd;
1243 struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
1244 struct mxc_nand_host *host; 1321 struct mxc_nand_host *host;
1245 struct resource *res; 1322 struct resource *res;
1246 int err = 0; 1323 int err = 0;
@@ -1297,17 +1374,11 @@ static int __init mxcnd_probe(struct platform_device *pdev)
1297 1374
1298 host->main_area0 = host->base; 1375 host->main_area0 = host->base;
1299 1376
1300 if (nfc_is_v1()) { 1377 err = mxcnd_probe_dt(host);
1301 if (cpu_is_mx21()) 1378 if (err > 0)
1302 host->devtype_data = &imx21_nand_devtype_data; 1379 err = mxcnd_probe_pdata(host);
1303 else 1380 if (err < 0)
1304 host->devtype_data = &imx27_nand_devtype_data; 1381 goto eirq;
1305 } else if (nfc_is_v21()) {
1306 host->devtype_data = &imx25_nand_devtype_data;
1307 } else if (nfc_is_v3_2()) {
1308 host->devtype_data = &imx51_nand_devtype_data;
1309 } else
1310 BUG();
1311 1382
1312 if (host->devtype_data->regs_offset) 1383 if (host->devtype_data->regs_offset)
1313 host->regs = host->base + host->devtype_data->regs_offset; 1384 host->regs = host->base + host->devtype_data->regs_offset;
@@ -1335,7 +1406,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
1335 } 1406 }
1336 } 1407 }
1337 1408
1338 if (pdata->hw_ecc) { 1409 if (host->pdata.hw_ecc) {
1339 this->ecc.calculate = mxc_nand_calculate_ecc; 1410 this->ecc.calculate = mxc_nand_calculate_ecc;
1340 this->ecc.hwctl = mxc_nand_enable_hwecc; 1411 this->ecc.hwctl = mxc_nand_enable_hwecc;
1341 this->ecc.correct = host->devtype_data->correct_data; 1412 this->ecc.correct = host->devtype_data->correct_data;
@@ -1344,11 +1415,11 @@ static int __init mxcnd_probe(struct platform_device *pdev)
1344 this->ecc.mode = NAND_ECC_SOFT; 1415 this->ecc.mode = NAND_ECC_SOFT;
1345 } 1416 }
1346 1417
1347 /* NAND bus width determines access funtions used by upper layer */ 1418 /* NAND bus width determines access functions used by upper layer */
1348 if (pdata->width == 2) 1419 if (host->pdata.width == 2)
1349 this->options |= NAND_BUSWIDTH_16; 1420 this->options |= NAND_BUSWIDTH_16;
1350 1421
1351 if (pdata->flash_bbt) { 1422 if (host->pdata.flash_bbt) {
1352 this->bbt_td = &bbt_main_descr; 1423 this->bbt_td = &bbt_main_descr;
1353 this->bbt_md = &bbt_mirror_descr; 1424 this->bbt_md = &bbt_mirror_descr;
1354 /* update flash based bbt */ 1425 /* update flash based bbt */
@@ -1408,8 +1479,12 @@ static int __init mxcnd_probe(struct platform_device *pdev)
1408 } 1479 }
1409 1480
1410 /* Register the partitions */ 1481 /* Register the partitions */
1411 mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts, 1482 mtd_device_parse_register(mtd, part_probes,
1412 pdata->nr_parts); 1483 &(struct mtd_part_parser_data){
1484 .of_node = pdev->dev.of_node,
1485 },
1486 host->pdata.parts,
1487 host->pdata.nr_parts);
1413 1488
1414 platform_set_drvdata(pdev, host); 1489 platform_set_drvdata(pdev, host);
1415 1490
@@ -1451,6 +1526,7 @@ static struct platform_driver mxcnd_driver = {
1451 .driver = { 1526 .driver = {
1452 .name = DRIVER_NAME, 1527 .name = DRIVER_NAME,
1453 .owner = THIS_MODULE, 1528 .owner = THIS_MODULE,
1529 .of_match_table = of_match_ptr(mxcnd_dt_ids),
1454 }, 1530 },
1455 .remove = __devexit_p(mxcnd_remove), 1531 .remove = __devexit_p(mxcnd_remove),
1456}; 1532};