]>
Commit | Line | Data |
---|---|---|
54d33c4c | 1 | /* |
54d33c4c MR |
2 | * Copyright (C) 2006 Compulab, Ltd. |
3 | * Mike Rapoport <mike@compulab.co.il> | |
4 | * | |
187c5448 | 5 | * Derived from drivers/mtd/nand/h1910.c (removed in v3.10) |
54d33c4c MR |
6 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) |
7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | |
8 | * | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | * Overview: | |
15 | * This is a device driver for the NAND flash device found on the | |
16 | * CM-X270 board. | |
17 | */ | |
18 | ||
d4092d76 | 19 | #include <linux/mtd/rawnand.h> |
54d33c4c | 20 | #include <linux/mtd/partitions.h> |
5a0e3ad6 | 21 | #include <linux/slab.h> |
70eb33d6 | 22 | #include <linux/gpio.h> |
a0e5cc58 | 23 | #include <linux/module.h> |
54d33c4c MR |
24 | |
25 | #include <asm/io.h> | |
26 | #include <asm/irq.h> | |
70eb33d6 | 27 | #include <asm/mach-types.h> |
54d33c4c | 28 | |
b74d1969 | 29 | #include <mach/pxa2xx-regs.h> |
54d33c4c MR |
30 | |
31 | #define GPIO_NAND_CS (11) | |
32 | #define GPIO_NAND_RB (89) | |
33 | ||
54d33c4c MR |
34 | /* MTD structure for CM-X270 board */ |
35 | static struct mtd_info *cmx270_nand_mtd; | |
36 | ||
37 | /* remaped IO address of the device */ | |
38 | static void __iomem *cmx270_nand_io; | |
39 | ||
40 | /* | |
41 | * Define static partitions for flash device | |
42 | */ | |
d4906688 | 43 | static const struct mtd_partition partition_info[] = { |
54d33c4c MR |
44 | [0] = { |
45 | .name = "cmx270-0", | |
46 | .offset = 0, | |
47 | .size = MTDPART_SIZ_FULL | |
48 | } | |
49 | }; | |
50 | #define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) | |
51 | ||
54d33c4c MR |
52 | static u_char cmx270_read_byte(struct mtd_info *mtd) |
53 | { | |
4bd4ebcc | 54 | struct nand_chip *this = mtd_to_nand(mtd); |
54d33c4c MR |
55 | |
56 | return (readl(this->IO_ADDR_R) >> 16); | |
57 | } | |
58 | ||
59 | static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | |
60 | { | |
61 | int i; | |
4bd4ebcc | 62 | struct nand_chip *this = mtd_to_nand(mtd); |
54d33c4c MR |
63 | |
64 | for (i=0; i<len; i++) | |
65 | writel((*buf++ << 16), this->IO_ADDR_W); | |
66 | } | |
67 | ||
68 | static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |
69 | { | |
70 | int i; | |
4bd4ebcc | 71 | struct nand_chip *this = mtd_to_nand(mtd); |
54d33c4c MR |
72 | |
73 | for (i=0; i<len; i++) | |
74 | *buf++ = readl(this->IO_ADDR_R) >> 16; | |
75 | } | |
76 | ||
54d33c4c MR |
77 | static inline void nand_cs_on(void) |
78 | { | |
70eb33d6 | 79 | gpio_set_value(GPIO_NAND_CS, 0); |
54d33c4c MR |
80 | } |
81 | ||
82 | static void nand_cs_off(void) | |
83 | { | |
70eb33d6 | 84 | dsb(); |
54d33c4c | 85 | |
70eb33d6 | 86 | gpio_set_value(GPIO_NAND_CS, 1); |
54d33c4c MR |
87 | } |
88 | ||
89 | /* | |
90 | * hardware specific access to control-lines | |
91 | */ | |
92 | static void cmx270_hwcontrol(struct mtd_info *mtd, int dat, | |
93 | unsigned int ctrl) | |
94 | { | |
4bd4ebcc | 95 | struct nand_chip *this = mtd_to_nand(mtd); |
54d33c4c MR |
96 | unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; |
97 | ||
70eb33d6 | 98 | dsb(); |
54d33c4c MR |
99 | |
100 | if (ctrl & NAND_CTRL_CHANGE) { | |
101 | if ( ctrl & NAND_ALE ) | |
102 | nandaddr |= (1 << 3); | |
103 | else | |
104 | nandaddr &= ~(1 << 3); | |
105 | if ( ctrl & NAND_CLE ) | |
106 | nandaddr |= (1 << 2); | |
107 | else | |
108 | nandaddr &= ~(1 << 2); | |
109 | if ( ctrl & NAND_NCE ) | |
110 | nand_cs_on(); | |
111 | else | |
112 | nand_cs_off(); | |
113 | } | |
114 | ||
70eb33d6 | 115 | dsb(); |
54d33c4c MR |
116 | this->IO_ADDR_W = (void __iomem*)nandaddr; |
117 | if (dat != NAND_CMD_NONE) | |
118 | writel((dat << 16), this->IO_ADDR_W); | |
119 | ||
70eb33d6 | 120 | dsb(); |
54d33c4c MR |
121 | } |
122 | ||
123 | /* | |
124 | * read device ready pin | |
125 | */ | |
126 | static int cmx270_device_ready(struct mtd_info *mtd) | |
127 | { | |
70eb33d6 | 128 | dsb(); |
54d33c4c | 129 | |
70eb33d6 | 130 | return (gpio_get_value(GPIO_NAND_RB)); |
54d33c4c MR |
131 | } |
132 | ||
133 | /* | |
134 | * Main initialization routine | |
135 | */ | |
627df23c | 136 | static int __init cmx270_init(void) |
54d33c4c MR |
137 | { |
138 | struct nand_chip *this; | |
54d33c4c MR |
139 | int ret; |
140 | ||
a7f3f030 | 141 | if (!(machine_is_armcore() && cpu_is_pxa27x())) |
70eb33d6 MR |
142 | return -ENODEV; |
143 | ||
144 | ret = gpio_request(GPIO_NAND_CS, "NAND CS"); | |
145 | if (ret) { | |
e8348dc5 | 146 | pr_warn("CM-X270: failed to request NAND CS gpio\n"); |
70eb33d6 MR |
147 | return ret; |
148 | } | |
149 | ||
150 | gpio_direction_output(GPIO_NAND_CS, 1); | |
151 | ||
152 | ret = gpio_request(GPIO_NAND_RB, "NAND R/B"); | |
153 | if (ret) { | |
e8348dc5 | 154 | pr_warn("CM-X270: failed to request NAND R/B gpio\n"); |
70eb33d6 MR |
155 | goto err_gpio_request; |
156 | } | |
157 | ||
158 | gpio_direction_input(GPIO_NAND_RB); | |
159 | ||
54d33c4c | 160 | /* Allocate memory for MTD device structure and private data */ |
2afd14f9 BB |
161 | this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); |
162 | if (!this) { | |
70eb33d6 MR |
163 | ret = -ENOMEM; |
164 | goto err_kzalloc; | |
54d33c4c MR |
165 | } |
166 | ||
167 | cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12); | |
168 | if (!cmx270_nand_io) { | |
70eb33d6 | 169 | pr_debug("Unable to ioremap NAND device\n"); |
54d33c4c | 170 | ret = -EINVAL; |
70eb33d6 | 171 | goto err_ioremap; |
54d33c4c MR |
172 | } |
173 | ||
2afd14f9 | 174 | cmx270_nand_mtd = nand_to_mtd(this); |
54d33c4c MR |
175 | |
176 | /* Link the private data with the MTD structure */ | |
177 | cmx270_nand_mtd->owner = THIS_MODULE; | |
54d33c4c MR |
178 | |
179 | /* insert callbacks */ | |
180 | this->IO_ADDR_R = cmx270_nand_io; | |
181 | this->IO_ADDR_W = cmx270_nand_io; | |
182 | this->cmd_ctrl = cmx270_hwcontrol; | |
183 | this->dev_ready = cmx270_device_ready; | |
184 | ||
185 | /* 15 us command delay time */ | |
186 | this->chip_delay = 20; | |
187 | this->ecc.mode = NAND_ECC_SOFT; | |
d9944e1f | 188 | this->ecc.algo = NAND_ECC_HAMMING; |
54d33c4c MR |
189 | |
190 | /* read/write functions */ | |
191 | this->read_byte = cmx270_read_byte; | |
192 | this->read_buf = cmx270_read_buf; | |
193 | this->write_buf = cmx270_write_buf; | |
54d33c4c MR |
194 | |
195 | /* Scan to find existence of the device */ | |
546fe03f MY |
196 | ret = nand_scan(cmx270_nand_mtd, 1); |
197 | if (ret) { | |
70eb33d6 | 198 | pr_notice("No NAND device\n"); |
70eb33d6 | 199 | goto err_scan; |
54d33c4c MR |
200 | } |
201 | ||
54d33c4c | 202 | /* Register the partitions */ |
42d7fbe2 | 203 | ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL, |
0b118f06 | 204 | partition_info, NUM_PARTITIONS); |
54d33c4c | 205 | if (ret) |
70eb33d6 | 206 | goto err_scan; |
54d33c4c MR |
207 | |
208 | /* Return happy */ | |
209 | return 0; | |
210 | ||
70eb33d6 | 211 | err_scan: |
54d33c4c | 212 | iounmap(cmx270_nand_io); |
70eb33d6 | 213 | err_ioremap: |
2afd14f9 | 214 | kfree(this); |
70eb33d6 MR |
215 | err_kzalloc: |
216 | gpio_free(GPIO_NAND_RB); | |
217 | err_gpio_request: | |
218 | gpio_free(GPIO_NAND_CS); | |
54d33c4c MR |
219 | |
220 | return ret; | |
221 | ||
222 | } | |
223 | module_init(cmx270_init); | |
224 | ||
225 | /* | |
226 | * Clean up routine | |
227 | */ | |
627df23c | 228 | static void __exit cmx270_cleanup(void) |
54d33c4c MR |
229 | { |
230 | /* Release resources, unregister device */ | |
231 | nand_release(cmx270_nand_mtd); | |
232 | ||
70eb33d6 MR |
233 | gpio_free(GPIO_NAND_RB); |
234 | gpio_free(GPIO_NAND_CS); | |
235 | ||
54d33c4c MR |
236 | iounmap(cmx270_nand_io); |
237 | ||
2afd14f9 | 238 | kfree(mtd_to_nand(cmx270_nand_mtd)); |
54d33c4c MR |
239 | } |
240 | module_exit(cmx270_cleanup); | |
241 | ||
242 | MODULE_LICENSE("GPL"); | |
243 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | |
244 | MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module"); |