mirror of
https://github.com/joel16/android_kernel_sony_msm8994.git
synced 2025-02-13 09:23:56 +00:00
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>
This commit is contained in:
parent
279f08d4ef
commit
e10db1f00a
33
Documentation/devicetree/bindings/mtd/gpmi-nand.txt
Normal file
33
Documentation/devicetree/bindings/mtd/gpmi-nand.txt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
* Freescale General-Purpose Media Interface (GPMI)
|
||||||
|
|
||||||
|
The GPMI nand controller provides an interface to control the
|
||||||
|
NAND flash chips. We support only one NAND chip now.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : should be "fsl,<chip>-gpmi-nand"
|
||||||
|
- reg : should contain registers location and length for gpmi and bch.
|
||||||
|
- reg-names: Should contain the reg names "gpmi-nand" and "bch"
|
||||||
|
- interrupts : The first is the DMA interrupt number for GPMI.
|
||||||
|
The second is the BCH interrupt number.
|
||||||
|
- interrupt-names : The interrupt names "gpmi-dma", "bch";
|
||||||
|
- fsl,gpmi-dma-channel : Should contain the dma channel it uses.
|
||||||
|
|
||||||
|
The device tree may optionally contain sub-nodes describing partitions of the
|
||||||
|
address space. See partition.txt for more detail.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
gpmi-nand@8000c000 {
|
||||||
|
compatible = "fsl,imx28-gpmi-nand";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
reg = <0x8000c000 2000>, <0x8000a000 2000>;
|
||||||
|
reg-names = "gpmi-nand", "bch";
|
||||||
|
interrupts = <88>, <41>;
|
||||||
|
interrupt-names = "gpmi-dma", "bch";
|
||||||
|
fsl,gpmi-dma-channel = <4>;
|
||||||
|
|
||||||
|
partition@0 {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
};
|
@ -256,11 +256,12 @@ static unsigned int ns_to_cycles(unsigned int time,
|
|||||||
return max(k, min);
|
return max(k, min);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DEF_MIN_PROP_DELAY 5
|
||||||
|
#define DEF_MAX_PROP_DELAY 9
|
||||||
/* Apply timing to current hardware conditions. */
|
/* Apply timing to current hardware conditions. */
|
||||||
static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
|
static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
|
||||||
struct gpmi_nfc_hardware_timing *hw)
|
struct gpmi_nfc_hardware_timing *hw)
|
||||||
{
|
{
|
||||||
struct gpmi_nand_platform_data *pdata = this->pdata;
|
|
||||||
struct timing_threshod *nfc = &timing_default_threshold;
|
struct timing_threshod *nfc = &timing_default_threshold;
|
||||||
struct nand_chip *nand = &this->nand;
|
struct nand_chip *nand = &this->nand;
|
||||||
struct nand_timing target = this->timing;
|
struct nand_timing target = this->timing;
|
||||||
@ -277,8 +278,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
|
|||||||
int ideal_sample_delay_in_ns;
|
int ideal_sample_delay_in_ns;
|
||||||
unsigned int sample_delay_factor;
|
unsigned int sample_delay_factor;
|
||||||
int tEYE;
|
int tEYE;
|
||||||
unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns;
|
unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
|
||||||
unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns;
|
unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are multiple chips, we need to relax the timings to allow
|
* If there are multiple chips, we need to relax the timings to allow
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mtd/gpmi-nand.h>
|
#include <linux/mtd/gpmi-nand.h>
|
||||||
#include <linux/mtd/partitions.h>
|
#include <linux/mtd/partitions.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include "gpmi-nand.h"
|
#include "gpmi-nand.h"
|
||||||
|
|
||||||
/* add our owner bbt descriptor */
|
/* 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)
|
static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
|
||||||
{
|
{
|
||||||
struct gpmi_nand_data *this = param;
|
struct gpmi_nand_data *this = param;
|
||||||
struct resource *r = this->private;
|
int dma_channel = (int)this->private;
|
||||||
|
|
||||||
if (!mxs_dma_is_apbh(chan))
|
if (!mxs_dma_is_apbh(chan))
|
||||||
return false;
|
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
|
* for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7
|
||||||
* (These eight channels share the same IRQ!)
|
* (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;
|
chan->private = &this->dma_data;
|
||||||
return true;
|
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)
|
static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = this->pdev;
|
struct platform_device *pdev = this->pdev;
|
||||||
struct gpmi_nand_platform_data *pdata = this->pdata;
|
struct resource *r_dma;
|
||||||
struct resources *res = &this->resources;
|
struct device_node *dn;
|
||||||
struct resource *r, *r_dma;
|
int dma_channel;
|
||||||
unsigned int i;
|
unsigned int ret;
|
||||||
|
struct dma_chan *dma_chan;
|
||||||
|
dma_cap_mask_t mask;
|
||||||
|
|
||||||
r = platform_get_resource_byname(pdev, IORESOURCE_DMA,
|
/* dma channel, we only use the first one. */
|
||||||
GPMI_NAND_DMA_CHANNELS_RES_NAME);
|
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;
|
||||||
|
|
||||||
|
/* gpmi dma interrupt */
|
||||||
r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||||
GPMI_NAND_DMA_INTERRUPT_RES_NAME);
|
GPMI_NAND_DMA_INTERRUPT_RES_NAME);
|
||||||
if (!r || !r_dma) {
|
if (!r_dma) {
|
||||||
pr_err("Can't get resource for DMA\n");
|
pr_err("Can't get resource for DMA\n");
|
||||||
return -ENXIO;
|
goto acquire_err;
|
||||||
|
}
|
||||||
|
this->dma_data.chan_irq = r_dma->start;
|
||||||
|
|
||||||
|
/* request dma channel */
|
||||||
|
dma_cap_zero(mask);
|
||||||
|
dma_cap_set(DMA_SLAVE, mask);
|
||||||
|
|
||||||
|
dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
|
||||||
|
if (!dma_chan) {
|
||||||
|
pr_err("dma_request_channel failed.\n");
|
||||||
|
goto acquire_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* used in gpmi_dma_filter() */
|
this->dma_chans[0] = dma_chan;
|
||||||
this->private = r;
|
|
||||||
|
|
||||||
for (i = r->start; i <= r->end; i++) {
|
|
||||||
struct dma_chan *dma_chan;
|
|
||||||
dma_cap_mask_t 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
res->dma_low_channel = r->start;
|
|
||||||
res->dma_high_channel = i;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
acquire_err:
|
acquire_err:
|
||||||
pr_err("Can't acquire DMA channel %u\n", i);
|
|
||||||
release_dma_channels(this);
|
release_dma_channels(this);
|
||||||
return -EINVAL;
|
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)
|
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 mtd_info *mtd = &this->mtd;
|
||||||
struct nand_chip *chip = &this->nand;
|
struct nand_chip *chip = &this->nand;
|
||||||
|
struct mtd_part_parser_data ppdata = {};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* init current chip */
|
/* init current chip */
|
||||||
@ -1505,14 +1495,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
ret = nand_scan(mtd, pdata->max_chip_count);
|
ret = nand_scan(mtd, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Chip scan failed\n");
|
pr_err("Chip scan failed\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mtd_device_parse_register(mtd, NULL, NULL,
|
ppdata.of_node = this->pdev->dev.of_node;
|
||||||
pdata->partitions, pdata->partition_count);
|
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1522,12 +1512,37 @@ err_out:
|
|||||||
return ret;
|
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)
|
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;
|
struct gpmi_nand_data *this;
|
||||||
|
const struct of_device_id *of_id;
|
||||||
int ret;
|
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);
|
this = kzalloc(sizeof(*this), GFP_KERNEL);
|
||||||
if (!this) {
|
if (!this) {
|
||||||
pr_err("Failed to allocate per-device memory\n");
|
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);
|
platform_set_drvdata(pdev, this);
|
||||||
this->pdev = pdev;
|
this->pdev = pdev;
|
||||||
this->dev = &pdev->dev;
|
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);
|
ret = acquire_resources(this);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1561,7 +1569,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
exit_nfc_init:
|
exit_nfc_init:
|
||||||
release_resources(this);
|
release_resources(this);
|
||||||
platform_init_error:
|
|
||||||
exit_acquire_resources:
|
exit_acquire_resources:
|
||||||
platform_set_drvdata(pdev, NULL);
|
platform_set_drvdata(pdev, NULL);
|
||||||
kfree(this);
|
kfree(this);
|
||||||
@ -1579,19 +1586,10 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
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 = {
|
static struct platform_driver gpmi_nand_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "gpmi-nand",
|
.name = "gpmi-nand",
|
||||||
|
.of_match_table = gpmi_nand_id_table,
|
||||||
},
|
},
|
||||||
.probe = gpmi_nand_probe,
|
.probe = gpmi_nand_probe,
|
||||||
.remove = __exit_p(gpmi_nand_remove),
|
.remove = __exit_p(gpmi_nand_remove),
|
||||||
|
@ -266,8 +266,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *,
|
|||||||
#define STATUS_UNCORRECTABLE 0xfe
|
#define STATUS_UNCORRECTABLE 0xfe
|
||||||
|
|
||||||
/* Use the platform_id to distinguish different Archs. */
|
/* Use the platform_id to distinguish different Archs. */
|
||||||
#define IS_MX23 0x1
|
#define IS_MX23 0x0
|
||||||
#define IS_MX28 0x2
|
#define IS_MX28 0x1
|
||||||
#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23)
|
#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23)
|
||||||
#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28)
|
#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28)
|
||||||
#endif
|
#endif
|
||||||
|
@ -23,12 +23,12 @@
|
|||||||
#define GPMI_NAND_RES_SIZE 6
|
#define GPMI_NAND_RES_SIZE 6
|
||||||
|
|
||||||
/* Resource names for the GPMI NAND driver. */
|
/* Resource names for the GPMI NAND driver. */
|
||||||
#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "GPMI NAND GPMI Registers"
|
#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand"
|
||||||
#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt"
|
#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt"
|
||||||
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "GPMI NAND BCH Registers"
|
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch"
|
||||||
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "GPMI NAND BCH Interrupt"
|
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch"
|
||||||
#define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels"
|
#define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels"
|
||||||
#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "GPMI NAND DMA Interrupt"
|
#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct gpmi_nand_platform_data - GPMI NAND driver platform data.
|
* struct gpmi_nand_platform_data - GPMI NAND driver platform data.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user