linux/arch/arm/mach-omap2/gpmc-nand.c
Tony Lindgren a1e01703ba Changes for GPMC (General Purpose Memory Controller) that take it
closer for being just a regular device driver.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJQUQu9AAoJEBvUPslcq6Vz8AQQALVhM5PoomGlr4OkTFEc7+xy
 9r1W9NMbD0EX91o5SrdOCSvEaGSV3eKpe2nNGWXNhDwrpDz/Zeci2Ga/ADJdIx+h
 OxbMtx4o9hakSKJAgQAtnc8Ay9Ao5zYcDfMv2kVi8/iQ+CpVnzhZT9HN4rFv0eQF
 +7xhWlni10iqGyAEKVO1FajNZMO7qYdwXNq1XeuDNV3dFV/vOoaCVQbcH/+dyaRQ
 Wqq8BtYuZ3ELu2GiM7rJJMVu/c7AimHjmsXvO4nJ3fkD+izPaqHroNZFyNtHIv0k
 Hc6iWuxN9KnbKXv0Yioc78jDUxumUBToMfniBB9f7S69uKFBFB7FZQjxxje2KTZ8
 HWgUOHWPW3jKM24xfaZhtWtn+swSkSJcZB2DC4shK/nHF2WHH1zaWNVF6NOE/uk0
 nC3cGNOnsSw+jTbl0/CtxBOnpA8RCV3yeW+Fg+iH8v310yrZChtBh6e3ptlHoYl9
 2vZ4xEO2LRBa9MIq5RyLoei+omJFkiugkp75Ln3UrwjbfQyiH0HTWoI9nzkI8HF3
 CiyA7k6aDQ+Qp82L5WEvAh04Z8af2BZSDp6TlC4yEgBXV9Y4ssF8rhHvqBIzv1hC
 d6ohUGdwYQcVfL8xbVUwcbUaTvJcqmxNy20vkhEdqdYMrLWnjy09Nxbl8EJxe6Hh
 zvILFXH7sTIjXBGN3RlN
 =A43b
 -----END PGP SIGNATURE-----
mergetag object cf3a6ec2c0
 type commit
 tag cleanup-omap-tags-for-v3.7
 tagger Tony Lindgren <tony@atomide.com> 1347323254 -0700
 
 Remove the ancient omap specific atags that are no longer needed.
 
 At some point we were planning to pass the bootloader information
 with custom atags that did not work out too well.
 
 There's no need for these any longer as the kernel has been booting
 fine without them for quite some time. And Now we have device tree
 support that can be used instead.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJQToX6AAoJEBvUPslcq6VznGYP/141pkbT7BL112e8zMQrAWRb
 eKCJKw58J+XJZ4BTOCCqDwcGvKn0ZjRaCx7rtBmQVi1Pc7r4hmbPUwn6GSIMUTKY
 BKaCsfQFs1mS/uXXJcWV2JkXuKxooEsEP8KD7ctO5GgjBgTjPIIa45OG7qZMBqKL
 CYrjGRuaXJqtP9OR7Ad3gcbAkfCaYAIxvi+bb7jHHfYYQKJCLPPWno0aSEMRqvAm
 qZmRzc4CIzfBTxTixOvBsxa2MluViUTwtu+p6hpvhKvVO80QjJCL4kgdWk4hiSSe
 hWxHRsnA+aLX9vyuBwEWzDJ3ty0C3gur+F1bJpwtkQR/YUEmgak+pOQbe5WlA6rr
 9oonRue886c3QjyubY5k9uLWWC/wTnnPmztoGdDiWyDA89dJFjHGvK7tngKL/xz+
 cLhT5pHJnWSPiFlEWQbwU3znaA+rzbVbxwyDdIzl6KWyvq+m4rlCLHfv+StoC/4V
 JakoQTANNv3CIXwDpZiO0Ci4UwPzbr6SnUHCpuBauF4LpTIKUWp3wS/Vbl1rk2nr
 5huY48Dq5+itzFT8AoWMe+efjOI+pkKVOiuvdfMcd7qYKaFjqOCeEDOcFSKm7cq8
 gDDFG4BleDSVE69N+VR83+wZqCNtVEEeJiRWdNXmOE3laYbxfy3lJceZ0nejakLI
 hz+gFKrWiULXmQXkZh/J
 =utuw
 -----END PGP SIGNATURE-----

Merge tags 'omap-devel-gpmc-fixed-for-v3.7' and 'cleanup-omap-tags-for-v3.7' into cleanup-sparseirq

Changes for GPMC (General Purpose Memory Controller) that take it
closer for being just a regular device driver.

Remove the ancient omap specific atags that are no longer needed.

At some point we were planning to pass the bootloader information
with custom atags that did not work out too well.

There's no need for these any longer as the kernel has been booting
fine without them for quite some time. And Now we have device tree
support that can be used instead.
2012-09-12 18:05:19 -07:00

141 lines
3.7 KiB
C

/*
* gpmc-nand.c
*
* Copyright (C) 2009 Texas Instruments
* Vimal Singh <vimalsingh@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/mtd/nand.h>
#include <asm/mach/flash.h>
#include <plat/cpu.h>
#include <plat/nand.h>
#include <plat/gpmc.h>
static struct resource gpmc_nand_resource[] = {
{
.flags = IORESOURCE_MEM,
},
{
.flags = IORESOURCE_IRQ,
},
{
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device gpmc_nand_device = {
.name = "omap2-nand",
.id = 0,
.num_resources = ARRAY_SIZE(gpmc_nand_resource),
.resource = gpmc_nand_resource,
};
static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data)
{
struct gpmc_timings t;
int err;
if (!gpmc_nand_data->gpmc_t)
return 0;
memset(&t, 0, sizeof(t));
t.sync_clk = gpmc_nand_data->gpmc_t->sync_clk;
t.cs_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_on);
t.adv_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->adv_on);
/* Read */
t.adv_rd_off = gpmc_round_ns_to_ticks(
gpmc_nand_data->gpmc_t->adv_rd_off);
t.oe_on = t.adv_on;
t.access = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->access);
t.oe_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->oe_off);
t.cs_rd_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_rd_off);
t.rd_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->rd_cycle);
/* Write */
t.adv_wr_off = gpmc_round_ns_to_ticks(
gpmc_nand_data->gpmc_t->adv_wr_off);
t.we_on = t.oe_on;
if (cpu_is_omap34xx()) {
t.wr_data_mux_bus = gpmc_round_ns_to_ticks(
gpmc_nand_data->gpmc_t->wr_data_mux_bus);
t.wr_access = gpmc_round_ns_to_ticks(
gpmc_nand_data->gpmc_t->wr_access);
}
t.we_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->we_off);
t.cs_wr_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_wr_off);
t.wr_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);
/* Configure GPMC */
if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16)
gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 1);
else
gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0);
gpmc_cs_configure(gpmc_nand_data->cs,
GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND);
gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0);
err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
if (err)
return err;
return 0;
}
int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data)
{
int err = 0;
struct device *dev = &gpmc_nand_device.dev;
gpmc_nand_device.dev.platform_data = gpmc_nand_data;
err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
(unsigned long *)&gpmc_nand_resource[0].start);
if (err < 0) {
dev_err(dev, "Cannot request GPMC CS\n");
return err;
}
gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
NAND_IO_SIZE - 1;
gpmc_nand_resource[1].start =
gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
gpmc_nand_resource[2].start =
gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
/* Set timings in GPMC */
err = omap2_nand_gpmc_retime(gpmc_nand_data);
if (err < 0) {
dev_err(dev, "Unable to set gpmc timings: %d\n", err);
return err;
}
/* Enable RD PIN Monitoring Reg */
if (gpmc_nand_data->dev_ready) {
gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1);
}
gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
err = platform_device_register(&gpmc_nand_device);
if (err < 0) {
dev_err(dev, "Unable to register NAND device\n");
goto out_free_cs;
}
return 0;
out_free_cs:
gpmc_cs_free(gpmc_nand_data->cs);
return err;
}