ARM64: DTS: Add rk3399-firefly uart4 device, node as /dev/ttyS1
[firefly-linux-kernel-4.4.55.git] / drivers / mtd / rknand / rknand_base_ko.c
1 /*\r
2  *  linux/drivers/mtd/rknand/rknand_base.c\r
3  *\r
4  *  Copyright (C) 2005-2009 Fuzhou Rockchip Electronics\r
5  *  ZYF <zyf@rock-chips.com>\r
6  *\r
7  *   \r
8  */\r
9 #include <linux/version.h>\r
10 #include <linux/module.h>\r
11 #include <linux/sched.h>\r
12 #include <linux/delay.h>\r
13 #include <linux/init.h>\r
14 #include <linux/slab.h>\r
15 #include <linux/platform_device.h>\r
16 #include <linux/mtd/mtd.h>\r
17 #include <linux/mtd/mtd.h>\r
18 #include <linux/mtd/partitions.h>\r
19 #include <linux/mutex.h>\r
20 #include <linux/kthread.h>\r
21 #include <linux/dma-mapping.h>\r
22 #include <asm/dma.h>\r
23 #include <asm/cacheflush.h>\r
24 #include <linux/irq.h>\r
25 #include <linux/interrupt.h>\r
26 #include <linux/reboot.h>\r
27 #include <asm/io.h>\r
28 #include <asm/mach/flash.h>\r
29 //#include "api_flash.h"\r
30 #include "rknand_base.h"\r
31 #include "../mtdcore.h"\r
32 #include <linux/clk.h>\r
33 #include <linux/cpufreq.h>\r
34 #ifdef CONFIG_OF\r
35 #include <linux/of.h>\r
36 #endif\r
37 \r
38 #define DRIVER_NAME     "rk29xxnand"\r
39 \r
40 const char rknand_base_version[] = "rknand_base.c version: 4.38 20120717";\r
41 #define NAND_DEBUG_LEVEL0 0\r
42 #define NAND_DEBUG_LEVEL1 1\r
43 #define NAND_DEBUG_LEVEL2 2\r
44 #define NAND_DEBUG_LEVEL3 3\r
45 \r
46 int g_num_partitions = 0;\r
47 unsigned long SysImageWriteEndAdd = 0;\r
48 struct mtd_info         rknand_mtd;  \r
49 struct mtd_partition *rknand_parts;\r
50 struct rknand_info * gpNandInfo;\r
51 \r
52 #ifdef CONFIG_MTD_NAND_RK29XX_DEBUG\r
53 static int s_debug = CONFIG_MTD_NAND_RK29XX_DEBUG_VERBOSE;\r
54 #undef NAND_DEBUG\r
55 #define NAND_DEBUG(n, format, arg...) \\r
56         if (n <= s_debug) {      \\r
57                 printk(format,##arg); \\r
58         }\r
59 #else\r
60 #undef NAND_DEBUG\r
61 #define NAND_DEBUG(n, arg...)\r
62 static const int s_debug = 0;\r
63 #endif\r
64 \r
65 #include <linux/proc_fs.h>\r
66 #include <linux/version.h>\r
67 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))\r
68 #define NANDPROC_ROOT  (&proc_root)\r
69 #else\r
70 #define NANDPROC_ROOT  NULL\r
71 #endif\r
72 \r
73 //#define RKNAND_TRAC_EN\r
74 #ifdef RKNAND_TRAC_EN\r
75 static struct proc_dir_entry *my_trac_proc_entry;\r
76 #define MAX_TRAC_BUFFER_SIZE     (long)(2048 * 8 * 512) //sector\r
77 static char grknand_trac_buf[MAX_TRAC_BUFFER_SIZE];\r
78 static char *ptrac_buf = grknand_trac_buf;\r
79 void trac_log(long lba,int len, int mod)\r
80 {\r
81         unsigned long long t;\r
82     unsigned long nanosec_rem;\r
83     t = cpu_clock(UINT_MAX);\r
84     nanosec_rem = do_div(t, 1000000000);\r
85     if(mod)\r
86         ptrac_buf += sprintf(ptrac_buf,"[%5lu.%06lu] W %d %d \n",(unsigned long) t, nanosec_rem / 1000,lba,len);\r
87     else\r
88         ptrac_buf += sprintf(ptrac_buf,"[%5lu.%06lu] R %d %d \n",(unsigned long) t, nanosec_rem / 1000,lba,len);\r
89 }\r
90 \r
91 void trac_logs(char *s)\r
92 {\r
93         unsigned long long t;\r
94     unsigned long nanosec_rem;\r
95     t = cpu_clock(UINT_MAX);\r
96     nanosec_rem = do_div(t, 1000000000);\r
97         ptrac_buf += sprintf(ptrac_buf,"[%5lu.%06lu] %s\n",(unsigned long) t, nanosec_rem / 1000,s);\r
98 }\r
99 \r
100 static int rkNand_trac_read(char *page, char **start, off_t off, int count, int *eof,\r
101                     void *data)\r
102 {\r
103         char *p = page;\r
104         int len;\r
105 \r
106          len = ptrac_buf - grknand_trac_buf - off;\r
107      //printk("rkNand_trac_read: page=%x,off=%x,count=%x ,len=%x \n",(int)page,(int)off,count,len);\r
108 \r
109         if (len < 0)\r
110                 len = 0;\r
111                 \r
112          if(len > count)\r
113             len = count;\r
114 \r
115          memcpy(p,grknand_trac_buf + off,len);\r
116 \r
117         *eof = (len <  count) ? 1 : 0;\r
118         *start = page;\r
119         if(len < count)\r
120         ptrac_buf = grknand_trac_buf;\r
121         return len;\r
122 }\r
123 \r
124 #endif\r
125 \r
126 #define     DATA_LEN            (1024*8*2/4)              //Êý¾Ý¿éµ¥Î»word\r
127 #define     SPARE_LEN           (32*8*2/4)               //УÑéÊý¾Ý³¤¶È\r
128 #define     PAGE_LEN            (DATA_LEN+SPARE_LEN)    //ÿ¸öÊý¾Ýµ¥Î»µÄ³¤¶È\r
129 #define     MAX_BUFFER_SIZE     (long)(2048 * 8) //sector\r
130 //long grknand_buf[MAX_BUFFER_SIZE * 512/4] __attribute__((aligned(4096)));\r
131 //long grknand_dma_buf[PAGE_LEN*4*5] __attribute__((aligned(4096)));\r
132 static struct proc_dir_entry *my_proc_entry;\r
133 extern int rkNand_proc_ftlread(char *page);\r
134 extern int rkNand_proc_bufread(char *page);\r
135 static int rkNand_proc_read(char *page,\r
136                            char **start,\r
137                            off_t offset, int count, int *eof, void *data)\r
138 {\r
139         char *buf = page;\r
140         int step = offset;\r
141         *(int *)start = 1;\r
142         if(step == 0)\r
143         {\r
144         buf += sprintf(buf, "%s\n", rknand_base_version);\r
145         if(gpNandInfo->proc_ftlread)\r
146             buf += gpNandInfo->proc_ftlread(buf);\r
147         if(gpNandInfo->proc_bufread)\r
148             buf += gpNandInfo->proc_bufread(buf);\r
149 #ifdef RKNAND_TRAC_EN\r
150         buf += sprintf(buf, "trac data len:%d\n", ptrac_buf - grknand_trac_buf);\r
151 #endif\r
152     }\r
153         return buf - page < count ? buf - page : count;\r
154 }\r
155 \r
156 #if 0// (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))\r
157 static void rknand_create_procfs(void)\r
158 {\r
159     /* Install the proc_fs entry */\r
160     my_proc_entry = create_proc_entry("rknand",\r
161                            S_IRUGO | S_IFREG,\r
162                            NANDPROC_ROOT);\r
163 \r
164     if (my_proc_entry) {\r
165         my_proc_entry->write_proc = NULL;\r
166         my_proc_entry->read_proc = rkNand_proc_read;\r
167         my_proc_entry->data = NULL;\r
168     } \r
169 #ifdef RKNAND_TRAC_EN\r
170     /* Install the proc_fs entry */\r
171     my_trac_proc_entry = create_proc_entry("rknand_trac",\r
172                            S_IRUGO | S_IFREG,\r
173                            NANDPROC_ROOT);\r
174     if (my_trac_proc_entry) {\r
175         my_trac_proc_entry->write_proc = NULL;\r
176         my_trac_proc_entry->read_proc = rkNand_trac_read;\r
177         my_trac_proc_entry->data = NULL;\r
178     } \r
179 #endif\r
180 }\r
181 #else\r
182 static const struct file_operations my_proc_fops = {\r
183 .owner = THIS_MODULE,\r
184 .read = rkNand_proc_read,\r
185 .write = NULL,\r
186 };\r
187 \r
188 static void rknand_create_procfs(void)\r
189 {\r
190     /* Install the proc_fs entry */\r
191     my_proc_entry = proc_create("rknand",\r
192                            S_IRUGO | S_IFREG,\r
193                            NANDPROC_ROOT,&my_proc_fops);\r
194 }\r
195 #endif\r
196 void printk_write_log(long lba,int len, const u_char *pbuf)\r
197 {\r
198     char debug_buf[100];\r
199     int i;\r
200     for(i=0;i<len;i++)\r
201     {\r
202         sprintf(debug_buf,"%lx :",lba+i);\r
203         print_hex_dump(KERN_WARNING, debug_buf, DUMP_PREFIX_NONE, 16,4, &pbuf[512*i], 8, 0);\r
204     }\r
205 }\r
206 \r
207 static int rknand_read(struct mtd_info *mtd, loff_t from, size_t len,\r
208         size_t *retlen, u_char *buf)\r
209 {\r
210         int ret = 0;\r
211         int sector = len>>9;\r
212         int LBA = (int)(from>>9);\r
213 #ifdef RKNAND_TRAC_EN\r
214     //trac_log(LBA,sector,0);\r
215 #endif\r
216         //printk("R %d %d \n",(int)LBA,sector);\r
217         //if(rknand_debug)\r
218     //   printk("rk28xxnand_read: from=%x,sector=%x,\n",(int)LBA,sector);\r
219     if(sector && gpNandInfo->ftl_read)\r
220     {\r
221                 ret = gpNandInfo->ftl_read(LBA, sector, buf);\r
222                 if(ret)\r
223                    *retlen = 0;\r
224     }\r
225         return ret;\r
226 }\r
227 \r
228 static int rknand_write(struct mtd_info *mtd, loff_t from, size_t len,\r
229         size_t *retlen, const u_char *buf)\r
230 {\r
231         int ret = 0;\r
232         int sector = len>>9;\r
233         int LBA = (int)(from>>9);\r
234 #ifdef RKNAND_TRAC_EN\r
235     trac_log(LBA,sector,1);\r
236 #endif\r
237         //printk("W %d %d \n",(int)LBA,sector);\r
238     //return 0;\r
239         //printk("*");\r
240         //if(rknand_debug)\r
241     //    printk(KERN_NOTICE "write: from=%lx,sector=%x\n",(int)LBA,sector);\r
242     //printk_write_log(LBA,sector,buf);\r
243         if(sector && gpNandInfo->ftl_write)// cmy\r
244         {\r
245                 if(LBA < SysImageWriteEndAdd)//0x4E000)\r
246                 {\r
247                         //NAND_DEBUG(NAND_DEBUG_LEVEL0,">>> FtlWriteImage: LBA=0x%08X  sector=%d\n",LBA, sector);\r
248             ret = gpNandInfo->ftl_write(LBA, sector, (void *)buf,1);\r
249         }\r
250                 else\r
251         {\r
252             ret = gpNandInfo->ftl_write(LBA, sector, (void *)buf,0);\r
253         }\r
254         }\r
255         *retlen = len;\r
256         return 0;\r
257 }\r
258 \r
259 static int rknand_diacard(struct mtd_info *mtd, loff_t from, size_t len)\r
260 {\r
261         int ret = 0;\r
262         int sector = len>>9;\r
263         int LBA = (int)(from>>9);\r
264         //printk("rknand_diacard: from=%x,sector=%x,\n",(int)LBA,sector);\r
265     if(sector && gpNandInfo->ftl_discard)\r
266     {\r
267                 ret = gpNandInfo->ftl_discard(LBA, sector);\r
268     }\r
269         return ret;\r
270 }\r
271 \r
272 static int rknand_erase(struct mtd_info *mtd, struct erase_info *instr)\r
273 {\r
274         int ret = 0;\r
275     if (instr->callback)\r
276                 instr->callback(instr);\r
277         return ret;\r
278 }\r
279 \r
280 static void rknand_sync(struct mtd_info *mtd)\r
281 {\r
282         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk_nand_sync: \n");\r
283     if(gpNandInfo->ftl_sync)\r
284         gpNandInfo->ftl_sync();\r
285 }\r
286 \r
287 extern void FtlWriteCacheEn(int);\r
288 static int rknand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)\r
289 {\r
290         int sector = len >> 9;\r
291         int LBA = (int)(to >> 9);\r
292 \r
293         if (sector && gpNandInfo->ftl_write_panic) {\r
294             if(gpNandInfo->ftl_cache_en)\r
295                     gpNandInfo->ftl_cache_en(0);\r
296                 gpNandInfo->ftl_write_panic(LBA, sector, (void *)buf);\r
297             if(gpNandInfo->ftl_cache_en)\r
298                     gpNandInfo->ftl_cache_en(1);\r
299         }\r
300         *retlen = len;\r
301         return 0;\r
302 }\r
303 \r
304 \r
305 int GetIdBlockSysData(char * buf, int Sector)\r
306 {\r
307     if(gpNandInfo->GetIdBlockSysData)\r
308            return( gpNandInfo->GetIdBlockSysData( buf,  Sector));\r
309     return 0;\r
310 }\r
311 \r
312 char GetSNSectorInfoBeforeNandInit(char * pbuf)\r
313 {\r
314     char * sn_addr = ioremap(0x10501600,0x200);\r
315     memcpy(pbuf,sn_addr,0x200);\r
316     iounmap(sn_addr);\r
317         //print_hex_dump(KERN_WARNING, "sn:", DUMP_PREFIX_NONE, 16,1, sn_addr, 16, 0);\r
318     return 0;\r
319\r
320 \r
321 char GetSNSectorInfo(char * pbuf)\r
322 {\r
323     if(gpNandInfo->GetSNSectorInfo)\r
324            return( gpNandInfo->GetSNSectorInfo( pbuf));\r
325         else\r
326            return GetSNSectorInfoBeforeNandInit(pbuf);\r
327     return 0;\r
328 }\r
329 \r
330 \r
331 char GetVendor0InfoBeforeNandInit(char * pbuf)\r
332 {\r
333     char * sn_addr = ioremap(0x10501400,0x200);\r
334     memcpy(pbuf,sn_addr + 8,504);\r
335     iounmap(sn_addr);\r
336         //print_hex_dump(KERN_WARNING, "sn:", DUMP_PREFIX_NONE, 16,1, sn_addr, 16, 0);\r
337     return 0;\r
338\r
339 \r
340 char GetChipSectorInfo(char * pbuf)\r
341 {\r
342     if(gpNandInfo->GetChipSectorInfo)\r
343            return( gpNandInfo->GetChipSectorInfo( pbuf));\r
344     return 0;\r
345 }\r
346 \r
347 int  GetParamterInfo(char * pbuf , int len)\r
348 {\r
349     int ret = -1;\r
350         int sector = (len)>>9;\r
351         int LBA = 0;\r
352         if(sector && gpNandInfo->ftl_read)\r
353         {\r
354                 ret = gpNandInfo->ftl_read(LBA, sector, pbuf);\r
355         }\r
356         return ret?-1:(sector<<9);\r
357 }\r
358 \r
359 int  GetflashDataByLba(int lba,char * pbuf , int len)\r
360 {\r
361     int ret = -1;\r
362         int sector = (len)>>9;\r
363         int LBA = lba;\r
364         if(sector && gpNandInfo->ftl_read)\r
365         {\r
366                 ret = gpNandInfo->ftl_read(LBA, sector, pbuf);\r
367         }\r
368         return ret?-1:(sector<<9);\r
369 }\r
370 \r
371 void rknand_dev_cache_flush(void)\r
372 {\r
373     if(gpNandInfo->rknand_dev_cache_flush)\r
374         gpNandInfo->rknand_dev_cache_flush();\r
375 }\r
376 \r
377 \r
378 static int rknand_block_isbad(struct mtd_info *mtd, loff_t ofs)\r
379 {\r
380         return 0;\r
381 }\r
382 \r
383 static int rknand_block_markbad(struct mtd_info *mtd, loff_t ofs)\r
384 {\r
385         return 0;\r
386 }\r
387 \r
388 \r
389 static struct clk                       *nandc_clk;\r
390 static unsigned long             nandc_clk_rate = 0;\r
391 static struct notifier_block   nandc_freq_transition;\r
392 /* cpufreq driver support */\r
393 static int rknand_nand_timing_cfg(void)\r
394 {\r
395         unsigned long newclk;\r
396         newclk = clk_get_rate(nandc_clk);\r
397         //printk("rknand_nand_timing_cfg %d",newclk);\r
398         if (newclk != nandc_clk_rate) \r
399         {\r
400         if(gpNandInfo->nand_timing_config)\r
401         {\r
402             nandc_clk_rate = newclk;\r
403             //gpNandInfo->nand_timing_config( nandc_clk_rate / 1000); // KHz\r
404         }\r
405         }\r
406         return 0;\r
407 }\r
408 \r
409 static int rknand_info_init(struct rknand_info *nand_info)\r
410 {\r
411         struct mtd_info    *mtd = &rknand_mtd;\r
412         struct rknand_chip *rknand = &nand_info->rknand;  \r
413 \r
414         rknand->state = FL_READY;\r
415         rknand->rknand_schedule_enable = 1;\r
416         rknand->pFlashCallBack = NULL;\r
417         init_waitqueue_head(&rknand->wq);\r
418 \r
419     mtd->oobsize = 0;\r
420     mtd->oobavail = 0;\r
421     mtd->ecclayout = 0;\r
422     mtd->erasesize = 32*0x200;\r
423     mtd->writesize = 8*0x200;\r
424 \r
425         // Fill in remaining MTD driver data \r
426         mtd->type = MTD_NANDFLASH;\r
427         mtd->flags = (MTD_WRITEABLE|MTD_NO_ERASE);//\r
428         mtd->_erase = rknand_erase;\r
429         mtd->_point = NULL;\r
430         mtd->_unpoint = NULL;\r
431         mtd->_read = rknand_read;\r
432         mtd->_write = rknand_write;\r
433         //mtd->discard = rknand_diacard;\r
434         mtd->_read_oob = NULL;\r
435         mtd->_write_oob = NULL;\r
436         mtd->_panic_write = rknand_panic_write;\r
437 \r
438         mtd->_sync = rknand_sync;\r
439         mtd->_lock = NULL;\r
440         mtd->_unlock = NULL;\r
441         mtd->_suspend = NULL;\r
442         mtd->_resume = NULL;\r
443         mtd->_block_isbad = rknand_block_isbad;\r
444         mtd->_block_markbad = rknand_block_markbad;\r
445         mtd->owner = THIS_MODULE;\r
446     return 0;\r
447 }\r
448 \r
449 \r
450 /*\r
451  * CMY: Ôö¼ÓÁ˶ÔÃüÁîÐзÖÇøÐÅÏ¢µÄÖ§³Ö\r
452  *              ÈôcmdlineÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃcmdlineµÄ·ÖÇøÐÅÏ¢½øÐзÖÇø\r
453  *              ÈôcmdlineûÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃĬÈϵķÖÇøÐÅÏ¢(rk28_partition_info)½øÐзÖÇø\r
454  */\r
455 \r
456 #ifdef CONFIG_MTD_CMDLINE_PARTS\r
457 const char *part_probes[] = { "cmdlinepart", NULL }; \r
458 #endif \r
459 \r
460 static int rknand_add_partitions(struct rknand_info *nand_info)\r
461 {\r
462 #ifdef CONFIG_MTD_CMDLINE_PARTS\r
463     int num_partitions = 0; \r
464 \r
465         // ´ÓÃüÁîÐнâÎö·ÖÇøµÄÐÅÏ¢\r
466     num_partitions = parse_mtd_partitions(&(rknand_mtd), part_probes, &rknand_parts, 0); \r
467     NAND_DEBUG(NAND_DEBUG_LEVEL0,"num_partitions = %d\n",num_partitions);\r
468         printk("num_partitions = %d\n",num_partitions);\r
469     if(num_partitions > 0) { \r
470         int i;\r
471         for (i = 0; i < num_partitions; i++) \r
472         {\r
473             rknand_parts[i].offset *= 0x200;\r
474             rknand_parts[i].size   *=0x200;\r
475         }\r
476         rknand_parts[num_partitions - 1].size = rknand_mtd.size - rknand_parts[num_partitions - 1].offset;\r
477         \r
478                 g_num_partitions = num_partitions;\r
479 //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
480 //              return mtd_device_register(&rknand_mtd, rknand_parts, num_partitions);\r
481 //#else\r
482                 return add_mtd_partitions(&(rknand_mtd), rknand_parts, num_partitions);\r
483 //#endif\r
484     } \r
485 #endif \r
486     g_num_partitions = 0;\r
487         return 0;\r
488 }\r
489 \r
490 int add_rknand_device(struct rknand_info * prknand_Info)\r
491 {\r
492     struct mtd_partition *parts;\r
493     int i;\r
494     NAND_DEBUG(NAND_DEBUG_LEVEL0,"add_rknand_device: \n");\r
495     printk("gpNandInfo->nandCapacity = %lx\n",gpNandInfo->nandCapacity);\r
496     rknand_mtd.size = (uint64_t)gpNandInfo->nandCapacity*0x200;\r
497     \r
498     rknand_add_partitions(prknand_Info);\r
499  \r
500     parts = rknand_parts;\r
501         SysImageWriteEndAdd = 0;\r
502     for(i=0;i<g_num_partitions;i++)\r
503     {\r
504         //printk(">>> part[%d]: name=%s offset=0x%012llx\n", i, parts[i].name, parts[i].offset);\r
505         if(strcmp(parts[i].name,"backup") == 0)\r
506         {\r
507             SysImageWriteEndAdd = (unsigned long)(parts[i].offset + parts[i].size)>>9;//sector\r
508             //printk(">>> SysImageWriteEndAdd=0x%lx\n", SysImageWriteEndAdd);\r
509             break;\r
510         }\r
511     }\r
512         if(SysImageWriteEndAdd)\r
513         gpNandInfo->SysImageWriteEndAdd = SysImageWriteEndAdd;\r
514 \r
515         //nandc_clk = clk_get(NULL, "nandc");\r
516         //clk_enable(nandc_clk);\r
517     //rknand_nand_timing_cfg();\r
518 \r
519     return 0;\r
520 }\r
521 \r
522 int get_rknand_device(struct rknand_info ** prknand_Info)\r
523 {\r
524     *prknand_Info = gpNandInfo;\r
525     return 0;    \r
526 }\r
527 \r
528 EXPORT_SYMBOL(get_rknand_device);\r
529 \r
530 int rknand_dma_map_single(unsigned long ptr,int size,int dir)\r
531 {\r
532     return dma_map_single(NULL, ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);\r
533 }\r
534 EXPORT_SYMBOL(rknand_dma_map_single);\r
535 \r
536 void rknand_dma_unmap_single(unsigned long ptr,int size,int dir)\r
537 {\r
538     dma_unmap_single(NULL, ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);\r
539 }\r
540 EXPORT_SYMBOL(rknand_dma_unmap_single);\r
541 \r
542 int rknand_flash_cs_init(void)\r
543 {\r
544 \r
545 }\r
546 EXPORT_SYMBOL(rknand_flash_cs_init);\r
547 \r
548 \r
549 int rknand_get_reg_addr(int *pNandc,int *pSDMMC0,int *pSDMMC1,int *pSDMMC2)\r
550 {\r
551     //*pNandc = ioremap(RK30_NANDC_PHYS,RK30_NANDC_SIZE);\r
552     //*pSDMMC0 = ioremap(SDMMC0_BASE_ADDR, 0x4000);\r
553     //*pSDMMC1 = ioremap(SDMMC1_BASE_ADDR, 0x4000);\r
554     //*pSDMMC2 = ioremap(EMMC_BASE_ADDR,   0x4000);\r
555         *pNandc = ioremap(0x10500000,0x4000);\r
556 }\r
557 EXPORT_SYMBOL(rknand_get_reg_addr);\r
558 \r
559 static int g_nandc_irq = 27;\r
560 int rknand_nandc_irq_init(int mode,void * pfun)\r
561 {\r
562     int ret = 0;\r
563     if(mode) //init\r
564     {\r
565         ret = request_irq(g_nandc_irq, pfun, 0, "nandc", NULL);\r
566         if(ret)\r
567             printk("request IRQ_NANDC irq , ret=%x.........\n", ret);\r
568     }\r
569     else //deinit\r
570     {\r
571         free_irq(g_nandc_irq,  NULL);\r
572     }\r
573     return ret;\r
574 }\r
575 EXPORT_SYMBOL(rknand_nandc_irq_init);\r
576 static int rknand_probe(struct platform_device *pdev)\r
577 {\r
578         struct rknand_info *nand_info;\r
579         int err = 0;\r
580         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk_nand_probe: \n");\r
581         gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);\r
582         if (!gpNandInfo)\r
583                 return -ENOMEM;\r
584     \r
585     nand_info = gpNandInfo;\r
586         printk("rknand_probe: \n");\r
587 \r
588         g_nandc_irq = platform_get_irq(pdev, 0);\r
589         if (g_nandc_irq < 0) {\r
590                 dev_err(&pdev->dev, "no irq resource?\n");\r
591                 return g_nandc_irq;\r
592         }\r
593         \r
594     memset(gpNandInfo,0,sizeof(struct rknand_info));\r
595 \r
596     gpNandInfo->bufSize = MAX_BUFFER_SIZE * 512;\r
597     gpNandInfo->pbuf = (char *)NULL;//grknand_buf;\r
598     gpNandInfo->pdmaBuf = (char *)NULL;//grknand_dma_buf;\r
599     //printk(" gpNandInfo->pdmaBuf=0x%x\n",  gpNandInfo->pdmaBuf); \r
600 #ifdef CONFIG_MTD_EMMC_CLK_POWER_SAVE\r
601     gpNandInfo->emmc_clk_power_save_en = 1;\r
602 #endif\r
603 \r
604         rknand_mtd.name = DRIVER_NAME;//dev_name(&pdev->dev);\r
605         rknand_mtd.priv = &nand_info->rknand;\r
606         rknand_mtd.owner = THIS_MODULE;\r
607     \r
608         if(rknand_info_init(nand_info))\r
609         {\r
610                 err = -ENXIO;\r
611                 goto  exit_free;\r
612         }\r
613         \r
614         nand_info->add_rknand_device = add_rknand_device;\r
615         nand_info->get_rknand_device = get_rknand_device;\r
616 \r
617         rknand_create_procfs();\r
618         return 0;\r
619 \r
620 exit_free:\r
621         if(nand_info)\r
622         kfree(nand_info);\r
623 \r
624         return err;\r
625 }\r
626 \r
627 static int rknand_suspend(struct platform_device *pdev, pm_message_t state)\r
628 {\r
629     gpNandInfo->rknand.rknand_schedule_enable = 0;\r
630    // if(gpNandInfo->rknand_suspend)\r
631      //   gpNandInfo->rknand_suspend();  \r
632         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_suspend: \n");\r
633         return 0;\r
634 }\r
635 \r
636 static int rknand_resume(struct platform_device *pdev)\r
637 {\r
638     //if(gpNandInfo->rknand_resume)\r
639       // gpNandInfo->rknand_resume();  \r
640     gpNandInfo->rknand.rknand_schedule_enable = 1;\r
641         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_resume: \n");\r
642         return 0;\r
643 }\r
644 \r
645 void rknand_shutdown(struct platform_device *pdev)\r
646 {\r
647     printk("rknand_shutdown...\n");\r
648     gpNandInfo->rknand.rknand_schedule_enable = 0;\r
649     if(gpNandInfo->rknand_buffer_shutdown)\r
650         gpNandInfo->rknand_buffer_shutdown();    \r
651 }\r
652 \r
653 #ifdef CONFIG_OF\r
654 static const struct of_device_id of_rk_nandc_match[] = {\r
655         { .compatible = "rockchip,rk-nandc" },\r
656         { /* Sentinel */ }\r
657 };\r
658 #endif\r
659 \r
660 static struct platform_driver rknand_driver = {\r
661         .probe          = rknand_probe,\r
662         .suspend        = rknand_suspend,\r
663         .resume         = rknand_resume,\r
664         .shutdown   = rknand_shutdown,\r
665         .driver         = {\r
666                 .name   = DRIVER_NAME,\r
667 #ifdef CONFIG_OF\r
668         .of_match_table = of_rk_nandc_match,\r
669 #endif\r
670                 .owner  = THIS_MODULE,\r
671         },\r
672 };\r
673 \r
674 \r
675 MODULE_ALIAS(DRIVER_NAME);\r
676 \r
677 static int __init rknand_init(void)\r
678 {\r
679         int ret;\r
680         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_init: \n");\r
681         ret = platform_driver_register(&rknand_driver);\r
682         NAND_DEBUG(NAND_DEBUG_LEVEL0,"platform_driver_register:ret = %x \n",ret);\r
683         return ret;\r
684 }\r
685 \r
686 static void __exit rknand_exit(void)\r
687 {\r
688     platform_driver_unregister(&rknand_driver);\r
689 }\r
690 \r
691 module_init(rknand_init);\r
692 module_exit(rknand_exit);\r
693 \r
694 MODULE_LICENSE("GPL");\r
695 MODULE_AUTHOR("ZYF <zyf@rock-chips.com>");\r
696 MODULE_DESCRIPTION("rknand driver.");\r
697 \r
698 \r