Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6
[pandora-kernel.git] / drivers / mtd / nand / w90p910_nand.c
1 /*
2  * Copyright (c) 2009 Nuvoton technology corporation.
3  *
4  * Wan ZongShun <mcuos.com@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation;version 2 of the License.
9  *
10  */
11
12 #include <linux/slab.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/interrupt.h>
16 #include <linux/io.h>
17 #include <linux/platform_device.h>
18 #include <linux/delay.h>
19 #include <linux/clk.h>
20 #include <linux/err.h>
21
22 #include <linux/mtd/mtd.h>
23 #include <linux/mtd/nand.h>
24 #include <linux/mtd/partitions.h>
25
26 #define REG_FMICSR      0x00
27 #define REG_SMCSR       0xa0
28 #define REG_SMISR       0xac
29 #define REG_SMCMD       0xb0
30 #define REG_SMADDR      0xb4
31 #define REG_SMDATA      0xb8
32
33 #define RESET_FMI       0x01
34 #define NAND_EN         0x08
35 #define READYBUSY       (0x01 << 18)
36
37 #define SWRST           0x01
38 #define PSIZE           (0x01 << 3)
39 #define DMARWEN         (0x03 << 1)
40 #define BUSWID          (0x01 << 4)
41 #define ECC4EN          (0x01 << 5)
42 #define WP              (0x01 << 24)
43 #define NANDCS          (0x01 << 25)
44 #define ENDADDR         (0x01 << 31)
45
46 #define read_data_reg(dev)              \
47         __raw_readl((dev)->reg + REG_SMDATA)
48
49 #define write_data_reg(dev, val)        \
50         __raw_writel((val), (dev)->reg + REG_SMDATA)
51
52 #define write_cmd_reg(dev, val)         \
53         __raw_writel((val), (dev)->reg + REG_SMCMD)
54
55 #define write_addr_reg(dev, val)        \
56         __raw_writel((val), (dev)->reg + REG_SMADDR)
57
58 struct w90p910_nand {
59         struct mtd_info mtd;
60         struct nand_chip chip;
61         void __iomem *reg;
62         struct clk *clk;
63         spinlock_t lock;
64 };
65
66 static const struct mtd_partition partitions[] = {
67         {
68          .name = "NAND FS 0",
69          .offset = 0,
70          .size = 8 * 1024 * 1024
71         },
72         {
73          .name = "NAND FS 1",
74          .offset = MTDPART_OFS_APPEND,
75          .size = MTDPART_SIZ_FULL
76         }
77 };
78
79 static unsigned char w90p910_nand_read_byte(struct mtd_info *mtd)
80 {
81         unsigned char ret;
82         struct w90p910_nand *nand;
83
84         nand = container_of(mtd, struct w90p910_nand, mtd);
85
86         ret = (unsigned char)read_data_reg(nand);
87
88         return ret;
89 }
90
91 static void w90p910_nand_read_buf(struct mtd_info *mtd,
92                                                 unsigned char *buf, int len)
93 {
94         int i;
95         struct w90p910_nand *nand;
96
97         nand = container_of(mtd, struct w90p910_nand, mtd);
98
99         for (i = 0; i < len; i++)
100                 buf[i] = (unsigned char)read_data_reg(nand);
101 }
102
103 static void w90p910_nand_write_buf(struct mtd_info *mtd,
104                                         const unsigned char *buf, int len)
105 {
106         int i;
107         struct w90p910_nand *nand;
108
109         nand = container_of(mtd, struct w90p910_nand, mtd);
110
111         for (i = 0; i < len; i++)
112                 write_data_reg(nand, buf[i]);
113 }
114
115 static int w90p910_verify_buf(struct mtd_info *mtd,
116                                         const unsigned char *buf, int len)
117 {
118         int i;
119         struct w90p910_nand *nand;
120
121         nand = container_of(mtd, struct w90p910_nand, mtd);
122
123         for (i = 0; i < len; i++) {
124                 if (buf[i] != (unsigned char)read_data_reg(nand))
125                         return -EFAULT;
126         }
127
128         return 0;
129 }
130
131 static int w90p910_check_rb(struct w90p910_nand *nand)
132 {
133         unsigned int val;
134         spin_lock(&nand->lock);
135         val = __raw_readl(REG_SMISR);
136         val &= READYBUSY;
137         spin_unlock(&nand->lock);
138
139         return val;
140 }
141
142 static int w90p910_nand_devready(struct mtd_info *mtd)
143 {
144         struct w90p910_nand *nand;
145         int ready;
146
147         nand = container_of(mtd, struct w90p910_nand, mtd);
148
149         ready = (w90p910_check_rb(nand)) ? 1 : 0;
150         return ready;
151 }
152
153 static void w90p910_nand_command_lp(struct mtd_info *mtd,
154                         unsigned int command, int column, int page_addr)
155 {
156         register struct nand_chip *chip = mtd->priv;
157         struct w90p910_nand *nand;
158
159         nand = container_of(mtd, struct w90p910_nand, mtd);
160
161         if (command == NAND_CMD_READOOB) {
162                 column += mtd->writesize;
163                 command = NAND_CMD_READ0;
164         }
165
166         write_cmd_reg(nand, command & 0xff);
167
168         if (column != -1 || page_addr != -1) {
169
170                 if (column != -1) {
171                         if (chip->options & NAND_BUSWIDTH_16)
172                                 column >>= 1;
173                         write_addr_reg(nand, column);
174                         write_addr_reg(nand, column >> 8 | ENDADDR);
175                 }
176                 if (page_addr != -1) {
177                         write_addr_reg(nand, page_addr);
178
179                         if (chip->chipsize > (128 << 20)) {
180                                 write_addr_reg(nand, page_addr >> 8);
181                                 write_addr_reg(nand, page_addr >> 16 | ENDADDR);
182                         } else {
183                                 write_addr_reg(nand, page_addr >> 8 | ENDADDR);
184                         }
185                 }
186         }
187
188         switch (command) {
189         case NAND_CMD_CACHEDPROG:
190         case NAND_CMD_PAGEPROG:
191         case NAND_CMD_ERASE1:
192         case NAND_CMD_ERASE2:
193         case NAND_CMD_SEQIN:
194         case NAND_CMD_RNDIN:
195         case NAND_CMD_STATUS:
196         case NAND_CMD_DEPLETE1:
197                 return;
198
199         case NAND_CMD_STATUS_ERROR:
200         case NAND_CMD_STATUS_ERROR0:
201         case NAND_CMD_STATUS_ERROR1:
202         case NAND_CMD_STATUS_ERROR2:
203         case NAND_CMD_STATUS_ERROR3:
204                 udelay(chip->chip_delay);
205                 return;
206
207         case NAND_CMD_RESET:
208                 if (chip->dev_ready)
209                         break;
210                 udelay(chip->chip_delay);
211
212                 write_cmd_reg(nand, NAND_CMD_STATUS);
213                 write_cmd_reg(nand, command);
214
215                 while (!w90p910_check_rb(nand))
216                         ;
217
218                 return;
219
220         case NAND_CMD_RNDOUT:
221                 write_cmd_reg(nand, NAND_CMD_RNDOUTSTART);
222                 return;
223
224         case NAND_CMD_READ0:
225
226                 write_cmd_reg(nand, NAND_CMD_READSTART);
227         default:
228
229                 if (!chip->dev_ready) {
230                         udelay(chip->chip_delay);
231                         return;
232                 }
233         }
234
235         /* Apply this short delay always to ensure that we do wait tWB in
236          * any case on any machine. */
237         ndelay(100);
238
239         while (!chip->dev_ready(mtd))
240                 ;
241 }
242
243
244 static void w90p910_nand_enable(struct w90p910_nand *nand)
245 {
246         unsigned int val;
247         spin_lock(&nand->lock);
248         __raw_writel(RESET_FMI, (nand->reg + REG_FMICSR));
249
250         val = __raw_readl(nand->reg + REG_FMICSR);
251
252         if (!(val & NAND_EN))
253                 __raw_writel(val | NAND_EN, REG_FMICSR);
254
255         val = __raw_readl(nand->reg + REG_SMCSR);
256
257         val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS);
258         val |= WP;
259
260         __raw_writel(val, nand->reg + REG_SMCSR);
261
262         spin_unlock(&nand->lock);
263 }
264
265 static int __devinit w90p910_nand_probe(struct platform_device *pdev)
266 {
267         struct w90p910_nand *w90p910_nand;
268         struct nand_chip *chip;
269         int retval;
270         struct resource *res;
271
272         retval = 0;
273
274         w90p910_nand = kzalloc(sizeof(struct w90p910_nand), GFP_KERNEL);
275         if (!w90p910_nand)
276                 return -ENOMEM;
277         chip = &(w90p910_nand->chip);
278
279         w90p910_nand->mtd.priv  = chip;
280         w90p910_nand->mtd.owner = THIS_MODULE;
281         spin_lock_init(&w90p910_nand->lock);
282
283         w90p910_nand->clk = clk_get(&pdev->dev, NULL);
284         if (IS_ERR(w90p910_nand->clk)) {
285                 retval = -ENOENT;
286                 goto fail1;
287         }
288         clk_enable(w90p910_nand->clk);
289
290         chip->cmdfunc           = w90p910_nand_command_lp;
291         chip->dev_ready         = w90p910_nand_devready;
292         chip->read_byte         = w90p910_nand_read_byte;
293         chip->write_buf         = w90p910_nand_write_buf;
294         chip->read_buf          = w90p910_nand_read_buf;
295         chip->verify_buf        = w90p910_verify_buf;
296         chip->chip_delay        = 50;
297         chip->options           = 0;
298         chip->ecc.mode          = NAND_ECC_SOFT;
299
300         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
301         if (!res) {
302                 retval = -ENXIO;
303                 goto fail1;
304         }
305
306         if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
307                 retval = -EBUSY;
308                 goto fail1;
309         }
310
311         w90p910_nand->reg = ioremap(res->start, resource_size(res));
312         if (!w90p910_nand->reg) {
313                 retval = -ENOMEM;
314                 goto fail2;
315         }
316
317         w90p910_nand_enable(w90p910_nand);
318
319         if (nand_scan(&(w90p910_nand->mtd), 1)) {
320                 retval = -ENXIO;
321                 goto fail3;
322         }
323
324         add_mtd_partitions(&(w90p910_nand->mtd), partitions,
325                                                 ARRAY_SIZE(partitions));
326
327         platform_set_drvdata(pdev, w90p910_nand);
328
329         return retval;
330
331 fail3:  iounmap(w90p910_nand->reg);
332 fail2:  release_mem_region(res->start, resource_size(res));
333 fail1:  kfree(w90p910_nand);
334         return retval;
335 }
336
337 static int __devexit w90p910_nand_remove(struct platform_device *pdev)
338 {
339         struct w90p910_nand *w90p910_nand = platform_get_drvdata(pdev);
340         struct resource *res;
341
342         iounmap(w90p910_nand->reg);
343
344         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
345         release_mem_region(res->start, resource_size(res));
346
347         clk_disable(w90p910_nand->clk);
348         clk_put(w90p910_nand->clk);
349
350         kfree(w90p910_nand);
351
352         platform_set_drvdata(pdev, NULL);
353
354         return 0;
355 }
356
357 static struct platform_driver w90p910_nand_driver = {
358         .probe          = w90p910_nand_probe,
359         .remove         = __devexit_p(w90p910_nand_remove),
360         .driver         = {
361                 .name   = "w90p910-fmi",
362                 .owner  = THIS_MODULE,
363         },
364 };
365
366 static int __init w90p910_nand_init(void)
367 {
368         return platform_driver_register(&w90p910_nand_driver);
369 }
370
371 static void __exit w90p910_nand_exit(void)
372 {
373         platform_driver_unregister(&w90p910_nand_driver);
374 }
375
376 module_init(w90p910_nand_init);
377 module_exit(w90p910_nand_exit);
378
379 MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
380 MODULE_DESCRIPTION("w90p910 nand driver!");
381 MODULE_LICENSE("GPL");
382 MODULE_ALIAS("platform:w90p910-fmi");