Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
[pandora-kernel.git] / arch / arm / mach-omap2 / gpmc-nand.c
1 /*
2  * gpmc-nand.c
3  *
4  * Copyright (C) 2009 Texas Instruments
5  * Vimal Singh <vimalsingh@ti.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/platform_device.h>
14 #include <linux/io.h>
15
16 #include <asm/mach/flash.h>
17
18 #include <plat/nand.h>
19 #include <plat/board.h>
20 #include <plat/gpmc.h>
21
22 #define WR_RD_PIN_MONITORING    0x00600000
23
24 static struct omap_nand_platform_data *gpmc_nand_data;
25
26 static struct resource gpmc_nand_resource = {
27         .flags          = IORESOURCE_MEM,
28 };
29
30 static struct platform_device gpmc_nand_device = {
31         .name           = "omap2-nand",
32         .id             = 0,
33         .num_resources  = 1,
34         .resource       = &gpmc_nand_resource,
35 };
36
37 static int omap2_nand_gpmc_retime(void)
38 {
39         struct gpmc_timings t;
40         int err;
41
42         if (!gpmc_nand_data->gpmc_t)
43                 return 0;
44
45         memset(&t, 0, sizeof(t));
46         t.sync_clk = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->sync_clk);
47         t.cs_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_on);
48         t.adv_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->adv_on);
49
50         /* Read */
51         t.adv_rd_off = gpmc_round_ns_to_ticks(
52                                 gpmc_nand_data->gpmc_t->adv_rd_off);
53         t.oe_on  = t.adv_on;
54         t.access = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->access);
55         t.oe_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->oe_off);
56         t.cs_rd_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_rd_off);
57         t.rd_cycle  = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->rd_cycle);
58
59         /* Write */
60         t.adv_wr_off = gpmc_round_ns_to_ticks(
61                                 gpmc_nand_data->gpmc_t->adv_wr_off);
62         t.we_on  = t.oe_on;
63         if (cpu_is_omap34xx()) {
64             t.wr_data_mux_bus = gpmc_round_ns_to_ticks(
65                                 gpmc_nand_data->gpmc_t->wr_data_mux_bus);
66             t.wr_access = gpmc_round_ns_to_ticks(
67                                 gpmc_nand_data->gpmc_t->wr_access);
68         }
69         t.we_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->we_off);
70         t.cs_wr_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_wr_off);
71         t.wr_cycle  = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);
72
73         /* Configure GPMC */
74         gpmc_cs_write_reg(gpmc_nand_data->cs, GPMC_CS_CONFIG1,
75                         GPMC_CONFIG1_DEVICESIZE(gpmc_nand_data->devsize) |
76                         GPMC_CONFIG1_DEVICETYPE_NAND);
77
78         err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
79         if (err)
80                 return err;
81
82         return 0;
83 }
84
85 static int gpmc_nand_setup(void)
86 {
87         struct device *dev = &gpmc_nand_device.dev;
88
89         /* Set timings in GPMC */
90         if (omap2_nand_gpmc_retime() < 0) {
91                 dev_err(dev, "Unable to set gpmc timings\n");
92                 return -EINVAL;
93         }
94
95         return 0;
96 }
97
98 int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
99 {
100         unsigned int val;
101         int err = 0;
102         struct device *dev = &gpmc_nand_device.dev;
103
104         gpmc_nand_data = _nand_data;
105         gpmc_nand_data->nand_setup = gpmc_nand_setup;
106         gpmc_nand_device.dev.platform_data = gpmc_nand_data;
107
108         err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
109                                 &gpmc_nand_data->phys_base);
110         if (err < 0) {
111                 dev_err(dev, "Cannot request GPMC CS\n");
112                 return err;
113         }
114
115         err = gpmc_nand_setup();
116         if (err < 0) {
117                 dev_err(dev, "NAND platform setup failed: %d\n", err);
118                 return err;
119         }
120
121         /* Enable RD PIN Monitoring Reg */
122         if (gpmc_nand_data->dev_ready) {
123                 val  = gpmc_cs_read_reg(gpmc_nand_data->cs,
124                                                  GPMC_CS_CONFIG1);
125                 val |= WR_RD_PIN_MONITORING;
126                 gpmc_cs_write_reg(gpmc_nand_data->cs,
127                                                 GPMC_CS_CONFIG1, val);
128         }
129
130         err = platform_device_register(&gpmc_nand_device);
131         if (err < 0) {
132                 dev_err(dev, "Unable to register NAND device\n");
133                 goto out_free_cs;
134         }
135
136         return 0;
137
138 out_free_cs:
139         gpmc_cs_free(gpmc_nand_data->cs);
140
141         return err;
142 }