diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2012-04-23 05:23:41 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-05-14 00:03:08 -0400 |
commit | 6436356ba156b909c34a72e2905d9a9a874ca8e1 (patch) | |
tree | 7c19d41ca3c8695b7d950abe13c432bbeee7803c /drivers/mtd/nand/mxc_nand.c | |
parent | f48d0f9aa93c8f1d38f21d2531d572cf96205d58 (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.c | 114 |
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 | ||
271 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; | 274 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL }; |
272 | 275 | ||
273 | static int check_int_v3(struct mxc_nand_host *host) | 276 | static 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 | ||
1243 | static 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 | |||
1260 | static 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 | ||
1287 | static int __init mxcnd_probe_dt(struct mxc_nand_host *host) | ||
1288 | { | ||
1289 | return 1; | ||
1290 | } | ||
1291 | #endif | ||
1292 | |||
1293 | static 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 | |||
1239 | static int __init mxcnd_probe(struct platform_device *pdev) | 1317 | static 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 | }; |