OMAP GPMC (General Purpose Memory Controller) changes to add
device tree bindings. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJRD/qiAAoJEBvUPslcq6VzqDYQAI0L0cINi94HHr+PFHlqdmRk kbOSAZtGLBCOXKL5/hpQA+whCP2CRS56SUJhRzAqgD02oaNUCSYvwIuiF35eOfTN QLAQOucF/hSueNJew9IYqKs4rYmYNNQq4xF03QvVc/OOs6ASYSWDMi9e78GyDPXa gqYyAVQekUUGTW+az7SHn+c/0hsdsSKOUZ0KbVyuaP7b64MZdIqqYGwTkRv8dVqc 5un4DCslVIaAtDDqUs1RML/dLwsZ8XLHiEZnhmii+V8bSnVlOa0e0us+vhyBus9S fbU8bdLaFAi6OPzJ9nCoQw9YSqyKjg6fq7EcSq5CQ0KpCq6iw0VAYW3usxSWrzsu vZpzUvnC+5MJFY68vg7emrF2CcCOf0v6U172ypviU3nbSHaH1l0cSdPJugk3Z4mr 5jmNPFKhslB64PvOW406UGdUJ5PoZaIO/S6fjic0HF8aqpYYqCQWQaHVDieJf5GV DTtpPPGWe94ZGd67g7cqCO6ZWn+/kXGMze/CKQJERJUjoMpKr0/yrJICpHac4Gxa 8TuNi78YYpyor+IAWYRIrycjjO2GRiftFywccRZuN8eaDlZFC10K30Qp0SUqngrr sdNbTORbCEBPsM9mbMZ5I+UNiDB5kUaFw790BvxDyjAfkpc4xr5ZKk875WZ4nGEP PL+RCilq+3hk6weipnuk =bQWe -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.9/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/drivers From Tony Lindgren: OMAP GPMC (General Purpose Memory Controller) changes to add device tree bindings. * tag 'omap-for-v3.9/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: ARM: OMAP2+: gpmc: Add device tree documentation for elm handle ARM: OMAP2+: gpmc: add DT bindings for OneNAND ARM: OMAP2+: gpmc-onenand: drop __init annotation mtd: omap-onenand: pass device_node in platform data ARM: OMAP2+: Prevent potential crash if GPMC probe fails ARM: OMAP2+: gpmc: Remove unneeded of_node_put() ARM: OMAP: gpmc: add DT bindings for GPMC timings and NAND ARM: OMAP: gpmc: enable hwecc for AM33xx SoCs ARM: OMAP: gpmc-nand: drop __init annotation mtd: omap-nand: pass device_node in platform data ARM: OMAP: gpmc: don't create devices from initcall on DT Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
b6a03d0492
10 changed files with 459 additions and 12 deletions
84
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Normal file
84
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Normal file
|
@ -0,0 +1,84 @@
|
|||
Device tree bindings for OMAP general purpose memory controllers (GPMC)
|
||||
|
||||
The actual devices are instantiated from the child nodes of a GPMC node.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should be set to one of the following:
|
||||
|
||||
ti,omap2420-gpmc (omap2420)
|
||||
ti,omap2430-gpmc (omap2430)
|
||||
ti,omap3430-gpmc (omap3430 & omap3630)
|
||||
ti,omap4430-gpmc (omap4430 & omap4460 & omap543x)
|
||||
ti,am3352-gpmc (am335x devices)
|
||||
|
||||
- reg: A resource specifier for the register space
|
||||
(see the example below)
|
||||
- ti,hwmods: Should be set to "ti,gpmc" until the DT transition is
|
||||
completed.
|
||||
- #address-cells: Must be set to 2 to allow memory address translation
|
||||
- #size-cells: Must be set to 1 to allow CS address passing
|
||||
- gpmc,num-cs: The maximum number of chip-select lines that controller
|
||||
can support.
|
||||
- gpmc,num-waitpins: The maximum number of wait pins that controller can
|
||||
support.
|
||||
- ranges: Must be set up to reflect the memory layout with four
|
||||
integer values for each chip-select line in use:
|
||||
|
||||
<cs-number> 0 <physical address of mapping> <size>
|
||||
|
||||
Currently, calculated values derived from the contents
|
||||
of the per-CS register GPMC_CONFIG7 (as set up by the
|
||||
bootloader) are used for the physical address decoding.
|
||||
As this will change in the future, filling correct
|
||||
values here is a requirement.
|
||||
|
||||
Timing properties for child nodes. All are optional and default to 0.
|
||||
|
||||
- gpmc,sync-clk: Minimum clock period for synchronous mode, in picoseconds
|
||||
|
||||
Chip-select signal timings corresponding to GPMC_CONFIG2:
|
||||
- gpmc,cs-on: Assertion time
|
||||
- gpmc,cs-rd-off: Read deassertion time
|
||||
- gpmc,cs-wr-off: Write deassertion time
|
||||
|
||||
ADV signal timings corresponding to GPMC_CONFIG3:
|
||||
- gpmc,adv-on: Assertion time
|
||||
- gpmc,adv-rd-off: Read deassertion time
|
||||
- gpmc,adv-wr-off: Write deassertion time
|
||||
|
||||
WE signals timings corresponding to GPMC_CONFIG4:
|
||||
- gpmc,we-on: Assertion time
|
||||
- gpmc,we-off: Deassertion time
|
||||
|
||||
OE signals timings corresponding to GPMC_CONFIG4:
|
||||
- gpmc,oe-on: Assertion time
|
||||
- gpmc,oe-off: Deassertion time
|
||||
|
||||
Access time and cycle time timings corresponding to GPMC_CONFIG5:
|
||||
- gpmc,page-burst-access: Multiple access word delay
|
||||
- gpmc,access: Start-cycle to first data valid delay
|
||||
- gpmc,rd-cycle: Total read cycle time
|
||||
- gpmc,wr-cycle: Total write cycle time
|
||||
|
||||
The following are only applicable to OMAP3+ and AM335x:
|
||||
- gpmc,wr-access
|
||||
- gpmc,wr-data-mux-bus
|
||||
|
||||
|
||||
Example for an AM33xx board:
|
||||
|
||||
gpmc: gpmc@50000000 {
|
||||
compatible = "ti,am3352-gpmc";
|
||||
ti,hwmods = "gpmc";
|
||||
reg = <0x50000000 0x2000>;
|
||||
interrupts = <100>;
|
||||
|
||||
gpmc,num-cs = <8>;
|
||||
gpmc,num-waitpins = <2>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
|
||||
|
||||
/* child nodes go here */
|
||||
};
|
80
Documentation/devicetree/bindings/mtd/gpmc-nand.txt
Normal file
80
Documentation/devicetree/bindings/mtd/gpmc-nand.txt
Normal file
|
@ -0,0 +1,80 @@
|
|||
Device tree bindings for GPMC connected NANDs
|
||||
|
||||
GPMC connected NAND (found on OMAP boards) are represented as child nodes of
|
||||
the GPMC controller with a name of "nand".
|
||||
|
||||
All timing relevant properties as well as generic gpmc child properties are
|
||||
explained in a separate documents - please refer to
|
||||
Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||
|
||||
For NAND specific properties such as ECC modes or bus width, please refer to
|
||||
Documentation/devicetree/bindings/mtd/nand.txt
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- reg: The CS line the peripheral is connected to
|
||||
|
||||
Optional properties:
|
||||
|
||||
- nand-bus-width: Set this numeric value to 16 if the hardware
|
||||
is wired that way. If not specified, a bus
|
||||
width of 8 is assumed.
|
||||
|
||||
- ti,nand-ecc-opt: A string setting the ECC layout to use. One of:
|
||||
|
||||
"sw" Software method (default)
|
||||
"hw" Hardware method
|
||||
"hw-romcode" gpmc hamming mode method & romcode layout
|
||||
"bch4" 4-bit BCH ecc code
|
||||
"bch8" 8-bit BCH ecc code
|
||||
|
||||
- elm_id: Specifies elm device node. This is required to support BCH
|
||||
error correction using ELM module.
|
||||
|
||||
For inline partiton table parsing (optional):
|
||||
|
||||
- #address-cells: should be set to 1
|
||||
- #size-cells: should be set to 1
|
||||
|
||||
Example for an AM33xx board:
|
||||
|
||||
gpmc: gpmc@50000000 {
|
||||
compatible = "ti,am3352-gpmc";
|
||||
ti,hwmods = "gpmc";
|
||||
reg = <0x50000000 0x1000000>;
|
||||
interrupts = <100>;
|
||||
gpmc,num-cs = <8>;
|
||||
gpmc,num-waitpins = <2>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0 0x08000000 0x2000>; /* CS0: NAND */
|
||||
elm_id = <&elm>;
|
||||
|
||||
nand@0,0 {
|
||||
reg = <0 0 0>; /* CS0, offset 0 */
|
||||
nand-bus-width = <16>;
|
||||
ti,nand-ecc-opt = "bch8";
|
||||
|
||||
gpmc,sync-clk = <0>;
|
||||
gpmc,cs-on = <0>;
|
||||
gpmc,cs-rd-off = <44>;
|
||||
gpmc,cs-wr-off = <44>;
|
||||
gpmc,adv-on = <6>;
|
||||
gpmc,adv-rd-off = <34>;
|
||||
gpmc,adv-wr-off = <44>;
|
||||
gpmc,we-off = <40>;
|
||||
gpmc,oe-off = <54>;
|
||||
gpmc,access = <64>;
|
||||
gpmc,rd-cycle = <82>;
|
||||
gpmc,wr-cycle = <82>;
|
||||
gpmc,wr-access = <40>;
|
||||
gpmc,wr-data-mux-bus = <0>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
/* partitions go here */
|
||||
};
|
||||
};
|
||||
|
43
Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
Normal file
43
Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
Device tree bindings for GPMC connected OneNANDs
|
||||
|
||||
GPMC connected OneNAND (found on OMAP boards) are represented as child nodes of
|
||||
the GPMC controller with a name of "onenand".
|
||||
|
||||
All timing relevant properties as well as generic gpmc child properties are
|
||||
explained in a separate documents - please refer to
|
||||
Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||
|
||||
Required properties:
|
||||
|
||||
- reg: The CS line the peripheral is connected to
|
||||
|
||||
Optional properties:
|
||||
|
||||
- dma-channel: DMA Channel index
|
||||
|
||||
For inline partiton table parsing (optional):
|
||||
|
||||
- #address-cells: should be set to 1
|
||||
- #size-cells: should be set to 1
|
||||
|
||||
Example for an OMAP3430 board:
|
||||
|
||||
gpmc: gpmc@6e000000 {
|
||||
compatible = "ti,omap3430-gpmc";
|
||||
ti,hwmods = "gpmc";
|
||||
reg = <0x6e000000 0x1000000>;
|
||||
interrupts = <20>;
|
||||
gpmc,num-cs = <8>;
|
||||
gpmc,num-waitpins = <4>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
|
||||
onenand@0 {
|
||||
reg = <0 0 0>; /* CS0, offset 0 */
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
/* partitions go here */
|
||||
};
|
||||
};
|
|
@ -89,20 +89,21 @@ static int omap2_nand_gpmc_retime(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
|
||||
static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
|
||||
{
|
||||
/* support only OMAP3 class */
|
||||
if (!cpu_is_omap34xx()) {
|
||||
if (!cpu_is_omap34xx() && !soc_is_am33xx()) {
|
||||
pr_err("BCH ecc is not supported on this CPU\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1.
|
||||
* Other chips may be added if confirmed to work.
|
||||
* For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1
|
||||
* and AM33xx derivates. Other chips may be added if confirmed to work.
|
||||
*/
|
||||
if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) &&
|
||||
(!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) {
|
||||
(!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0)) &&
|
||||
(!soc_is_am33xx())) {
|
||||
pr_err("BCH 4-bit mode is not supported on this CPU\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,8 +111,8 @@ static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
int err = 0;
|
||||
struct device *dev = &gpmc_nand_device.dev;
|
||||
|
|
|
@ -356,7 +356,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
||||
void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_mtd.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
|
@ -34,6 +38,8 @@
|
|||
#include "common.h"
|
||||
#include "omap_device.h"
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-nand.h"
|
||||
#include "gpmc-onenand.h"
|
||||
|
||||
#define DEVICE_NAME "omap-gpmc"
|
||||
|
||||
|
@ -145,7 +151,8 @@ static unsigned gpmc_irq_start;
|
|||
static struct resource gpmc_mem_root;
|
||||
static struct resource gpmc_cs_mem[GPMC_CS_NUM];
|
||||
static DEFINE_SPINLOCK(gpmc_mem_lock);
|
||||
static unsigned int gpmc_cs_map; /* flag for cs which are initialized */
|
||||
/* Define chip-selects as reserved by default until probe completes */
|
||||
static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
|
||||
static struct device *gpmc_dev;
|
||||
static int gpmc_irq;
|
||||
static resource_size_t phys_base, mem_size;
|
||||
|
@ -1118,9 +1125,216 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
|
|||
/* TODO: remove, see function definition */
|
||||
gpmc_convert_ps_to_ns(gpmc_t);
|
||||
|
||||
/* Now the GPMC is initialised, unreserve the chip-selects */
|
||||
gpmc_cs_map = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id gpmc_dt_ids[] = {
|
||||
{ .compatible = "ti,omap2420-gpmc" },
|
||||
{ .compatible = "ti,omap2430-gpmc" },
|
||||
{ .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */
|
||||
{ .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */
|
||||
{ .compatible = "ti,am3352-gpmc" }, /* am335x devices */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
|
||||
|
||||
static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
memset(gpmc_t, 0, sizeof(*gpmc_t));
|
||||
|
||||
/* minimum clock period for syncronous mode */
|
||||
if (!of_property_read_u32(np, "gpmc,sync-clk", &val))
|
||||
gpmc_t->sync_clk = val;
|
||||
|
||||
/* chip select timtings */
|
||||
if (!of_property_read_u32(np, "gpmc,cs-on", &val))
|
||||
gpmc_t->cs_on = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val))
|
||||
gpmc_t->cs_rd_off = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val))
|
||||
gpmc_t->cs_wr_off = val;
|
||||
|
||||
/* ADV signal timings */
|
||||
if (!of_property_read_u32(np, "gpmc,adv-on", &val))
|
||||
gpmc_t->adv_on = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val))
|
||||
gpmc_t->adv_rd_off = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val))
|
||||
gpmc_t->adv_wr_off = val;
|
||||
|
||||
/* WE signal timings */
|
||||
if (!of_property_read_u32(np, "gpmc,we-on", &val))
|
||||
gpmc_t->we_on = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,we-off", &val))
|
||||
gpmc_t->we_off = val;
|
||||
|
||||
/* OE signal timings */
|
||||
if (!of_property_read_u32(np, "gpmc,oe-on", &val))
|
||||
gpmc_t->oe_on = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,oe-off", &val))
|
||||
gpmc_t->oe_off = val;
|
||||
|
||||
/* access and cycle timings */
|
||||
if (!of_property_read_u32(np, "gpmc,page-burst-access", &val))
|
||||
gpmc_t->page_burst_access = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,access", &val))
|
||||
gpmc_t->access = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,rd-cycle", &val))
|
||||
gpmc_t->rd_cycle = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,wr-cycle", &val))
|
||||
gpmc_t->wr_cycle = val;
|
||||
|
||||
/* only for OMAP3430 */
|
||||
if (!of_property_read_u32(np, "gpmc,wr-access", &val))
|
||||
gpmc_t->wr_access = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val))
|
||||
gpmc_t->wr_data_mux_bus = val;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_NAND
|
||||
|
||||
static const char * const nand_ecc_opts[] = {
|
||||
[OMAP_ECC_HAMMING_CODE_DEFAULT] = "sw",
|
||||
[OMAP_ECC_HAMMING_CODE_HW] = "hw",
|
||||
[OMAP_ECC_HAMMING_CODE_HW_ROMCODE] = "hw-romcode",
|
||||
[OMAP_ECC_BCH4_CODE_HW] = "bch4",
|
||||
[OMAP_ECC_BCH8_CODE_HW] = "bch8",
|
||||
};
|
||||
|
||||
static int gpmc_probe_nand_child(struct platform_device *pdev,
|
||||
struct device_node *child)
|
||||
{
|
||||
u32 val;
|
||||
const char *s;
|
||||
struct gpmc_timings gpmc_t;
|
||||
struct omap_nand_platform_data *gpmc_nand_data;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &val) < 0) {
|
||||
dev_err(&pdev->dev, "%s has no 'reg' property\n",
|
||||
child->full_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
|
||||
GFP_KERNEL);
|
||||
if (!gpmc_nand_data)
|
||||
return -ENOMEM;
|
||||
|
||||
gpmc_nand_data->cs = val;
|
||||
gpmc_nand_data->of_node = child;
|
||||
|
||||
if (!of_property_read_string(child, "ti,nand-ecc-opt", &s))
|
||||
for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++)
|
||||
if (!strcasecmp(s, nand_ecc_opts[val])) {
|
||||
gpmc_nand_data->ecc_opt = val;
|
||||
break;
|
||||
}
|
||||
|
||||
val = of_get_nand_bus_width(child);
|
||||
if (val == 16)
|
||||
gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
|
||||
|
||||
gpmc_read_timings_dt(child, &gpmc_t);
|
||||
gpmc_nand_init(gpmc_nand_data, &gpmc_t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int gpmc_probe_nand_child(struct platform_device *pdev,
|
||||
struct device_node *child)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_ONENAND
|
||||
static int gpmc_probe_onenand_child(struct platform_device *pdev,
|
||||
struct device_node *child)
|
||||
{
|
||||
u32 val;
|
||||
struct omap_onenand_platform_data *gpmc_onenand_data;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &val) < 0) {
|
||||
dev_err(&pdev->dev, "%s has no 'reg' property\n",
|
||||
child->full_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data),
|
||||
GFP_KERNEL);
|
||||
if (!gpmc_onenand_data)
|
||||
return -ENOMEM;
|
||||
|
||||
gpmc_onenand_data->cs = val;
|
||||
gpmc_onenand_data->of_node = child;
|
||||
gpmc_onenand_data->dma_channel = -1;
|
||||
|
||||
if (!of_property_read_u32(child, "dma-channel", &val))
|
||||
gpmc_onenand_data->dma_channel = val;
|
||||
|
||||
gpmc_onenand_init(gpmc_onenand_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int gpmc_probe_onenand_child(struct platform_device *pdev,
|
||||
struct device_node *child)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int gpmc_probe_dt(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct device_node *child;
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(gpmc_dt_ids, &pdev->dev);
|
||||
|
||||
if (!of_id)
|
||||
return 0;
|
||||
|
||||
for_each_node_by_name(child, "nand") {
|
||||
ret = gpmc_probe_nand_child(pdev, child);
|
||||
if (ret < 0) {
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_node_by_name(child, "onenand") {
|
||||
ret = gpmc_probe_onenand_child(pdev, child);
|
||||
if (ret < 0) {
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int gpmc_probe_dt(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int gpmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
|
@ -1174,6 +1388,14 @@ static int gpmc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR_VALUE(gpmc_setup_irq()))
|
||||
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
|
||||
|
||||
rc = gpmc_probe_dt(pdev);
|
||||
if (rc < 0) {
|
||||
clk_disable_unprepare(gpmc_l3_clk);
|
||||
clk_put(gpmc_l3_clk);
|
||||
dev_err(gpmc_dev, "failed to probe DT parameters\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1191,6 +1413,7 @@ static struct platform_driver gpmc_driver = {
|
|||
.driver = {
|
||||
.name = DEVICE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(gpmc_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1214,6 +1437,13 @@ static int __init omap_gpmc_init(void)
|
|||
struct platform_device *pdev;
|
||||
char *oh_name = "gpmc";
|
||||
|
||||
/*
|
||||
* if the board boots up with a populated DT, do not
|
||||
* manually add the device from this initcall
|
||||
*/
|
||||
if (of_have_populated_dt())
|
||||
return -ENODEV;
|
||||
|
||||
oh = omap_hwmod_lookup(oh_name);
|
||||
if (!oh) {
|
||||
pr_err("Could not look up %s\n", oh_name);
|
||||
|
|
|
@ -1332,6 +1332,7 @@ static int omap_nand_probe(struct platform_device *pdev)
|
|||
dma_cap_mask_t mask;
|
||||
unsigned sig;
|
||||
struct resource *res;
|
||||
struct mtd_part_parser_data ppdata = {};
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
|
@ -1557,7 +1558,8 @@ static int omap_nand_probe(struct platform_device *pdev)
|
|||
goto out_release_mem_region;
|
||||
}
|
||||
|
||||
mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
|
||||
ppdata.of_node = pdata->of_node;
|
||||
mtd_device_parse_register(&info->mtd, NULL, &ppdata, pdata->parts,
|
||||
pdata->nr_parts);
|
||||
|
||||
platform_set_drvdata(pdev, &info->mtd);
|
||||
|
|
|
@ -637,6 +637,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
|
|||
struct onenand_chip *this;
|
||||
int r;
|
||||
struct resource *res;
|
||||
struct mtd_part_parser_data ppdata = {};
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
|
@ -767,7 +768,8 @@ static int omap2_onenand_probe(struct platform_device *pdev)
|
|||
if ((r = onenand_scan(&c->mtd, 1)) < 0)
|
||||
goto err_release_regulator;
|
||||
|
||||
r = mtd_device_parse_register(&c->mtd, NULL, NULL,
|
||||
ppdata.of_node = pdata->of_node;
|
||||
r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
|
||||
pdata ? pdata->parts : NULL,
|
||||
pdata ? pdata->nr_parts : 0);
|
||||
if (r)
|
||||
|
|
|
@ -60,6 +60,8 @@ struct omap_nand_platform_data {
|
|||
int devsize;
|
||||
enum omap_ecc ecc_opt;
|
||||
struct gpmc_nand_regs reg;
|
||||
};
|
||||
|
||||
/* for passing the partitions */
|
||||
struct device_node *of_node;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -29,5 +29,8 @@ struct omap_onenand_platform_data {
|
|||
u8 flags;
|
||||
u8 regulator_can_sleep;
|
||||
u8 skip_initial_unlocking;
|
||||
|
||||
/* for passing the partitions */
|
||||
struct device_node *of_node;
|
||||
};
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue