VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / char / lcd.c
1 /*
2  * LCD, LED and Button interface for Cobalt
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * Copyright (C) 1996, 1997 by Andrew Bose
9  *
10  * Linux kernel version history:
11  *       March 2001: Ported from 2.0.34  by Liam Davies
12  *
13  */
14
15 #define RTC_IO_EXTENT   0x10    /*Only really two ports, but... */
16
17 #include <linux/config.h>
18 #include <linux/types.h>
19 #include <linux/errno.h>
20 #include <linux/miscdevice.h>
21 #include <linux/slab.h>
22 #include <linux/ioport.h>
23 #include <linux/fcntl.h>
24 #include <linux/mc146818rtc.h>
25 #include <linux/netdevice.h>
26 #include <linux/sched.h>
27
28 #include <asm/io.h>
29 #include <asm/uaccess.h>
30 #include <asm/system.h>
31 #include <linux/delay.h>
32
33 #include "lcd.h"
34
35 static int lcd_ioctl(struct inode *inode, struct file *file,
36                      unsigned int cmd, unsigned long arg);
37
38 static int lcd_present = 1;
39
40 int led_state = 0;
41
42 #if defined(CONFIG_TULIP) && 0
43
44 #define MAX_INTERFACES  8
45 static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES];
46 static void *linkcheck_cookies[MAX_INTERFACES];
47
48 int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie)
49 {
50         if (iface_num < 0 ||
51             iface_num >= MAX_INTERFACES ||
52             linkcheck_callbacks[iface_num] != NULL)
53                 return -1;
54         linkcheck_callbacks[iface_num] = (linkcheck_func_t) func;
55         linkcheck_cookies[iface_num] = cookie;
56         return 0;
57 }
58 #endif
59
60 static int lcd_ioctl(struct inode *inode, struct file *file,
61                      unsigned int cmd, unsigned long arg)
62 {
63         struct lcd_display button_display;
64         unsigned long address, a;
65         int index;
66
67         switch (cmd) {
68         case LCD_On:
69                 udelay(150);
70                 BusyCheck();
71                 LCDWriteInst(0x0F);
72                 break;
73
74         case LCD_Off:
75                 udelay(150);
76                 BusyCheck();
77                 LCDWriteInst(0x08);
78                 break;
79
80         case LCD_Reset:
81                 udelay(150);
82                 LCDWriteInst(0x3F);
83                 udelay(150);
84                 LCDWriteInst(0x3F);
85                 udelay(150);
86                 LCDWriteInst(0x3F);
87                 udelay(150);
88                 LCDWriteInst(0x3F);
89                 udelay(150);
90                 LCDWriteInst(0x01);
91                 udelay(150);
92                 LCDWriteInst(0x06);
93                 break;
94
95         case LCD_Clear:
96                 udelay(150);
97                 BusyCheck();
98                 LCDWriteInst(0x01);
99                 break;
100
101         case LCD_Cursor_Left:
102                 udelay(150);
103                 BusyCheck();
104                 LCDWriteInst(0x10);
105                 break;
106
107         case LCD_Cursor_Right:
108                 udelay(150);
109                 BusyCheck();
110                 LCDWriteInst(0x14);
111                 break;
112
113         case LCD_Cursor_Off:
114                 udelay(150);
115                 BusyCheck();
116                 LCDWriteInst(0x0C);
117                 break;
118
119         case LCD_Cursor_On:
120                 udelay(150);
121                 BusyCheck();
122                 LCDWriteInst(0x0F);
123                 break;
124
125         case LCD_Blink_Off:
126                 udelay(150);
127                 BusyCheck();
128                 LCDWriteInst(0x0E);
129                 break;
130
131         case LCD_Get_Cursor_Pos:{
132                         struct lcd_display display;
133
134                         udelay(150);
135                         BusyCheck();
136                         display.cursor_address = (LCDReadInst);
137                         display.cursor_address =
138                             (display.cursor_address & 0x07F);
139                         if (copy_to_user
140                             ((struct lcd_display *) arg, &display,
141                              sizeof(struct lcd_display)))
142                                 return -EFAULT;
143
144                         break;
145                 }
146
147
148         case LCD_Set_Cursor_Pos:{
149                         struct lcd_display display;
150
151                         if (copy_from_user
152                             (&display, (struct lcd_display *) arg,
153                              sizeof(struct lcd_display)))
154                                 return -EFAULT;
155
156                         a = (display.cursor_address | kLCD_Addr);
157
158                         udelay(150);
159                         BusyCheck();
160                         LCDWriteInst(a);
161
162                         break;
163                 }
164
165         case LCD_Get_Cursor:{
166                         struct lcd_display display;
167
168                         udelay(150);
169                         BusyCheck();
170                         display.character = LCDReadData;
171
172                         if (copy_to_user
173                             ((struct lcd_display *) arg, &display,
174                              sizeof(struct lcd_display)))
175                                 return -EFAULT;
176                         udelay(150);
177                         BusyCheck();
178                         LCDWriteInst(0x10);
179
180                         break;
181                 }
182
183         case LCD_Set_Cursor:{
184                         struct lcd_display display;
185
186                         if (copy_from_user
187                             (&display, (struct lcd_display *) arg,
188                              sizeof(struct lcd_display)))
189                                 return -EFAULT;
190
191                         udelay(150);
192                         BusyCheck();
193                         LCDWriteData(display.character);
194                         udelay(150);
195                         BusyCheck();
196                         LCDWriteInst(0x10);
197
198                         break;
199                 }
200
201
202         case LCD_Disp_Left:
203                 udelay(150);
204                 BusyCheck();
205                 LCDWriteInst(0x18);
206                 break;
207
208         case LCD_Disp_Right:
209                 udelay(150);
210                 BusyCheck();
211                 LCDWriteInst(0x1C);
212                 break;
213
214         case LCD_Home:
215                 udelay(150);
216                 BusyCheck();
217                 LCDWriteInst(0x02);
218                 break;
219
220         case LCD_Write:{
221                         struct lcd_display display;
222
223
224                         if (copy_from_user
225                             (&display, (struct lcd_display *) arg,
226                              sizeof(struct lcd_display)))
227                                 return -EFAULT;
228
229                         udelay(150);
230                         BusyCheck();
231                         LCDWriteInst(0x80);
232                         udelay(150);
233                         BusyCheck();
234
235                         for (index = 0; index < (display.size1); index++) {
236                                 udelay(150);
237                                 BusyCheck();
238                                 LCDWriteData(display.line1[index]);
239                                 BusyCheck();
240                         }
241
242                         udelay(150);
243                         BusyCheck();
244                         LCDWriteInst(0xC0);
245                         udelay(150);
246                         BusyCheck();
247                         for (index = 0; index < (display.size2); index++) {
248                                 udelay(150);
249                                 BusyCheck();
250                                 LCDWriteData(display.line2[index]);
251                         }
252
253                         break;
254                 }
255
256         case LCD_Read:{
257                         struct lcd_display display;
258
259                         BusyCheck();
260                         for (address = kDD_R00; address <= kDD_R01;
261                              address++) {
262                                 a = (address | kLCD_Addr);
263
264                                 udelay(150);
265                                 BusyCheck();
266                                 LCDWriteInst(a);
267                                 udelay(150);
268                                 BusyCheck();
269                                 display.line1[address] = LCDReadData;
270                         }
271
272                         display.line1[0x27] = '\0';
273
274                         for (address = kDD_R10; address <= kDD_R11;
275                              address++) {
276                                 a = (address | kLCD_Addr);
277
278                                 udelay(150);
279                                 BusyCheck();
280                                 LCDWriteInst(a);
281
282                                 udelay(150);
283                                 BusyCheck();
284                                 display.line2[address - 0x40] =
285                                     LCDReadData;
286                         }
287
288                         display.line2[0x27] = '\0';
289
290                         if (copy_to_user
291                             ((struct lcd_display *) arg, &display,
292                              sizeof(struct lcd_display)))
293                                 return -EFAULT;
294                         break;
295                 }
296
297 //  set all GPIO leds to led_display.leds
298
299         case LED_Set:{
300                         struct lcd_display led_display;
301
302
303                         if (copy_from_user
304                             (&led_display, (struct lcd_display *) arg,
305                              sizeof(struct lcd_display)))
306                                 return -EFAULT;
307
308                         led_state = led_display.leds;
309                         LEDSet(led_state);
310
311                         break;
312                 }
313
314
315 //  set only bit led_display.leds
316
317         case LED_Bit_Set:{
318                         int i;
319                         int bit = 1;
320                         struct lcd_display led_display;
321
322
323                         if (copy_from_user
324                             (&led_display, (struct lcd_display *) arg,
325                              sizeof(struct lcd_display)))
326                                 return -EFAULT;
327
328                         for (i = 0; i < (int) led_display.leds; i++) {
329                                 bit = 2 * bit;
330                         }
331
332                         led_state = led_state | bit;
333                         LEDSet(led_state);
334                         break;
335                 }
336
337 //  clear only bit led_display.leds
338
339         case LED_Bit_Clear:{
340                         int i;
341                         int bit = 1;
342                         struct lcd_display led_display;
343
344
345                         if (copy_from_user
346                             (&led_display, (struct lcd_display *) arg,
347                              sizeof(struct lcd_display)))
348                                 return -EFAULT;
349
350                         for (i = 0; i < (int) led_display.leds; i++) {
351                                 bit = 2 * bit;
352                         }
353
354                         led_state = led_state & ~bit;
355                         LEDSet(led_state);
356                         break;
357                 }
358
359
360         case BUTTON_Read:{
361                         button_display.buttons = GPIRead;
362                         if (copy_to_user
363                             ((struct lcd_display *) arg, &button_display,
364                              sizeof(struct lcd_display)))
365                                 return -EFAULT;
366                         break;
367                 }
368
369         case LINK_Check:{
370                         button_display.buttons =
371                             *((volatile unsigned long *) (0xB0100060));
372                         if (copy_to_user
373                             ((struct lcd_display *) arg, &button_display,
374                              sizeof(struct lcd_display)))
375                                 return -EFAULT;
376                         break;
377                 }
378
379         case LINK_Check_2:{
380                         int iface_num;
381
382                         /* panel-utils should pass in the desired interface status is wanted for
383                          * in "buttons" of the structure.  We will set this to non-zero if the
384                          * link is in fact up for the requested interface.  --DaveM
385                          */
386                         if (copy_from_user
387                             (&button_display, (struct lcd_display *) arg,
388                              sizeof(button_display)))
389                                 return -EFAULT;
390                         iface_num = button_display.buttons;
391 #if defined(CONFIG_TULIP) && 0
392                         if (iface_num >= 0 &&
393                             iface_num < MAX_INTERFACES &&
394                             linkcheck_callbacks[iface_num] != NULL) {
395                                 button_display.buttons =
396                                     linkcheck_callbacks[iface_num]
397                                     (linkcheck_cookies[iface_num]);
398                         } else
399 #endif
400                                 button_display.buttons = 0;
401
402                         if (__copy_to_user
403                             ((struct lcd_display *) arg, &button_display,
404                              sizeof(struct lcd_display)))
405                                 return -EFAULT;
406                         break;
407                 }
408
409 //  Erase the flash
410
411         case FLASH_Erase:{
412
413                         int ctr = 0;
414
415                         // Chip Erase Sequence
416                         WRITE_FLASH(kFlash_Addr1, kFlash_Data1);
417                         WRITE_FLASH(kFlash_Addr2, kFlash_Data2);
418                         WRITE_FLASH(kFlash_Addr1, kFlash_Erase3);
419                         WRITE_FLASH(kFlash_Addr1, kFlash_Data1);
420                         WRITE_FLASH(kFlash_Addr2, kFlash_Data2);
421                         WRITE_FLASH(kFlash_Addr1, kFlash_Erase6);
422
423                         printk("Erasing Flash.\n");
424
425                         while ((!dqpoll(0x00000000, 0xFF))
426                                && (!timeout(0x00000000))) {
427                                 ctr++;
428                         }
429
430                         printk("\n");
431                         printk("\n");
432                         printk("\n");
433
434                         if (READ_FLASH(0x07FFF0) == 0xFF) {
435                                 printk("Erase Successful\r\n");
436                         } else if (timeout) {
437                                 printk("Erase Timed Out\r\n");
438                         }
439
440                         break;
441                 }
442
443 // burn the flash
444
445         case FLASH_Burn:{
446
447                         volatile unsigned long burn_addr;
448                         unsigned long flags;
449                         int i;
450                         unsigned char *rom;
451
452
453                         struct lcd_display display;
454
455                         if (copy_from_user
456                             (&display, (struct lcd_display *) arg,
457                              sizeof(struct lcd_display)))
458                                 return -EFAULT;
459                         rom = (unsigned char *) kmalloc((128), GFP_ATOMIC);
460                         if (rom == NULL) {
461                                 printk("broken\n");
462                                 return 1;
463                         }
464
465                         printk("Churning and Burning -");
466                         save_flags(flags);
467                         for (i = 0; i < FLASH_SIZE; i = i + 128) {
468
469                                 if (copy_from_user
470                                     (rom, display.RomImage + i, 128))
471                                         return -EFAULT;
472                                 burn_addr = kFlashBase + i;
473                                 cli();
474                                 for (index = 0; index < (128); index++) {
475
476                                         WRITE_FLASH(kFlash_Addr1,
477                                                     kFlash_Data1);
478                                         WRITE_FLASH(kFlash_Addr2,
479                                                     kFlash_Data2);
480                                         WRITE_FLASH(kFlash_Addr1,
481                                                     kFlash_Prog);
482                                         *((volatile unsigned char *)
483                                           burn_addr) =
484                  (volatile unsigned char) rom[index];
485
486                                         while ((!dqpoll
487                                                 (burn_addr,
488                                                  (volatile unsigned char)
489                                                  rom[index]))
490                                                && (!timeout(burn_addr))) {
491                                         }
492                                         burn_addr++;
493                                 }
494                                 restore_flags(flags);
495                                 if (*
496                                     ((volatile unsigned char *) (burn_addr
497                                                                  - 1)) ==
498                                     (volatile unsigned char) rom[index -
499                                                                  1]) {
500                                 } else if (timeout) {
501                                         printk("Program timed out\r\n");
502                                 }
503
504
505                         }
506                         kfree(rom);
507
508                         break;
509                 }
510
511 //  read the flash all at once
512
513         case FLASH_Read:{
514
515                         unsigned char *user_bytes;
516                         volatile unsigned long read_addr;
517                         int i;
518
519                         user_bytes =
520                             &(((struct lcd_display *) arg)->RomImage[0]);
521
522                         if (!access_ok
523                             (VERIFY_WRITE, user_bytes, FLASH_SIZE))
524                                 return -EFAULT;
525
526                         printk("Reading Flash");
527                         for (i = 0; i < FLASH_SIZE; i++) {
528                                 unsigned char tmp_byte;
529                                 read_addr = kFlashBase + i;
530                                 tmp_byte =
531                                     *((volatile unsigned char *)
532                                       read_addr);
533                                 if (__put_user(tmp_byte, &user_bytes[i]))
534                                         return -EFAULT;
535                         }
536
537
538                         break;
539                 }
540
541         default:
542                 return 0;
543                 break;
544
545         }
546
547         return 0;
548
549 }
550
551 static int lcd_open(struct inode *inode, struct file *file)
552 {
553         if (!lcd_present)
554                 return -ENXIO;
555         else
556                 return 0;
557 }
558
559 /* Only RESET or NEXT counts as button pressed */
560
561 static inline int button_pressed(void)
562 {
563         unsigned long buttons = GPIRead;
564
565         if ((buttons == BUTTON_Next) || (buttons == BUTTON_Next_B)
566             || (buttons == BUTTON_Reset_B))
567                 return buttons;
568         return 0;
569 }
570
571 /* LED daemon sits on this and we wake him up once a key is pressed. */
572
573 static int lcd_waiters = 0;
574
575 static long lcd_read(struct inode *inode, struct file *file, char *buf,
576                      unsigned long count)
577 {
578         long buttons_now;
579
580         if (lcd_waiters > 0)
581                 return -EINVAL;
582
583         lcd_waiters++;
584         while (((buttons_now = (long) button_pressed()) == 0) &&
585                !(signal_pending(current))) {
586                 current->state = TASK_INTERRUPTIBLE;
587                 schedule_timeout(2 * HZ);
588         }
589         lcd_waiters--;
590
591         if (signal_pending(current))
592                 return -ERESTARTSYS;
593         return buttons_now;
594 }
595
596 /*
597  *      The various file operations we support.
598  */
599
600 static struct file_operations lcd_fops = {
601         .read = lcd_read,
602         .ioctl = lcd_ioctl,
603         .open = lcd_open,
604 };
605
606 static struct miscdevice lcd_dev = {
607         MISC_DYNAMIC_MINOR,
608         "lcd",
609         &lcd_fops
610 };
611
612 static int lcd_init(void)
613 {
614         unsigned long data;
615
616         printk("%s\n", LCD_DRIVER);
617         misc_register(&lcd_dev);
618
619         /* Check region? Naaah! Just snarf it up. */
620 /*      request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/
621
622         udelay(150);
623         data = LCDReadData;
624         if ((data & 0x000000FF) == (0x00)) {
625                 lcd_present = 0;
626                 printk("LCD Not Present\n");
627         } else {
628                 lcd_present = 1;
629                 WRITE_GAL(kGal_DevBank2PReg, kGal_DevBank2Cfg);
630                 WRITE_GAL(kGal_DevBank3PReg, kGal_DevBank3Cfg);
631         }
632
633         return 0;
634 }
635
636 static void __exit lcd_exit(void)
637 {
638         misc_deregister(&lcd_dev);
639 }
640
641 //
642 // Function: dqpoll
643 //
644 // Description:  Polls the data lines to see if the flash is busy
645 //
646 // In: address, byte data
647 //
648 // Out: 0 = busy, 1 = write or erase complete
649 //
650 //
651
652 static int dqpoll(volatile unsigned long address, volatile unsigned char data)
653 {
654         volatile unsigned char dq7;
655
656         dq7 = data & 0x80;
657
658         return ((READ_FLASH(address) & 0x80) == dq7);
659 }
660
661 //
662 // Function: timeout
663 //
664 // Description: Checks to see if erase or write has timed out
665 //              By polling dq5
666 //
667 // In: address
668 //
669 //
670 // Out: 0 = not timed out, 1 = timed out
671
672 static int timeout(volatile unsigned long address)
673 {
674         return (READ_FLASH(address) & 0x20) == 0x20;
675 }
676
677 module_init(lcd_init);
678 module_exit(lcd_exit);
679
680 MODULE_AUTHOR("Andrew Bose");
681 MODULE_LICENSE("GPL");