|
@@ -24,6 +24,8 @@
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/mtd/gpmi-nand.h>
|
|
|
#include <linux/mtd/partitions.h>
|
|
|
+#include <linux/of.h>
|
|
|
+#include <linux/of_device.h>
|
|
|
#include "gpmi-nand.h"
|
|
|
|
|
|
/* add our owner bbt descriptor */
|
|
@@ -386,7 +388,7 @@ static void release_bch_irq(struct gpmi_nand_data *this)
|
|
|
static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
|
|
|
{
|
|
|
struct gpmi_nand_data *this = param;
|
|
|
- struct resource *r = this->private;
|
|
|
+ int dma_channel = (int)this->private;
|
|
|
|
|
|
if (!mxs_dma_is_apbh(chan))
|
|
|
return false;
|
|
@@ -398,7 +400,7 @@ static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
|
|
|
* for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7
|
|
|
* (These eight channels share the same IRQ!)
|
|
|
*/
|
|
|
- if (r->start <= chan->chan_id && chan->chan_id <= r->end) {
|
|
|
+ if (dma_channel == chan->chan_id) {
|
|
|
chan->private = &this->dma_data;
|
|
|
return true;
|
|
|
}
|
|
@@ -418,57 +420,45 @@ static void release_dma_channels(struct gpmi_nand_data *this)
|
|
|
static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
|
|
|
{
|
|
|
struct platform_device *pdev = this->pdev;
|
|
|
- struct gpmi_nand_platform_data *pdata = this->pdata;
|
|
|
- struct resources *res = &this->resources;
|
|
|
- struct resource *r, *r_dma;
|
|
|
- unsigned int i;
|
|
|
+ struct resource *r_dma;
|
|
|
+ struct device_node *dn;
|
|
|
+ int dma_channel;
|
|
|
+ unsigned int ret;
|
|
|
+ struct dma_chan *dma_chan;
|
|
|
+ dma_cap_mask_t mask;
|
|
|
+
|
|
|
+ /* dma channel, we only use the first one. */
|
|
|
+ dn = pdev->dev.of_node;
|
|
|
+ ret = of_property_read_u32(dn, "fsl,gpmi-dma-channel", &dma_channel);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("unable to get DMA channel from dt.\n");
|
|
|
+ goto acquire_err;
|
|
|
+ }
|
|
|
+ this->private = (void *)dma_channel;
|
|
|
|
|
|
- r = platform_get_resource_byname(pdev, IORESOURCE_DMA,
|
|
|
- GPMI_NAND_DMA_CHANNELS_RES_NAME);
|
|
|
+ /* gpmi dma interrupt */
|
|
|
r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
|
|
GPMI_NAND_DMA_INTERRUPT_RES_NAME);
|
|
|
- if (!r || !r_dma) {
|
|
|
+ if (!r_dma) {
|
|
|
pr_err("Can't get resource for DMA\n");
|
|
|
- return -ENXIO;
|
|
|
+ goto acquire_err;
|
|
|
}
|
|
|
+ this->dma_data.chan_irq = r_dma->start;
|
|
|
|
|
|
- /* used in gpmi_dma_filter() */
|
|
|
- this->private = r;
|
|
|
-
|
|
|
- for (i = r->start; i <= r->end; i++) {
|
|
|
- struct dma_chan *dma_chan;
|
|
|
- dma_cap_mask_t mask;
|
|
|
+ /* request dma channel */
|
|
|
+ dma_cap_zero(mask);
|
|
|
+ dma_cap_set(DMA_SLAVE, mask);
|
|
|
|
|
|
- if (i - r->start >= pdata->max_chip_count)
|
|
|
- break;
|
|
|
-
|
|
|
- dma_cap_zero(mask);
|
|
|
- dma_cap_set(DMA_SLAVE, mask);
|
|
|
-
|
|
|
- /* get the DMA interrupt */
|
|
|
- if (r_dma->start == r_dma->end) {
|
|
|
- /* only register the first. */
|
|
|
- if (i == r->start)
|
|
|
- this->dma_data.chan_irq = r_dma->start;
|
|
|
- else
|
|
|
- this->dma_data.chan_irq = NO_IRQ;
|
|
|
- } else
|
|
|
- this->dma_data.chan_irq = r_dma->start + (i - r->start);
|
|
|
-
|
|
|
- dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
|
|
|
- if (!dma_chan)
|
|
|
- goto acquire_err;
|
|
|
-
|
|
|
- /* fill the first empty item */
|
|
|
- this->dma_chans[i - r->start] = dma_chan;
|
|
|
+ dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
|
|
|
+ if (!dma_chan) {
|
|
|
+ pr_err("dma_request_channel failed.\n");
|
|
|
+ goto acquire_err;
|
|
|
}
|
|
|
|
|
|
- res->dma_low_channel = r->start;
|
|
|
- res->dma_high_channel = i;
|
|
|
+ this->dma_chans[0] = dma_chan;
|
|
|
return 0;
|
|
|
|
|
|
acquire_err:
|
|
|
- pr_err("Can't acquire DMA channel %u\n", i);
|
|
|
release_dma_channels(this);
|
|
|
return -EINVAL;
|
|
|
}
|
|
@@ -1465,9 +1455,9 @@ void gpmi_nfc_exit(struct gpmi_nand_data *this)
|
|
|
|
|
|
static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
|
|
|
{
|
|
|
- struct gpmi_nand_platform_data *pdata = this->pdata;
|
|
|
struct mtd_info *mtd = &this->mtd;
|
|
|
struct nand_chip *chip = &this->nand;
|
|
|
+ struct mtd_part_parser_data ppdata = {};
|
|
|
int ret;
|
|
|
|
|
|
/* init current chip */
|
|
@@ -1505,14 +1495,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
|
|
|
if (ret)
|
|
|
goto err_out;
|
|
|
|
|
|
- ret = nand_scan(mtd, pdata->max_chip_count);
|
|
|
+ ret = nand_scan(mtd, 1);
|
|
|
if (ret) {
|
|
|
pr_err("Chip scan failed\n");
|
|
|
goto err_out;
|
|
|
}
|
|
|
|
|
|
- ret = mtd_device_parse_register(mtd, NULL, NULL,
|
|
|
- pdata->partitions, pdata->partition_count);
|
|
|
+ ppdata.of_node = this->pdev->dev.of_node;
|
|
|
+ ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
|
|
|
if (ret)
|
|
|
goto err_out;
|
|
|
return 0;
|
|
@@ -1522,12 +1512,37 @@ err_out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static const struct platform_device_id gpmi_ids[] = {
|
|
|
+ { .name = "imx23-gpmi-nand", .driver_data = IS_MX23, },
|
|
|
+ { .name = "imx28-gpmi-nand", .driver_data = IS_MX28, },
|
|
|
+ {},
|
|
|
+};
|
|
|
+
|
|
|
+static const struct of_device_id gpmi_nand_id_table[] = {
|
|
|
+ {
|
|
|
+ .compatible = "fsl,imx23-gpmi-nand",
|
|
|
+ .data = (void *)&gpmi_ids[IS_MX23]
|
|
|
+ }, {
|
|
|
+ .compatible = "fsl,imx28-gpmi-nand",
|
|
|
+ .data = (void *)&gpmi_ids[IS_MX28]
|
|
|
+ }, {}
|
|
|
+};
|
|
|
+MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
|
|
|
+
|
|
|
static int __devinit gpmi_nand_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data;
|
|
|
struct gpmi_nand_data *this;
|
|
|
+ const struct of_device_id *of_id;
|
|
|
int ret;
|
|
|
|
|
|
+ of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
|
|
|
+ if (of_id) {
|
|
|
+ pdev->id_entry = of_id->data;
|
|
|
+ } else {
|
|
|
+ pr_err("Failed to find the right device id.\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
this = kzalloc(sizeof(*this), GFP_KERNEL);
|
|
|
if (!this) {
|
|
|
pr_err("Failed to allocate per-device memory\n");
|
|
@@ -1537,13 +1552,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
|
|
|
platform_set_drvdata(pdev, this);
|
|
|
this->pdev = pdev;
|
|
|
this->dev = &pdev->dev;
|
|
|
- this->pdata = pdata;
|
|
|
-
|
|
|
- if (pdata->platform_init) {
|
|
|
- ret = pdata->platform_init();
|
|
|
- if (ret)
|
|
|
- goto platform_init_error;
|
|
|
- }
|
|
|
|
|
|
ret = acquire_resources(this);
|
|
|
if (ret)
|
|
@@ -1561,7 +1569,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
|
|
|
|
|
|
exit_nfc_init:
|
|
|
release_resources(this);
|
|
|
-platform_init_error:
|
|
|
exit_acquire_resources:
|
|
|
platform_set_drvdata(pdev, NULL);
|
|
|
kfree(this);
|
|
@@ -1579,19 +1586,10 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static const struct platform_device_id gpmi_ids[] = {
|
|
|
- {
|
|
|
- .name = "imx23-gpmi-nand",
|
|
|
- .driver_data = IS_MX23,
|
|
|
- }, {
|
|
|
- .name = "imx28-gpmi-nand",
|
|
|
- .driver_data = IS_MX28,
|
|
|
- }, {},
|
|
|
-};
|
|
|
-
|
|
|
static struct platform_driver gpmi_nand_driver = {
|
|
|
.driver = {
|
|
|
.name = "gpmi-nand",
|
|
|
+ .of_match_table = gpmi_nand_id_table,
|
|
|
},
|
|
|
.probe = gpmi_nand_probe,
|
|
|
.remove = __exit_p(gpmi_nand_remove),
|