aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/gpmc-onenand.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/gpmc-onenand.c')
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c463
1 files changed, 260 insertions, 203 deletions
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 7bb69220adf..8b6876c98ce 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -10,30 +10,60 @@
* published by the Free Software Foundation.
*/
+#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/mtd/onenand_regs.h>
#include <linux/io.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
+#include <linux/err.h>
#include <asm/mach/flash.h>
-#include <plat/onenand.h>
-#include <plat/board.h>
-#include <plat/gpmc.h>
+#include "gpmc.h"
+#include "soc.h"
+#include "gpmc-onenand.h"
+
+#define ONENAND_IO_SIZE SZ_128K
+
+#define ONENAND_FLAG_SYNCREAD (1 << 0)
+#define ONENAND_FLAG_SYNCWRITE (1 << 1)
+#define ONENAND_FLAG_HF (1 << 2)
+#define ONENAND_FLAG_VHF (1 << 3)
+
+static unsigned onenand_flags;
+static unsigned latency;
static struct omap_onenand_platform_data *gpmc_onenand_data;
+static struct resource gpmc_onenand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
static struct platform_device gpmc_onenand_device = {
.name = "omap2-onenand",
.id = -1,
+ .num_resources = 1,
+ .resource = &gpmc_onenand_resource,
};
-static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
-{
- struct gpmc_timings t;
- u32 reg;
- int err;
+static struct gpmc_settings onenand_async = {
+ .device_width = GPMC_DEVWIDTH_16BIT,
+ .mux_add_data = GPMC_MUX_AD,
+};
+
+static struct gpmc_settings onenand_sync = {
+ .burst_read = true,
+ .burst_wrap = true,
+ .burst_len = GPMC_BURST_16,
+ .device_width = GPMC_DEVWIDTH_16BIT,
+ .mux_add_data = GPMC_MUX_AD,
+ .wait_pin = 0,
+};
+static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
+{
+ struct gpmc_device_timings dev_t;
const int t_cer = 15;
const int t_avdp = 12;
const int t_aavdh = 7;
@@ -41,60 +71,36 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
const int t_aa = 76;
const int t_oe = 20;
const int t_cez = 20; /* max of t_cez, t_oez */
- const int t_ds = 30;
const int t_wpl = 40;
const int t_wph = 30;
- /* Ensure sync read and sync write are disabled */
- reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
- reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
- writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+ memset(&dev_t, 0, sizeof(dev_t));
- memset(&t, 0, sizeof(t));
- t.sync_clk = 0;
- t.cs_on = 0;
- t.adv_on = 0;
-
- /* Read */
- t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
- t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
- t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
- t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
- t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
- t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
- t.cs_rd_off = t.oe_off;
- t.rd_cycle = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
-
- /* Write */
- t.adv_wr_off = t.adv_rd_off;
- t.we_on = t.oe_on;
- if (cpu_is_omap34xx()) {
- t.wr_data_mux_bus = t.we_on;
- t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
- }
- t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
- t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
- t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+ dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
+ dev_t.t_avdp_w = dev_t.t_avdp_r;
+ dev_t.t_aavdh = t_aavdh * 1000;
+ dev_t.t_aa = t_aa * 1000;
+ dev_t.t_ce = t_ce * 1000;
+ dev_t.t_oe = t_oe * 1000;
+ dev_t.t_cez_r = t_cez * 1000;
+ dev_t.t_cez_w = dev_t.t_cez_r;
+ dev_t.t_wpl = t_wpl * 1000;
+ dev_t.t_wph = t_wph * 1000;
- /* Configure GPMC for asynchronous read */
- gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
- GPMC_CONFIG1_DEVICESIZE_16 |
- GPMC_CONFIG1_MUXADDDATA);
+ gpmc_calc_timings(t, &onenand_async, &dev_t);
+}
- err = gpmc_cs_set_timings(cs, &t);
- if (err)
- return err;
+static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
+{
+ u32 reg;
/* Ensure sync read and sync write are disabled */
reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
-
- return 0;
}
-static void set_onenand_cfg(void __iomem *onenand_base, int latency,
- int sync_read, int sync_write, int hf)
+static void set_onenand_cfg(void __iomem *onenand_base)
{
u32 reg;
@@ -102,79 +108,85 @@ static void set_onenand_cfg(void __iomem *onenand_base, int latency,
reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
ONENAND_SYS_CFG1_BL_16;
- if (sync_read)
+ if (onenand_flags & ONENAND_FLAG_SYNCREAD)
reg |= ONENAND_SYS_CFG1_SYNC_READ;
else
reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
- if (sync_write)
+ if (onenand_flags & ONENAND_FLAG_SYNCWRITE)
reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
else
reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
- if (hf)
+ if (onenand_flags & ONENAND_FLAG_HF)
reg |= ONENAND_SYS_CFG1_HF;
else
reg &= ~ONENAND_SYS_CFG1_HF;
+ if (onenand_flags & ONENAND_FLAG_VHF)
+ reg |= ONENAND_SYS_CFG1_VHF;
+ else
+ reg &= ~ONENAND_SYS_CFG1_VHF;
writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
}
-static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
- void __iomem *onenand_base,
- int freq)
+static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
+ void __iomem *onenand_base)
{
- struct gpmc_timings t;
+ u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
+ int freq;
+
+ switch ((ver >> 4) & 0xf) {
+ case 0:
+ freq = 40;
+ break;
+ case 1:
+ freq = 54;
+ break;
+ case 2:
+ freq = 66;
+ break;
+ case 3:
+ freq = 83;
+ break;
+ case 4:
+ freq = 104;
+ break;
+ default:
+ freq = 54;
+ break;
+ }
+
+ return freq;
+}
+
+static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
+ unsigned int flags,
+ int freq)
+{
+ struct gpmc_device_timings dev_t;
const int t_cer = 15;
const int t_avdp = 12;
const int t_cez = 20; /* max of t_cez, t_oez */
- const int t_ds = 30;
const int t_wpl = 40;
const int t_wph = 30;
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
- int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
- int first_time = 0, hf = 0, sync_read = 0, sync_write = 0;
- int err, ticks_cez;
- int cs = cfg->cs;
- u32 reg;
+ int div, gpmc_clk_ns;
- if (cfg->flags & ONENAND_SYNC_READ) {
- sync_read = 1;
- } else if (cfg->flags & ONENAND_SYNC_READWRITE) {
- sync_read = 1;
- sync_write = 1;
- } else
- return omap2_onenand_set_async_mode(cs, onenand_base);
-
- if (!freq) {
- /* Very first call freq is not known */
- err = omap2_onenand_set_async_mode(cs, onenand_base);
- if (err)
- return err;
- reg = readw(onenand_base + ONENAND_REG_VERSION_ID);
- switch ((reg >> 4) & 0xf) {
- case 0:
- freq = 40;
- break;
- case 1:
- freq = 54;
- break;
- case 2:
- freq = 66;
- break;
- case 3:
- freq = 83;
- break;
- case 4:
- freq = 104;
- break;
- default:
- freq = 54;
- break;
- }
- first_time = 1;
- }
+ if (flags & ONENAND_SYNC_READ)
+ onenand_flags = ONENAND_FLAG_SYNCREAD;
+ else if (flags & ONENAND_SYNC_READWRITE)
+ onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
switch (freq) {
+ case 104:
+ min_gpmc_clk_period = 9600; /* 104 MHz */
+ t_ces = 3;
+ t_avds = 4;
+ t_avdh = 2;
+ t_ach = 3;
+ t_aavdh = 6;
+ t_rdyo = 6;
+ break;
case 83:
- min_gpmc_clk_period = 12; /* 83 MHz */
+ min_gpmc_clk_period = 12000; /* 83 MHz */
t_ces = 5;
t_avds = 4;
t_avdh = 2;
@@ -183,7 +195,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
t_rdyo = 9;
break;
case 66:
- min_gpmc_clk_period = 15; /* 66 MHz */
+ min_gpmc_clk_period = 15000; /* 66 MHz */
t_ces = 6;
t_avds = 5;
t_avdh = 2;
@@ -192,156 +204,201 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
t_rdyo = 11;
break;
default:
- min_gpmc_clk_period = 18; /* 54 MHz */
+ min_gpmc_clk_period = 18500; /* 54 MHz */
t_ces = 7;
t_avds = 7;
t_avdh = 7;
t_ach = 9;
t_aavdh = 7;
t_rdyo = 15;
- sync_write = 0;
+ onenand_flags &= ~ONENAND_FLAG_SYNCWRITE;
break;
}
- tick_ns = gpmc_ticks_to_ns(1);
- div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
+ div = gpmc_calc_divider(min_gpmc_clk_period);
gpmc_clk_ns = gpmc_ticks_to_ns(div);
if (gpmc_clk_ns < 15) /* >66Mhz */
- hf = 1;
- if (hf)
+ onenand_flags |= ONENAND_FLAG_HF;
+ else
+ onenand_flags &= ~ONENAND_FLAG_HF;
+ if (gpmc_clk_ns < 12) /* >83Mhz */
+ onenand_flags |= ONENAND_FLAG_VHF;
+ else
+ onenand_flags &= ~ONENAND_FLAG_VHF;
+ if (onenand_flags & ONENAND_FLAG_VHF)
+ latency = 8;
+ else if (onenand_flags & ONENAND_FLAG_HF)
latency = 6;
else if (gpmc_clk_ns >= 25) /* 40 MHz*/
latency = 3;
else
latency = 4;
- if (first_time)
- set_onenand_cfg(onenand_base, latency,
- sync_read, sync_write, hf);
-
- if (div == 1) {
- reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
- reg |= (1 << 7);
- gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
- reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
- reg |= (1 << 7);
- gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
- reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
- reg |= (1 << 7);
- reg |= (1 << 23);
- gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+ /* Set synchronous read timings */
+ memset(&dev_t, 0, sizeof(dev_t));
+
+ if (onenand_flags & ONENAND_FLAG_SYNCREAD)
+ onenand_sync.sync_read = true;
+ if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
+ onenand_sync.sync_write = true;
+ onenand_sync.burst_write = true;
} else {
- reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
- reg &= ~(1 << 7);
- gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
- reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
- reg &= ~(1 << 7);
- gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
- reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
- reg &= ~(1 << 7);
- reg &= ~(1 << 23);
- gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+ dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
+ dev_t.t_wpl = t_wpl * 1000;
+ dev_t.t_wph = t_wph * 1000;
+ dev_t.t_aavdh = t_aavdh * 1000;
}
+ dev_t.ce_xdelay = true;
+ dev_t.avd_xdelay = true;
+ dev_t.oe_xdelay = true;
+ dev_t.we_xdelay = true;
+ dev_t.clk = min_gpmc_clk_period;
+ dev_t.t_bacc = dev_t.clk;
+ dev_t.t_ces = t_ces * 1000;
+ dev_t.t_avds = t_avds * 1000;
+ dev_t.t_avdh = t_avdh * 1000;
+ dev_t.t_ach = t_ach * 1000;
+ dev_t.cyc_iaa = (latency + 1);
+ dev_t.t_cez_r = t_cez * 1000;
+ dev_t.t_cez_w = dev_t.t_cez_r;
+ dev_t.cyc_aavdh_oe = 1;
+ dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
+
+ gpmc_calc_timings(t, &onenand_sync, &dev_t);
+}
- /* Set synchronous read timings */
- memset(&t, 0, sizeof(t));
- t.sync_clk = min_gpmc_clk_period;
- t.cs_on = 0;
- t.adv_on = 0;
- fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
- fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
- t.page_burst_access = gpmc_clk_ns;
-
- /* Read */
- t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
- t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
- t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
- t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
- t.cs_rd_off = t.oe_off;
- ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
- t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
- ticks_cez);
-
- /* Write */
- if (sync_write) {
- t.adv_wr_off = t.adv_rd_off;
- t.we_on = 0;
- t.we_off = t.cs_rd_off;
- t.cs_wr_off = t.cs_rd_off;
- t.wr_cycle = t.rd_cycle;
- if (cpu_is_omap34xx()) {
- t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
- gpmc_ns_to_ticks(min_gpmc_clk_period +
- t_rdyo));
- t.wr_access = t.access;
+static int omap2_onenand_setup_async(void __iomem *onenand_base)
+{
+ struct gpmc_timings t;
+ int ret;
+
+ if (gpmc_onenand_data->of_node) {
+ gpmc_read_settings_dt(gpmc_onenand_data->of_node,
+ &onenand_async);
+ if (onenand_async.sync_read || onenand_async.sync_write) {
+ if (onenand_async.sync_write)
+ gpmc_onenand_data->flags |=
+ ONENAND_SYNC_READWRITE;
+ else
+ gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
+ onenand_async.sync_read = false;
+ onenand_async.sync_write = false;
}
+ }
+
+ omap2_onenand_set_async_mode(onenand_base);
+
+ omap2_onenand_calc_async_timings(&t);
+
+ ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
+ if (ret < 0)
+ return ret;
+
+ ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
+ if (ret < 0)
+ return ret;
+
+ omap2_onenand_set_async_mode(onenand_base);
+
+ return 0;
+}
+
+static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
+{
+ int ret, freq = *freq_ptr;
+ struct gpmc_timings t;
+
+ if (!freq) {
+ /* Very first call freq is not known */
+ freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
+ set_onenand_cfg(onenand_base);
+ }
+
+ if (gpmc_onenand_data->of_node) {
+ gpmc_read_settings_dt(gpmc_onenand_data->of_node,
+ &onenand_sync);
} else {
- t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int,
- t_avdp, t_cer));
- t.we_on = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
- t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
- t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
- t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
- if (cpu_is_omap34xx()) {
- t.wr_data_mux_bus = t.we_on;
- t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
- }
+ /*
+ * FIXME: Appears to be legacy code from initial ONENAND commit.
+ * Unclear what boards this is for and if this can be removed.
+ */
+ if (!cpu_is_omap34xx())
+ onenand_sync.wait_on_read = true;
}
- /* Configure GPMC for synchronous read */
- gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
- GPMC_CONFIG1_WRAPBURST_SUPP |
- GPMC_CONFIG1_READMULTIPLE_SUPP |
- (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
- (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
- (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
- GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
- GPMC_CONFIG1_PAGE_LEN(2) |
- (cpu_is_omap34xx() ? 0 :
- (GPMC_CONFIG1_WAIT_READ_MON |
- GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
- GPMC_CONFIG1_DEVICESIZE_16 |
- GPMC_CONFIG1_DEVICETYPE_NOR |
- GPMC_CONFIG1_MUXADDDATA);
-
- err = gpmc_cs_set_timings(cs, &t);
- if (err)
- return err;
-
- set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf);
+ omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq);
+
+ ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_sync);
+ if (ret < 0)
+ return ret;
+
+ ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
+ if (ret < 0)
+ return ret;
+
+ set_onenand_cfg(onenand_base);
+
+ *freq_ptr = freq;
return 0;
}
-static int gpmc_onenand_setup(void __iomem *onenand_base, int freq)
+static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
{
struct device *dev = &gpmc_onenand_device.dev;
+ unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
+ int ret;
- /* Set sync timings in GPMC */
- if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base,
- freq) < 0) {
- dev_err(dev, "Unable to set synchronous mode\n");
- return -EINVAL;
+ ret = omap2_onenand_setup_async(onenand_base);
+ if (ret) {
+ dev_err(dev, "unable to set to async mode\n");
+ return ret;
}
- return 0;
+ if (!(gpmc_onenand_data->flags & l))
+ return 0;
+
+ ret = omap2_onenand_setup_sync(onenand_base, freq_ptr);
+ if (ret)
+ dev_err(dev, "unable to set to sync mode\n");
+ 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;
+ struct device *dev = &gpmc_onenand_device.dev;
+
gpmc_onenand_data = _onenand_data;
gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
if (cpu_is_omap24xx() &&
(gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
- printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
+ dev_warn(dev, "OneNAND using only SYNC_READ on 24xx\n");
gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
}
+ if (cpu_is_omap34xx())
+ gpmc_onenand_data->flags |= ONENAND_IN_OMAP34XX;
+ else
+ gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;
+
+ err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
+ (unsigned long *)&gpmc_onenand_resource.start);
+ if (err < 0) {
+ dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
+ gpmc_onenand_data->cs, err);
+ return;
+ }
+
+ gpmc_onenand_resource.end = gpmc_onenand_resource.start +
+ ONENAND_IO_SIZE - 1;
+
if (platform_device_register(&gpmc_onenand_device) < 0) {
- printk(KERN_ERR "Unable to register OneNAND device\n");
+ dev_err(dev, "Unable to register OneNAND device\n");
+ gpmc_cs_free(gpmc_onenand_data->cs);
return;
}
}