gpmc-nand.c 3.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
/*
 * 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 <asm/mach/flash.h>

#include <plat/nand.h>
#include <plat/board.h>
#include <plat/gpmc.h>

#define WR_RD_PIN_MONITORING	0x00600000

static struct omap_nand_platform_data *gpmc_nand_data;

static struct resource gpmc_nand_resource = {
	.flags		= IORESOURCE_MEM,
};

static struct platform_device gpmc_nand_device = {
	.name		= "omap2-nand",
	.id		= 0,
	.num_resources	= 1,
	.resource	= &gpmc_nand_resource,
};

static int omap2_nand_gpmc_retime(void)
{
	struct gpmc_timings t;
	int err;

S
stanley.miao 已提交
42 43 44
	if (!gpmc_nand_data->gpmc_t)
		return 0;

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	memset(&t, 0, sizeof(t));
	t.sync_clk = gpmc_round_ns_to_ticks(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 */
	gpmc_cs_write_reg(gpmc_nand_data->cs, GPMC_CS_CONFIG1,
			GPMC_CONFIG1_DEVICESIZE(gpmc_nand_data->devsize) |
			GPMC_CONFIG1_DEVICETYPE_NAND);

	err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
	if (err)
		return err;

	return 0;
}

static int gpmc_nand_setup(void)
{
	struct device *dev = &gpmc_nand_device.dev;

	/* Set timings in GPMC */
	if (omap2_nand_gpmc_retime() < 0) {
		dev_err(dev, "Unable to set gpmc timings\n");
		return -EINVAL;
	}

	return 0;
}

int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
{
	unsigned int val;
	int err	= 0;
	struct device *dev = &gpmc_nand_device.dev;

	gpmc_nand_data = _nand_data;
	gpmc_nand_data->nand_setup = gpmc_nand_setup;
	gpmc_nand_device.dev.platform_data = gpmc_nand_data;

	err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
				&gpmc_nand_data->phys_base);
	if (err < 0) {
		dev_err(dev, "Cannot request GPMC CS\n");
		return err;
	}

	err = gpmc_nand_setup();
	if (err < 0) {
		dev_err(dev, "NAND platform setup failed: %d\n", err);
		return err;
	}

	/* Enable RD PIN Monitoring Reg */
	if (gpmc_nand_data->dev_ready) {
		val  = gpmc_cs_read_reg(gpmc_nand_data->cs,
						 GPMC_CS_CONFIG1);
		val |= WR_RD_PIN_MONITORING;
		gpmc_cs_write_reg(gpmc_nand_data->cs,
						GPMC_CS_CONFIG1, val);
	}

	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;
}