aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Shijie <b32955@freescale.com>2012-05-04 21:42:05 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-05-14 00:22:19 -0400
commite10db1f00a5e3c2ec04d7fe26c7444dc55a59b19 (patch)
tree4e92b7759d1a7ab888fa4ed39c81d44a00b89fa1
parent279f08d4ef6548be4e2fa638245adebc77436e54 (diff)
mtd: gpmi: add device tree support to gpmi-nand
This patch just adds the DT support to gpmi-nand. Signed-off-by: Huang Shijie <b32955@freescale.com> Signed-off-by: Huang Shijie <shijie8@gmail.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--Documentation/devicetree/bindings/mtd/gpmi-nand.txt33
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-lib.c7
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c126
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.h4
-rw-r--r--include/linux/mtd/gpmi-nand.h8
5 files changed, 105 insertions, 73 deletions
diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt
new file mode 100644
index 000000000000..1a5bbd346d22
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt
@@ -0,0 +1,33 @@
1* Freescale General-Purpose Media Interface (GPMI)
2
3The GPMI nand controller provides an interface to control the
4NAND flash chips. We support only one NAND chip now.
5
6Required properties:
7 - compatible : should be "fsl,<chip>-gpmi-nand"
8 - reg : should contain registers location and length for gpmi and bch.
9 - reg-names: Should contain the reg names "gpmi-nand" and "bch"
10 - interrupts : The first is the DMA interrupt number for GPMI.
11 The second is the BCH interrupt number.
12 - interrupt-names : The interrupt names "gpmi-dma", "bch";
13 - fsl,gpmi-dma-channel : Should contain the dma channel it uses.
14
15The device tree may optionally contain sub-nodes describing partitions of the
16address space. See partition.txt for more detail.
17
18Examples:
19
20gpmi-nand@8000c000 {
21 compatible = "fsl,imx28-gpmi-nand";
22 #address-cells = <1>;
23 #size-cells = <1>;
24 reg = <0x8000c000 2000>, <0x8000a000 2000>;
25 reg-names = "gpmi-nand", "bch";
26 interrupts = <88>, <41>;
27 interrupt-names = "gpmi-dma", "bch";
28 fsl,gpmi-dma-channel = <4>;
29
30 partition@0 {
31 ...
32 };
33};
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index fa5200b8c895..5c55c717fe14 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -256,11 +256,12 @@ static unsigned int ns_to_cycles(unsigned int time,
256 return max(k, min); 256 return max(k, min);
257} 257}
258 258
259#define DEF_MIN_PROP_DELAY 5
260#define DEF_MAX_PROP_DELAY 9
259/* Apply timing to current hardware conditions. */ 261/* Apply timing to current hardware conditions. */
260static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, 262static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
261 struct gpmi_nfc_hardware_timing *hw) 263 struct gpmi_nfc_hardware_timing *hw)
262{ 264{
263 struct gpmi_nand_platform_data *pdata = this->pdata;
264 struct timing_threshod *nfc = &timing_default_threshold; 265 struct timing_threshod *nfc = &timing_default_threshold;
265 struct nand_chip *nand = &this->nand; 266 struct nand_chip *nand = &this->nand;
266 struct nand_timing target = this->timing; 267 struct nand_timing target = this->timing;
@@ -277,8 +278,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
277 int ideal_sample_delay_in_ns; 278 int ideal_sample_delay_in_ns;
278 unsigned int sample_delay_factor; 279 unsigned int sample_delay_factor;
279 int tEYE; 280 int tEYE;
280 unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns; 281 unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
281 unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns; 282 unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
282 283
283 /* 284 /*
284 * If there are multiple chips, we need to relax the timings to allow 285 * If there are multiple chips, we need to relax the timings to allow
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 7e8a035d444a..d9dc4c874ffa 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -24,6 +24,8 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/mtd/gpmi-nand.h> 25#include <linux/mtd/gpmi-nand.h>
26#include <linux/mtd/partitions.h> 26#include <linux/mtd/partitions.h>
27#include <linux/of.h>
28#include <linux/of_device.h>
27#include "gpmi-nand.h" 29#include "gpmi-nand.h"
28 30
29/* add our owner bbt descriptor */ 31/* add our owner bbt descriptor */
@@ -386,7 +388,7 @@ static void release_bch_irq(struct gpmi_nand_data *this)
386static bool gpmi_dma_filter(struct dma_chan *chan, void *param) 388static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
387{ 389{
388 struct gpmi_nand_data *this = param; 390 struct gpmi_nand_data *this = param;
389 struct resource *r = this->private; 391 int dma_channel = (int)this->private;
390 392
391 if (!mxs_dma_is_apbh(chan)) 393 if (!mxs_dma_is_apbh(chan))
392 return false; 394 return false;
@@ -398,7 +400,7 @@ static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
398 * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 400 * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7
399 * (These eight channels share the same IRQ!) 401 * (These eight channels share the same IRQ!)
400 */ 402 */
401 if (r->start <= chan->chan_id && chan->chan_id <= r->end) { 403 if (dma_channel == chan->chan_id) {
402 chan->private = &this->dma_data; 404 chan->private = &this->dma_data;
403 return true; 405 return true;
404 } 406 }
@@ -418,57 +420,45 @@ static void release_dma_channels(struct gpmi_nand_data *this)
418static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) 420static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
419{ 421{
420 struct platform_device *pdev = this->pdev; 422 struct platform_device *pdev = this->pdev;
421 struct gpmi_nand_platform_data *pdata = this->pdata; 423 struct resource *r_dma;
422 struct resources *res = &this->resources; 424 struct device_node *dn;
423 struct resource *r, *r_dma; 425 int dma_channel;
424 unsigned int i; 426 unsigned int ret;
427 struct dma_chan *dma_chan;
428 dma_cap_mask_t mask;
429
430 /* dma channel, we only use the first one. */
431 dn = pdev->dev.of_node;
432 ret = of_property_read_u32(dn, "fsl,gpmi-dma-channel", &dma_channel);
433 if (ret) {
434 pr_err("unable to get DMA channel from dt.\n");
435 goto acquire_err;
436 }
437 this->private = (void *)dma_channel;
425 438
426 r = platform_get_resource_byname(pdev, IORESOURCE_DMA, 439 /* gpmi dma interrupt */
427 GPMI_NAND_DMA_CHANNELS_RES_NAME);
428 r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 440 r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
429 GPMI_NAND_DMA_INTERRUPT_RES_NAME); 441 GPMI_NAND_DMA_INTERRUPT_RES_NAME);
430 if (!r || !r_dma) { 442 if (!r_dma) {
431 pr_err("Can't get resource for DMA\n"); 443 pr_err("Can't get resource for DMA\n");
432 return -ENXIO; 444 goto acquire_err;
433 } 445 }
446 this->dma_data.chan_irq = r_dma->start;
434 447
435 /* used in gpmi_dma_filter() */ 448 /* request dma channel */
436 this->private = r; 449 dma_cap_zero(mask);
437 450 dma_cap_set(DMA_SLAVE, mask);
438 for (i = r->start; i <= r->end; i++) {
439 struct dma_chan *dma_chan;
440 dma_cap_mask_t mask;
441 451
442 if (i - r->start >= pdata->max_chip_count) 452 dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
443 break; 453 if (!dma_chan) {
444 454 pr_err("dma_request_channel failed.\n");
445 dma_cap_zero(mask); 455 goto acquire_err;
446 dma_cap_set(DMA_SLAVE, mask);
447
448 /* get the DMA interrupt */
449 if (r_dma->start == r_dma->end) {
450 /* only register the first. */
451 if (i == r->start)
452 this->dma_data.chan_irq = r_dma->start;
453 else
454 this->dma_data.chan_irq = NO_IRQ;
455 } else
456 this->dma_data.chan_irq = r_dma->start + (i - r->start);
457
458 dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
459 if (!dma_chan)
460 goto acquire_err;
461
462 /* fill the first empty item */
463 this->dma_chans[i - r->start] = dma_chan;
464 } 456 }
465 457
466 res->dma_low_channel = r->start; 458 this->dma_chans[0] = dma_chan;
467 res->dma_high_channel = i;
468 return 0; 459 return 0;
469 460
470acquire_err: 461acquire_err:
471 pr_err("Can't acquire DMA channel %u\n", i);
472 release_dma_channels(this); 462 release_dma_channels(this);
473 return -EINVAL; 463 return -EINVAL;
474} 464}
@@ -1465,9 +1455,9 @@ void gpmi_nfc_exit(struct gpmi_nand_data *this)
1465 1455
1466static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) 1456static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
1467{ 1457{
1468 struct gpmi_nand_platform_data *pdata = this->pdata;
1469 struct mtd_info *mtd = &this->mtd; 1458 struct mtd_info *mtd = &this->mtd;
1470 struct nand_chip *chip = &this->nand; 1459 struct nand_chip *chip = &this->nand;
1460 struct mtd_part_parser_data ppdata = {};
1471 int ret; 1461 int ret;
1472 1462
1473 /* init current chip */ 1463 /* init current chip */
@@ -1505,14 +1495,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
1505 if (ret) 1495 if (ret)
1506 goto err_out; 1496 goto err_out;
1507 1497
1508 ret = nand_scan(mtd, pdata->max_chip_count); 1498 ret = nand_scan(mtd, 1);
1509 if (ret) { 1499 if (ret) {
1510 pr_err("Chip scan failed\n"); 1500 pr_err("Chip scan failed\n");
1511 goto err_out; 1501 goto err_out;
1512 } 1502 }
1513 1503
1514 ret = mtd_device_parse_register(mtd, NULL, NULL, 1504 ppdata.of_node = this->pdev->dev.of_node;
1515 pdata->partitions, pdata->partition_count); 1505 ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
1516 if (ret) 1506 if (ret)
1517 goto err_out; 1507 goto err_out;
1518 return 0; 1508 return 0;
@@ -1522,12 +1512,37 @@ err_out:
1522 return ret; 1512 return ret;
1523} 1513}
1524 1514
1515static const struct platform_device_id gpmi_ids[] = {
1516 { .name = "imx23-gpmi-nand", .driver_data = IS_MX23, },
1517 { .name = "imx28-gpmi-nand", .driver_data = IS_MX28, },
1518 {},
1519};
1520
1521static const struct of_device_id gpmi_nand_id_table[] = {
1522 {
1523 .compatible = "fsl,imx23-gpmi-nand",
1524 .data = (void *)&gpmi_ids[IS_MX23]
1525 }, {
1526 .compatible = "fsl,imx28-gpmi-nand",
1527 .data = (void *)&gpmi_ids[IS_MX28]
1528 }, {}
1529};
1530MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
1531
1525static int __devinit gpmi_nand_probe(struct platform_device *pdev) 1532static int __devinit gpmi_nand_probe(struct platform_device *pdev)
1526{ 1533{
1527 struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data;
1528 struct gpmi_nand_data *this; 1534 struct gpmi_nand_data *this;
1535 const struct of_device_id *of_id;
1529 int ret; 1536 int ret;
1530 1537
1538 of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
1539 if (of_id) {
1540 pdev->id_entry = of_id->data;
1541 } else {
1542 pr_err("Failed to find the right device id.\n");
1543 return -ENOMEM;
1544 }
1545
1531 this = kzalloc(sizeof(*this), GFP_KERNEL); 1546 this = kzalloc(sizeof(*this), GFP_KERNEL);
1532 if (!this) { 1547 if (!this) {
1533 pr_err("Failed to allocate per-device memory\n"); 1548 pr_err("Failed to allocate per-device memory\n");
@@ -1537,13 +1552,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
1537 platform_set_drvdata(pdev, this); 1552 platform_set_drvdata(pdev, this);
1538 this->pdev = pdev; 1553 this->pdev = pdev;
1539 this->dev = &pdev->dev; 1554 this->dev = &pdev->dev;
1540 this->pdata = pdata;
1541
1542 if (pdata->platform_init) {
1543 ret = pdata->platform_init();
1544 if (ret)
1545 goto platform_init_error;
1546 }
1547 1555
1548 ret = acquire_resources(this); 1556 ret = acquire_resources(this);
1549 if (ret) 1557 if (ret)
@@ -1561,7 +1569,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
1561 1569
1562exit_nfc_init: 1570exit_nfc_init:
1563 release_resources(this); 1571 release_resources(this);
1564platform_init_error:
1565exit_acquire_resources: 1572exit_acquire_resources:
1566 platform_set_drvdata(pdev, NULL); 1573 platform_set_drvdata(pdev, NULL);
1567 kfree(this); 1574 kfree(this);
@@ -1579,19 +1586,10 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev)
1579 return 0; 1586 return 0;
1580} 1587}
1581 1588
1582static const struct platform_device_id gpmi_ids[] = {
1583 {
1584 .name = "imx23-gpmi-nand",
1585 .driver_data = IS_MX23,
1586 }, {
1587 .name = "imx28-gpmi-nand",
1588 .driver_data = IS_MX28,
1589 }, {},
1590};
1591
1592static struct platform_driver gpmi_nand_driver = { 1589static struct platform_driver gpmi_nand_driver = {
1593 .driver = { 1590 .driver = {
1594 .name = "gpmi-nand", 1591 .name = "gpmi-nand",
1592 .of_match_table = gpmi_nand_id_table,
1595 }, 1593 },
1596 .probe = gpmi_nand_probe, 1594 .probe = gpmi_nand_probe,
1597 .remove = __exit_p(gpmi_nand_remove), 1595 .remove = __exit_p(gpmi_nand_remove),
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index ec6180d4ff8f..12fdd7767c1c 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -266,8 +266,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *,
266#define STATUS_UNCORRECTABLE 0xfe 266#define STATUS_UNCORRECTABLE 0xfe
267 267
268/* Use the platform_id to distinguish different Archs. */ 268/* Use the platform_id to distinguish different Archs. */
269#define IS_MX23 0x1 269#define IS_MX23 0x0
270#define IS_MX28 0x2 270#define IS_MX28 0x1
271#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) 271#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23)
272#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) 272#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28)
273#endif 273#endif
diff --git a/include/linux/mtd/gpmi-nand.h b/include/linux/mtd/gpmi-nand.h
index 69b6dbf46b5e..ed3c4e09f3d1 100644
--- a/include/linux/mtd/gpmi-nand.h
+++ b/include/linux/mtd/gpmi-nand.h
@@ -23,12 +23,12 @@
23#define GPMI_NAND_RES_SIZE 6 23#define GPMI_NAND_RES_SIZE 6
24 24
25/* Resource names for the GPMI NAND driver. */ 25/* Resource names for the GPMI NAND driver. */
26#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "GPMI NAND GPMI Registers" 26#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand"
27#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt" 27#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt"
28#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "GPMI NAND BCH Registers" 28#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch"
29#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "GPMI NAND BCH Interrupt" 29#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch"
30#define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels" 30#define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels"
31#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "GPMI NAND DMA Interrupt" 31#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma"
32 32
33/** 33/**
34 * struct gpmi_nand_platform_data - GPMI NAND driver platform data. 34 * struct gpmi_nand_platform_data - GPMI NAND driver platform data.