kernel.org linux-2.6.10
[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 #include <linux/delay.h>
28
29 #include <asm/io.h>
30 #include <asm/uaccess.h>
31 #include <asm/system.h>
32 #include <linux/delay.h>
33
34 #include "lcd.h"
35
36 static int lcd_ioctl(struct inode *inode, struct file *file,
37                      unsigned int cmd, unsigned long arg);
38
39 static int lcd_present = 1;
40
41 int led_state = 0;
42
43 #if defined(CONFIG_TULIP) && 0
44
45 #define MAX_INTERFACES  8
46 static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES];
47 static void *linkcheck_cookies[MAX_INTERFACES];
48
49 int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie)
50 {
51         if (iface_num < 0 ||
52             iface_num >= MAX_INTERFACES ||
53             linkcheck_callbacks[iface_num] != NULL)
54                 return -1;
55         linkcheck_callbacks[iface_num] = (linkcheck_func_t) func;
56         linkcheck_cookies[iface_num] = cookie;
57         return 0;
58 }
59 #endif
60
61 static int lcd_ioctl(struct inode *inode, struct file *file,
62                      unsigned int cmd, unsigned long arg)
63 {
64         struct lcd_display button_display;
65         unsigned long address, a;
66         int index;
67
68         switch (cmd) {
69         case LCD_On:
70                 udelay(150);
71                 BusyCheck();
72                 LCDWriteInst(0x0F);
73                 break;
74
75         case LCD_Off:
76                 udelay(150);
77                 BusyCheck();
78                 LCDWriteInst(0x08);
79                 break;
80
81         case LCD_Reset:
82                 udelay(150);
83                 LCDWriteInst(0x3F);
84                 udelay(150);
85                 LCDWriteInst(0x3F);
86                 udelay(150);
87                 LCDWriteInst(0x3F);
88                 udelay(150);
89                 LCDWriteInst(0x3F);
90                 udelay(150);
91                 LCDWriteInst(0x01);
92                 udelay(150);
93                 LCDWriteInst(0x06);
94                 break;
95
96         case LCD_Clear:
97                 udelay(150);
98                 BusyCheck();
99                 LCDWriteInst(0x01);
100                 break;
101
102         case LCD_Cursor_Left:
103                 udelay(150);
104                 BusyCheck();
105                 LCDWriteInst(0x10);
106                 break;
107
108         case LCD_Cursor_Right:
109                 udelay(150);
110                 BusyCheck();
111                 LCDWriteInst(0x14);
112                 break;
113
114         case LCD_Cursor_Off:
115                 udelay(150);
116                 BusyCheck();
117                 LCDWriteInst(0x0C);
118                 break;
119
120         case LCD_Cursor_On:
121                 udelay(150);
122                 BusyCheck();
123                 LCDWriteInst(0x0F);
124                 break;
125
126         case LCD_Blink_Off:
127                 udelay(150);
128                 BusyCheck();
129                 LCDWriteInst(0x0E);
130                 break;
131
132         case LCD_Get_Cursor_Pos:{
133                         struct lcd_display display;
134
135                         udelay(150);
136                         BusyCheck();
137                         display.cursor_address = (LCDReadInst);
138                         display.cursor_address =
139                             (display.cursor_address & 0x07F);
140                         if (copy_to_user
141                             ((struct lcd_display *) arg, &display,
142                              sizeof(struct lcd_display)))
143                                 return -EFAULT;
144
145                         break;
146                 }
147
148
149         case LCD_Set_Cursor_Pos:{
150                         struct lcd_display display;
151
152                         if (copy_from_user
153                             (&display, (struct lcd_display *) arg,
154                              sizeof(struct lcd_display)))
155                                 return -EFAULT;
156
157                         a = (display.cursor_address | kLCD_Addr);
158
159                         udelay(150);
160                         BusyCheck();
161                         LCDWriteInst(a);
162
163                         break;
164                 }
165
166         case LCD_Get_Cursor:{
167                         struct lcd_display display;
168
169                         udelay(150);
170                         BusyCheck();
171                         display.character = LCDReadData;
172
173                         if (copy_to_user
174                             ((struct lcd_display *) arg, &display,
175                              sizeof(struct lcd_display)))
176                                 return -EFAULT;
177                         udelay(150);
178                         BusyCheck();
179                         LCDWriteInst(0x10);
180
181                         break;
182                 }
183
184         case LCD_Set_Cursor:{
185                         struct lcd_display display;
186
187                         if (copy_from_user
188                             (&display, (struct lcd_display *) arg,
189                              sizeof(struct lcd_display)))
190                                 return -EFAULT;
191
192                         udelay(150);
193                         BusyCheck();
194                         LCDWriteData(display.character);
195                         udelay(150);
196                         BusyCheck();
197                         LCDWriteInst(0x10);
198
199                         break;
200                 }
201
202
203         case LCD_Disp_Left:
204                 udelay(150);
205                 BusyCheck();
206                 LCDWriteInst(0x18);
207                 break;
208
209         case LCD_Disp_Right:
210                 udelay(150);
211                 BusyCheck();
212                 LCDWriteInst(0x1C);
213                 break;
214
215         case LCD_Home:
216                 udelay(150);
217                 BusyCheck();
218                 LCDWriteInst(0x02);
219                 break;
220
221         case LCD_Write:{
222                         struct lcd_display display;
223
224
225                         if (copy_from_user
226                             (&display, (struct lcd_display *) arg,
227                              sizeof(struct lcd_display)))
228                                 return -EFAULT;
229
230                         udelay(150);
231                         BusyCheck();
232                         LCDWriteInst(0x80);
233                         udelay(150);
234                         BusyCheck();
235
236                         for (index = 0; index < (display.size1); index++) {
237                                 udelay(150);
238                                 BusyCheck();
239                                 LCDWriteData(display.line1[index]);
240                                 BusyCheck();
241                         }
242
243                         udelay(150);
244                         BusyCheck();
245                         LCDWriteInst(0xC0);
246                         udelay(150);
247                         BusyCheck();
248                         for (index = 0; index < (display.size2); index++) {
249                                 udelay(150);
250                                 BusyCheck();
251                                 LCDWriteData(display.line2[index]);
252                         }
253
254                         break;
255                 }
256
257         case LCD_Read:{
258                         struct lcd_display display;
259
260                         BusyCheck();
261                         for (address = kDD_R00; address <= kDD_R01;
262                              address++) {
263                                 a = (address | kLCD_Addr);
264
265                                 udelay(150);
266                                 BusyCheck();
267                                 LCDWriteInst(a);
268                                 udelay(150);
269                                 BusyCheck();
270                                 display.line1[address] = LCDReadData;
271                         }
272
273                         display.line1[0x27] = '\0';
274
275                         for (address = kDD_R10; address <= kDD_R11;
276                              address++) {
277                                 a = (address | kLCD_Addr);
278
279                                 udelay(150);
280                                 BusyCheck();
281                                 LCDWriteInst(a);
282
283                                 udelay(150);
284                                 BusyCheck();
285                                 display.line2[address - 0x40] =
286                                     LCDReadData;
287                         }
288
289                         display.line2[0x27] = '\0';
290
291                         if (copy_to_user
292                             ((struct lcd_display *) arg, &display,
293                              sizeof(struct lcd_display)))
294                                 return -EFAULT;
295                         break;
296                 }
297
298 //  set all GPIO leds to led_display.leds
299
300         case LED_Set:{
301                         struct lcd_display led_display;
302
303
304                         if (copy_from_user
305                             (&led_display, (struct lcd_display *) arg,
306                              sizeof(struct lcd_display)))
307                                 return -EFAULT;
308
309                         led_state = led_display.leds;
310                         LEDSet(led_state);
311
312                         break;
313                 }
314
315
316 //  set only bit led_display.leds
317
318         case LED_Bit_Set:{
319                         int i;
320                         int bit = 1;
321                         struct lcd_display led_display;
322
323
324                         if (copy_from_user
325                             (&led_display, (struct lcd_display *) arg,
326                              sizeof(struct lcd_display)))
327                                 return -EFAULT;
328
329                         for (i = 0; i < (int) led_display.leds; i++) {
330                                 bit = 2 * bit;
331                         }
332
333                         led_state = led_state | bit;
334                         LEDSet(led_state);
335                         break;
336                 }
337
338 //  clear only bit led_display.leds
339
340         case LED_Bit_Clear:{
341                         int i;
342                         int bit = 1;
343                         struct lcd_display led_display;
344
345
346                         if (copy_from_user
347                             (&led_display, (struct lcd_display *) arg,
348                              sizeof(struct lcd_display)))
349                                 return -EFAULT;
350
351                         for (i = 0; i < (int) led_display.leds; i++) {
352                                 bit = 2 * bit;
353                         }
354
355                         led_state = led_state & ~bit;
356                         LEDSet(led_state);
357                         break;
358                 }
359
360
361         case BUTTON_Read:{
362                         button_display.buttons = GPIRead;
363                         if (copy_to_user
364                             ((struct lcd_display *) arg, &button_display,
365                              sizeof(struct lcd_display)))
366                                 return -EFAULT;
367                         break;
368                 }
369
370         case LINK_Check:{
371                         button_display.buttons =
372                             *((volatile unsigned long *) (0xB0100060));
373                         if (copy_to_user
374                             ((struct lcd_display *) arg, &button_display,
375                              sizeof(struct lcd_display)))
376                                 return -EFAULT;
377                         break;
378                 }
379
380         case LINK_Check_2:{
381                         int iface_num;
382
383                         /* panel-utils should pass in the desired interface status is wanted for
384                          * in "buttons" of the structure.  We will set this to non-zero if the
385                          * link is in fact up for the requested interface.  --DaveM
386                          */
387                         if (copy_from_user
388                             (&button_display, (struct lcd_display *) arg,
389                              sizeof(button_display)))
390                                 return -EFAULT;
391                         iface_num = button_display.buttons;
392 #if defined(CONFIG_TULIP) && 0
393                         if (iface_num >= 0 &&
394                             iface_num < MAX_INTERFACES &&
395                             linkcheck_callbacks[iface_num] != NULL) {
396                                 button_display.buttons =
397                                     linkcheck_callbacks[iface_num]
398                                     (linkcheck_cookies[iface_num]);
399                         } else
400 #endif
401                                 button_display.buttons = 0;
402
403                         if (__copy_to_user
404                             ((struct lcd_display *) arg, &button_display,
405                              sizeof(struct lcd_display)))
406                                 return -EFAULT;
407                         break;
408                 }
409
410 //  Erase the flash
411
412         case FLASH_Erase:{
413
414                         int ctr = 0;
415
416                         // Chip Erase Sequence
417                         WRITE_FLASH(kFlash_Addr1, kFlash_Data1);
418                         WRITE_FLASH(kFlash_Addr2, kFlash_Data2);
419                         WRITE_FLASH(kFlash_Addr1, kFlash_Erase3);
420                         WRITE_FLASH(kFlash_Addr1, kFlash_Data1);
421                         WRITE_FLASH(kFlash_Addr2, kFlash_Data2);
422                         WRITE_FLASH(kFlash_Addr1, kFlash_Erase6);
423
424                         printk("Erasing Flash.\n");
425
426                         while ((!dqpoll(0x00000000, 0xFF))
427                                && (!timeout(0x00000000))) {
428                                 ctr++;
429                         }
430
431                         printk("\n");
432                         printk("\n");
433                         printk("\n");
434
435                         if (READ_FLASH(0x07FFF0) == 0xFF) {
436                                 printk("Erase Successful\r\n");
437                         } else if (timeout) {
438                                 printk("Erase Timed Out\r\n");
439                         }
440
441                         break;
442                 }
443
444 // burn the flash
445
446         case FLASH_Burn:{
447
448                         volatile unsigned long burn_addr;
449                         unsigned long flags;
450                         int i;
451                         unsigned char *rom;
452
453
454                         struct lcd_display display;
455
456                         if (copy_from_user
457                             (&display, (struct lcd_display *) arg,
458                              sizeof(struct lcd_display)))
459                                 return -EFAULT;
460                         rom = (unsigned char *) kmalloc((128), GFP_ATOMIC);
461                         if (rom == NULL) {
462                                 printk("broken\n");
463                                 return 1;
464                         }
465
466                         printk("Churning and Burning -");
467                         save_flags(flags);
468                         for (i = 0; i < FLASH_SIZE; i = i + 128) {
469
470                                 if (copy_from_user
471                                     (rom, display.RomImage + i, 128))
472                                         return -EFAULT;
473                                 burn_addr = kFlashBase + i;
474                                 cli();
475                                 for (index = 0; index < (128); index++) {
476
477                                         WRITE_FLASH(kFlash_Addr1,
478                                                     kFlash_Data1);
479                                         WRITE_FLASH(kFlash_Addr2,
480                                                     kFlash_Data2);
481                                         WRITE_FLASH(kFlash_Addr1,
482                                                     kFlash_Prog);
483                                         *((volatile unsigned char *)
484                                           burn_addr) =
485                  (volatile unsigned char) rom[index];
486
487                                         while ((!dqpoll
488                                                 (burn_addr,
489                                                  (volatile unsigned char)
490                                                  rom[index]))
491                                                && (!timeout(burn_addr))) {
492                                         }
493                                         burn_addr++;
494                                 }
495                                 restore_flags(flags);
496                                 if (*
497                                     ((volatile unsigned char *) (burn_addr
498                                                                  - 1)) ==
499                                     (volatile unsigned char) rom[index -
500                                                                  1]) {
501                                 } else if (timeout) {
502                                         printk("Program timed out\r\n");
503                                 }
504
505
506                         }
507                         kfree(rom);
508
509                         break;
510                 }
511
512 //  read the flash all at once
513
514         case FLASH_Read:{
515
516                         unsigned char *user_bytes;
517                         volatile unsigned long read_addr;
518                         int i;
519
520                         user_bytes =
521                             &(((struct lcd_display *) arg)->RomImage[0]);
522
523                         if (!access_ok
524                             (VERIFY_WRITE, user_bytes, FLASH_SIZE))
525                                 return -EFAULT;
526
527                         printk("Reading Flash");
528                         for (i = 0; i < FLASH_SIZE; i++) {
529                                 unsigned char tmp_byte;
530                                 read_addr = kFlashBase + i;
531                                 tmp_byte =
532                                     *((volatile unsigned char *)
533                                       read_addr);
534                                 if (__put_user(tmp_byte, &user_bytes[i]))
535                                         return -EFAULT;
536                         }
537
538
539                         break;
540                 }
541
542         default:
543                 return 0;
544                 break;
545
546         }
547
548         return 0;
549
550 }
551
552 static int lcd_open(struct inode *inode, struct file *file)
553 {
554         if (!lcd_present)
555                 return -ENXIO;
556         else
557                 return 0;
558 }
559
560 /* Only RESET or NEXT counts as button pressed */
561
562 static inline int button_pressed(void)
563 {
564         unsigned long buttons = GPIRead;
565
566         if ((buttons == BUTTON_Next) || (buttons == BUTTON_Next_B)
567             || (buttons == BUTTON_Reset_B))
568                 return buttons;
569         return 0;
570 }
571
572 /* LED daemon sits on this and we wake him up once a key is pressed. */
573
574 static int lcd_waiters = 0;
575
576 static long lcd_read(struct inode *inode, struct file *file, char *buf,
577                      unsigned long count)
578 {
579         long buttons_now;
580
581         if (lcd_waiters > 0)
582                 return -EINVAL;
583
584         lcd_waiters++;
585         while (((buttons_now = (long) button_pressed()) == 0) &&
586                !(signal_pending(current))) {
587                 msleep_interruptible(2000);
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");