cleanup more ifxmips ssc reg acceses
[openwrt.git] / target / linux / danube / files / drivers / char / danube_eeprom.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
15  *
16  *   This driver was originally based on the INCA-IP driver, but due to
17  *   fundamental conceptual drawbacks there has been changed a lot.
18  *
19  *   Based on INCA-IP driver Copyright (c) 2003 Gary Jennejohn <gj@denx.de>
20  *   Based on the VxWorks drivers Copyright (c) 2002, Infineon Technologies.
21  *
22  *   Copyright (C) 2006 infineon
23  *   Copyright (C) 2007 John Crispin <blogic@openwrt.org> 
24  *
25  */
26
27 #define IFAP_EEPROM_DRV_VERSION "0.0.1"
28
29 #include <linux/module.h>
30 #include <linux/errno.h>
31 #include <linux/signal.h>
32 #include <linux/sched.h>
33 #include <linux/timer.h>
34 #include <linux/interrupt.h>
35 #include <linux/major.h>
36 #include <linux/string.h>
37 #include <linux/fs.h>
38 #include <linux/fcntl.h>
39 #include <linux/ptrace.h>
40 #include <linux/mm.h>
41 #include <linux/ioport.h>
42 #include <linux/init.h>
43 #include <linux/delay.h>
44 #include <linux/spinlock.h>
45 #include <linux/slab.h>
46 #include <asm/system.h>
47 #include <asm/io.h>
48 #include <asm/irq.h>
49 #include <asm/uaccess.h>
50 #include <asm/bitops.h>
51
52 #include <linux/types.h>
53 #include <linux/kernel.h>
54 #include <linux/version.h>
55
56 #include <asm/danube/danube.h>
57 #include <asm/danube/danube_irq.h>
58 #include <asm/danube/ifx_ssc_defines.h>
59 #include <asm/danube/ifx_ssc.h>
60
61 /* allow the user to set the major device number */
62 static int danube_eeprom_maj = 0;
63
64 extern int ifx_ssc_init (void);
65 extern int ifx_ssc_open (struct inode *inode, struct file *filp);
66 extern int ifx_ssc_close (struct inode *inode, struct file *filp);
67 extern void ifx_ssc_cleanup_module (void);
68 extern int ifx_ssc_ioctl (struct inode *inode, struct file *filp,
69                           unsigned int cmd, unsigned long data);
70 extern ssize_t ifx_ssc_kwrite (int port, const char *kbuf, size_t len);
71 extern ssize_t ifx_ssc_kread (int port, char *kbuf, size_t len);
72
73 extern int ifx_ssc_cs_low (unsigned int pin);
74 extern int ifx_ssc_cs_high (unsigned int pin);
75 extern int ifx_ssc_txrx (char *tx_buf, unsigned int tx_len, char *rx_buf, unsigned int rx_len);
76 extern int ifx_ssc_tx (char *tx_buf, unsigned int tx_len);
77 extern int ifx_ssc_rx (char *rx_buf, unsigned int rx_len);
78
79 #define EEPROM_CS IFX_SSC_WHBGPOSTAT_OUT0_POS
80
81 /* commands for EEPROM, x25160, x25140 */
82 #define EEPROM_WREN                     ((unsigned char)0x06)
83 #define EEPROM_WRDI                     ((unsigned char)0x04)
84 #define EEPROM_RDSR                     ((unsigned char)0x05)
85 #define EEPROM_WRSR                     ((unsigned char)0x01)
86 #define EEPROM_READ                     ((unsigned char)0x03)
87 #define EEPROM_WRITE                    ((unsigned char)0x02)
88 #define EEPROM_PAGE_SIZE                4
89 #define EEPROM_SIZE                     512
90
91 static int
92 eeprom_rdsr (void)
93 {
94         int ret = 0;
95         unsigned char cmd = EEPROM_RDSR;
96         unsigned long flag;
97         char status;
98
99         local_irq_save(flag);
100
101         if ((ret = ifx_ssc_cs_low(EEPROM_CS)) == 0)
102                 if ((ret = ifx_ssc_txrx(&cmd, 1, &status, 1)) >= 0)
103                         ret = status & 1;
104
105         ifx_ssc_cs_high(EEPROM_CS);
106         local_irq_restore(flag);
107
108         return ret;
109 }
110
111 void
112 eeprom_wip_over (void)
113 {
114         while (eeprom_rdsr())
115                 printk("waiting for eeprom\n");
116 }
117
118 static int
119 eeprom_wren (void)
120 {
121         unsigned char cmd = EEPROM_WREN;
122         int ret = 0;
123         unsigned long flag;
124
125         local_irq_save(flag);
126         if ((ret = ifx_ssc_cs_low(EEPROM_CS)) == 0)
127                 if ((ret = ifx_ssc_tx(&cmd, 1)) >= 0)
128                         ret = 0;
129
130         ifx_ssc_cs_high(EEPROM_CS);
131         local_irq_restore(flag);
132
133         if (!ret)
134                 eeprom_wip_over();
135
136         return ret;
137 }
138
139 static int
140 eeprom_wrsr (void)
141 {
142         int ret = 0;
143         unsigned char cmd[2];
144         unsigned long flag;
145
146         cmd[0] = EEPROM_WRSR;
147         cmd[1] = 0;
148
149         if ((ret = eeprom_wren()))
150         {
151                 printk ("eeprom_wren fails\n");
152                 goto out1;
153         }
154
155         local_irq_save(flag);
156
157         if ((ret = ifx_ssc_cs_low(EEPROM_CS)))
158                 goto out;
159
160         if ((ret = ifx_ssc_tx(cmd, 2)) < 0) {
161                 ifx_ssc_cs_high(EEPROM_CS);
162                 goto out;
163         }
164
165         if ((ret = ifx_ssc_cs_low(EEPROM_CS)))
166                 goto out;
167
168         local_irq_restore(flag);
169         eeprom_wip_over();
170
171         return ret;
172
173 out:
174         local_irq_restore (flag);
175         eeprom_wip_over ();
176
177 out1:
178         return ret;
179 }
180
181 static int
182 eeprom_read (unsigned int addr, unsigned char *buf, unsigned int len)
183 {
184         int ret = 0;
185         unsigned char write_buf[2];
186         unsigned int eff = 0;
187         unsigned long flag;
188
189         while (1)
190         {
191                 eeprom_wip_over();
192                 eff = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE);
193                 eff = (eff < len) ? eff : len;
194                 local_irq_save(flag);
195
196                 if ((ret = ifx_ssc_cs_low(EEPROM_CS)) < 0)
197                         goto out;
198
199                 write_buf[0] = EEPROM_READ | ((unsigned char) ((addr & 0x100) >> 5));
200                 write_buf[1] = (addr & 0xff);
201
202                 if ((ret = ifx_ssc_txrx (write_buf, 2, buf, eff)) != eff)
203                 {
204                         printk("ssc_txrx fails %d\n", ret);
205                         ifx_ssc_cs_high (EEPROM_CS);
206                         goto out;
207                 }
208
209                 buf += ret;
210                 len -= ret;
211                 addr += ret;
212
213                 if ((ret = ifx_ssc_cs_high(EEPROM_CS)))
214                         goto out;
215
216                 local_irq_restore(flag);
217
218                 if (len <= 0)
219                         goto out2;
220         }
221
222 out:
223         local_irq_restore (flag);
224 out2:
225         return ret;
226 }
227
228 static int
229 eeprom_write (unsigned int addr, unsigned char *buf, unsigned int len)
230 {
231         int ret = 0;
232         unsigned int eff = 0;
233         unsigned char write_buf[2];
234         int i;
235         unsigned char rx_buf[EEPROM_PAGE_SIZE];
236
237         while (1)
238         {
239                 eeprom_wip_over();
240
241                 if ((ret = eeprom_wren()))
242                 {
243                         printk("eeprom_wren fails\n");
244                         goto out;
245                 }
246
247                 write_buf[0] = EEPROM_WRITE | ((unsigned char) ((addr & 0x100) >> 5));
248                 write_buf[1] = (addr & 0xff);
249
250                 eff = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE);
251                 eff = (eff < len) ? eff : len;
252
253                 printk("EEPROM Write:\n");
254                 for (i = 0; i < eff; i++) {
255                         printk("%2x ", buf[i]);
256                         if ((i % 16) == 15)
257                                 printk("\n");
258                 }
259                 printk("\n");
260
261                 if ((ret = ifx_ssc_cs_low(EEPROM_CS)))
262                         goto out;
263
264                 if ((ret = ifx_ssc_tx (write_buf, 2)) < 0)
265                 {
266                         printk("ssc_tx fails %d\n", ret);
267                         ifx_ssc_cs_high(EEPROM_CS);
268                         goto out;
269                 }
270
271                 if ((ret = ifx_ssc_tx (buf, eff)) != eff)
272                 {
273                         printk("ssc_tx fails %d\n", ret);
274                         ifx_ssc_cs_high(EEPROM_CS);
275                         goto out;
276                 }
277
278                 buf += ret;
279                 len -= ret;
280                 addr += ret;
281
282                 if ((ret = ifx_ssc_cs_high (EEPROM_CS)))
283                         goto out;
284
285                 printk ("<==");
286                 eeprom_read((addr - eff), rx_buf, eff);
287                 for (i = 0; i < eff; i++)
288                 {
289                         printk ("[%x]", rx_buf[i]);
290                 }
291                 printk ("\n");
292
293                 if (len <= 0)
294                         break;
295         }
296
297 out:
298         return ret;
299 }
300
301 int
302 danube_eeprom_open (struct inode *inode, struct file *filp)
303 {
304         filp->f_pos = 0;
305         return 0;
306 }
307
308 int
309 danube_eeprom_close (struct inode *inode, struct file *filp)
310 {
311         return 0;
312 }
313
314 int
315 danube_eeprom_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data)
316 {
317         return 0;
318 }
319
320 ssize_t
321 danube_eeprom_read (char *buf, size_t len, unsigned int addr)
322 {
323         int ret = 0;
324         unsigned int data;
325
326         printk("addr:=%d\n", addr);
327         printk("len:=%d\n", len);
328
329         if ((addr + len) > EEPROM_SIZE)
330         {
331                 printk("invalid len\n");
332                 addr = 0;
333                 len = EEPROM_SIZE / 2;
334         }
335
336         if ((ret = ifx_ssc_open((struct inode *) 0, NULL)))
337         {
338                 printk("danube_eeprom_open fails\n");
339                 goto out;
340         }
341
342         data = (unsigned int)IFX_SSC_MODE_RXTX;
343
344         if ((ret = ifx_ssc_ioctl((struct inode *) 0, NULL, IFX_SSC_RXTX_MODE_SET, (unsigned long) &data)))
345         {
346                 printk("set RXTX mode fails\n");
347                 goto out;
348         }
349
350         if ((ret = eeprom_wrsr()))
351         {
352                 printk("EEPROM reset fails\n");
353                 goto out;
354         }
355
356         if ((ret = eeprom_read(addr, buf, len)))
357         {
358                 printk("eeprom read fails\n");
359                 goto out;
360         }
361
362 out:
363         if (ifx_ssc_close((struct inode *) 0, NULL))
364                 printk("danube_eeprom_close fails\n");
365
366         return len;
367 }
368 EXPORT_SYMBOL(danube_eeprom_read);
369
370 static ssize_t
371 danube_eeprom_fops_read (struct file *filp, char *ubuf, size_t len, loff_t * off)
372 {
373         int ret = 0;
374         unsigned char ssc_rx_buf[EEPROM_SIZE];
375         long flag;
376
377         if (*off >= EEPROM_SIZE)
378                 return 0;
379
380         if (*off + len > EEPROM_SIZE)
381                 len = EEPROM_SIZE - *off;
382
383         if (len == 0)
384                 return 0;
385
386         local_irq_save(flag);
387
388         if ((ret = danube_eeprom_read(ssc_rx_buf, len, *off)) < 0)
389         {
390                 printk("read fails, err=%x\n", ret);
391                 local_irq_restore(flag);
392                 return ret;
393         }
394
395         if (copy_to_user((void*)ubuf, ssc_rx_buf, ret) != 0)
396         {
397                 local_irq_restore(flag);
398                 ret = -EFAULT;
399         }
400
401         local_irq_restore(flag);
402         *off += len;
403
404         return len;
405 }
406
407 ssize_t
408 danube_eeprom_write (char *buf, size_t len, unsigned int addr)
409 {
410         int ret = 0;
411         unsigned int data;
412
413         if ((ret = ifx_ssc_open ((struct inode *) 0, NULL)))
414         {
415                 printk ("danube_eeprom_open fails\n");
416                 goto out;
417         }
418
419         data = (unsigned int) IFX_SSC_MODE_RXTX;
420
421         if ((ret = ifx_ssc_ioctl ((struct inode *) 0, NULL, IFX_SSC_RXTX_MODE_SET, (unsigned long) &data)))
422         {
423                 printk ("set RXTX mode fails\n");
424                 goto out;
425         }
426
427         if ((ret = eeprom_wrsr ())) {
428                 printk ("EEPROM reset fails\n");
429                 goto out;
430         }
431
432         if ((ret = eeprom_write (addr, buf, len))) {
433                 printk ("eeprom write fails\n");
434                 goto out;
435         }
436
437 out:
438         if (ifx_ssc_close ((struct inode *) 0, NULL))
439                 printk ("danube_eeprom_close fails\n");
440
441         return ret;
442 }
443 EXPORT_SYMBOL(danube_eeprom_write);
444
445 static ssize_t
446 danube_eeprom_fops_write (struct file *filp, const char *ubuf, size_t len, loff_t * off)
447 {
448         int ret = 0;
449         unsigned char ssc_tx_buf[EEPROM_SIZE];
450
451         if (*off >= EEPROM_SIZE)
452                 return 0;
453
454         if (len + *off > EEPROM_SIZE)
455                 len = EEPROM_SIZE - *off;
456
457         if ((ret = copy_from_user (ssc_tx_buf, ubuf, len)))
458                 return EFAULT;
459
460         ret = danube_eeprom_write (ssc_tx_buf, len, *off);
461
462         if (ret > 0)
463                 *off = ret;
464
465         return ret;
466 }
467
468 loff_t
469 danube_eeprom_llseek (struct file * filp, loff_t off, int whence)
470 {
471         loff_t newpos;
472         switch (whence) {
473         case SEEK_SET:
474                 newpos = off;
475                 break;
476
477         case SEEK_CUR:
478                 newpos = filp->f_pos + off;
479                 break;
480
481         default:
482                 return -EINVAL;
483         }
484
485         if (newpos < 0)
486                 return -EINVAL;
487
488         filp->f_pos = newpos;
489
490         return newpos;
491 }
492
493 static struct file_operations danube_eeprom_fops = {
494       owner:THIS_MODULE,
495       llseek:danube_eeprom_llseek,
496       read:danube_eeprom_fops_read,
497       write:danube_eeprom_fops_write,
498       ioctl:danube_eeprom_ioctl,
499       open:danube_eeprom_open,
500       release:danube_eeprom_close,
501 };
502
503 int __init
504 danube_eeprom_init (void)
505 {
506         int ret = 0;
507
508         danube_eeprom_maj = register_chrdev(0, "eeprom", &danube_eeprom_fops);
509
510         if (danube_eeprom_maj < 0)
511         {
512                 printk("failed to register eeprom device\n");
513                 ret = -EINVAL;
514                 
515                 goto out;
516         }
517
518         printk("danube_eeprom : /dev/eeprom mayor %d\n", danube_eeprom_maj);
519
520 out:
521         return ret;
522 }
523
524 void __exit
525 danube_eeprom_cleanup_module (void)
526 {
527         /*if (unregister_chrdev (danube_eeprom_maj, "eeprom")) {
528                 printk ("Unable to unregister major %d for the EEPROM\n",
529                         maj);
530         }*/
531 }
532
533 module_exit (danube_eeprom_cleanup_module);
534 module_init (danube_eeprom_init);
535
536 MODULE_LICENSE ("GPL");
537 MODULE_AUTHOR ("Peng Liu");
538 MODULE_DESCRIPTION ("IFAP EEPROM driver");
539 MODULE_SUPPORTED_DEVICE ("danube_eeprom");
540
541