diff options
author | Huang Shijie <b32955@freescale.com> | 2012-05-04 21:42:05 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-05-14 00:22:19 -0400 |
commit | e10db1f00a5e3c2ec04d7fe26c7444dc55a59b19 (patch) | |
tree | 4e92b7759d1a7ab888fa4ed39c81d44a00b89fa1 | |
parent | 279f08d4ef6548be4e2fa638245adebc77436e54 (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.txt | 33 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 126 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 | ||||
-rw-r--r-- | include/linux/mtd/gpmi-nand.h | 8 |
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 | |||
3 | The GPMI nand controller provides an interface to control the | ||
4 | NAND flash chips. We support only one NAND chip now. | ||
5 | |||
6 | Required 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 | |||
15 | The device tree may optionally contain sub-nodes describing partitions of the | ||
16 | address space. See partition.txt for more detail. | ||
17 | |||
18 | Examples: | ||
19 | |||
20 | gpmi-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. */ |
260 | static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, | 262 | static 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) | |||
386 | static bool gpmi_dma_filter(struct dma_chan *chan, void *param) | 388 | static 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) | |||
418 | static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) | 420 | static 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 | ||
470 | acquire_err: | 461 | acquire_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 | ||
1466 | static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) | 1456 | static 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 | ||
1515 | static 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 | |||
1521 | static 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 | }; | ||
1530 | MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); | ||
1531 | |||
1525 | static int __devinit gpmi_nand_probe(struct platform_device *pdev) | 1532 | static 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 | ||
1562 | exit_nfc_init: | 1570 | exit_nfc_init: |
1563 | release_resources(this); | 1571 | release_resources(this); |
1564 | platform_init_error: | ||
1565 | exit_acquire_resources: | 1572 | exit_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 | ||
1582 | static 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 | |||
1592 | static struct platform_driver gpmi_nand_driver = { | 1589 | static 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. |