Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/dtor/input
[pandora-kernel.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/types.h>
18 #include <linux/errno.h>
19 #include <linux/miscdevice.h>
20 #include <linux/slab.h>
21 #include <linux/ioport.h>
22 #include <linux/fcntl.h>
23 #include <linux/mc146818rtc.h>
24 #include <linux/netdevice.h>
25 #include <linux/sched.h>
26 #include <linux/delay.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 DEFINE_SPINLOCK(lcd_lock);
36
37 static int lcd_ioctl(struct inode *inode, struct file *file,
38                      unsigned int cmd, unsigned long arg);
39
40 static unsigned int lcd_present = 1;
41
42 /* used in arch/mips/cobalt/reset.c */
43 int led_state = 0;
44
45 #if defined(CONFIG_TULIP) && 0
46
47 #define MAX_INTERFACES  8
48 static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES];
49 static void *linkcheck_cookies[MAX_INTERFACES];
50
51 int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie)
52 {
53         if (iface_num < 0 ||
54             iface_num >= MAX_INTERFACES ||
55             linkcheck_callbacks[iface_num] != NULL)
56                 return -1;
57         linkcheck_callbacks[iface_num] = (linkcheck_func_t) func;
58         linkcheck_cookies[iface_num] = cookie;
59         return 0;
60 }
61 #endif
62
63 static int lcd_ioctl(struct inode *inode, struct file *file,
64                      unsigned int cmd, unsigned long arg)
65 {
66         struct lcd_display button_display;
67         unsigned long address, a;
68
69         switch (cmd) {
70         case LCD_On:
71                 udelay(150);
72                 BusyCheck();
73                 LCDWriteInst(0x0F);
74                 break;
75
76         case LCD_Off:
77                 udelay(150);
78                 BusyCheck();
79                 LCDWriteInst(0x08);
80                 break;
81
82         case LCD_Reset:
83                 udelay(150);
84                 LCDWriteInst(0x3F);
85                 udelay(150);
86                 LCDWriteInst(0x3F);
87                 udelay(150);
88                 LCDWriteInst(0x3F);
89                 udelay(150);
90                 LCDWriteInst(0x3F);
91                 udelay(150);
92                 LCDWriteInst(0x01);
93                 udelay(150);
94                 LCDWriteInst(0x06);
95                 break;
96
97         case LCD_Clear:
98                 udelay(150);
99                 BusyCheck();
100                 LCDWriteInst(0x01);
101                 break;
102
103         case LCD_Cursor_Left:
104                 udelay(150);
105                 BusyCheck();
106                 LCDWriteInst(0x10);
107                 break;
108
109         case LCD_Cursor_Right:
110                 udelay(150);
111                 BusyCheck();
112                 LCDWriteInst(0x14);
113                 break;
114
115         case LCD_Cursor_Off:
116                 udelay(150);
117                 BusyCheck();
118                 LCDWriteInst(0x0C);
119                 break;
120
121         case LCD_Cursor_On:
122                 udelay(150);
123                 BusyCheck();
124                 LCDWriteInst(0x0F);
125                 break;
126
127         case LCD_Blink_Off:
128                 udelay(150);
129                 BusyCheck();
130                 LCDWriteInst(0x0E);
131                 break;
132
133         case LCD_Get_Cursor_Pos:{
134                         struct lcd_display display;
135
136                         udelay(150);
137                         BusyCheck();
138                         display.cursor_address = (LCDReadInst);
139                         display.cursor_address =
140                             (display.cursor_address & 0x07F);
141                         if (copy_to_user
142                             ((struct lcd_display *) arg, &display,
143                              sizeof(struct lcd_display)))
144                                 return -EFAULT;
145
146                         break;
147                 }
148
149
150         case LCD_Set_Cursor_Pos:{
151                         struct lcd_display display;
152
153                         if (copy_from_user
154                             (&display, (struct lcd_display *) arg,
155                              sizeof(struct lcd_display)))
156                                 return -EFAULT;
157
158                         a = (display.cursor_address | kLCD_Addr);
159
160                         udelay(150);
161                         BusyCheck();
162                         LCDWriteInst(a);
163
164                         break;
165                 }
166
167         case LCD_Get_Cursor:{
168                         struct lcd_display display;
169
170                         udelay(150);
171                         BusyCheck();
172                         display.character = LCDReadData;
173
174                         if (copy_to_user
175                             ((struct lcd_display *) arg, &display,
176                              sizeof(struct lcd_display)))
177                                 return -EFAULT;
178                         udelay(150);
179                         BusyCheck();
180                         LCDWriteInst(0x10);
181
182                         break;
183                 }
184
185         case LCD_Set_Cursor:{
186                         struct lcd_display display;
187
188                         if (copy_from_user
189                             (&display, (struct lcd_display *) arg,
190                              sizeof(struct lcd_display)))
191                                 return -EFAULT;
192
193                         udelay(150);
194                         BusyCheck();
195                         LCDWriteData(display.character);
196                         udelay(150);
197                         BusyCheck();
198                         LCDWriteInst(0x10);
199
200                         break;
201                 }
202
203
204         case LCD_Disp_Left:
205                 udelay(150);
206                 BusyCheck();
207                 LCDWriteInst(0x18);
208                 break;
209
210         case LCD_Disp_Right:
211                 udelay(150);
212                 BusyCheck();
213                 LCDWriteInst(0x1C);
214                 break;
215
216         case LCD_Home:
217                 udelay(150);
218                 BusyCheck();
219                 LCDWriteInst(0x02);
220                 break;
221
222         case LCD_Write:{
223                         struct lcd_display display;
224                         unsigned int index;
225
226
227                         if (copy_from_user
228                             (&display, (struct lcd_display *) arg,
229                              sizeof(struct lcd_display)))
230                                 return -EFAULT;
231
232                         udelay(150);
233                         BusyCheck();
234                         LCDWriteInst(0x80);
235                         udelay(150);
236                         BusyCheck();
237
238                         for (index = 0; index < (display.size1); index++) {
239                                 udelay(150);
240                                 BusyCheck();
241                                 LCDWriteData(display.line1[index]);
242                                 BusyCheck();
243                         }
244
245                         udelay(150);
246                         BusyCheck();
247                         LCDWriteInst(0xC0);
248                         udelay(150);
249                         BusyCheck();
250                         for (index = 0; index < (display.size2); index++) {
251                                 udelay(150);
252                                 BusyCheck();
253                                 LCDWriteData(display.line2[index]);
254                         }
255
256                         break;
257                 }
258
259         case LCD_Read:{
260                         struct lcd_display display;
261
262                         BusyCheck();
263                         for (address = kDD_R00; address <= kDD_R01;
264                              address++) {
265                                 a = (address | kLCD_Addr);
266
267                                 udelay(150);
268                                 BusyCheck();
269                                 LCDWriteInst(a);
270                                 udelay(150);
271                                 BusyCheck();
272                                 display.line1[address] = LCDReadData;
273                         }
274
275                         display.line1[0x27] = '\0';
276
277                         for (address = kDD_R10; address <= kDD_R11;
278                              address++) {
279                                 a = (address | kLCD_Addr);
280
281                                 udelay(150);
282                                 BusyCheck();
283                                 LCDWriteInst(a);
284
285                                 udelay(150);
286                                 BusyCheck();
287                                 display.line2[address - 0x40] =
288                                     LCDReadData;
289                         }
290
291                         display.line2[0x27] = '\0';
292
293                         if (copy_to_user
294                             ((struct lcd_display *) arg, &display,
295                              sizeof(struct lcd_display)))
296                                 return -EFAULT;
297                         break;
298                 }
299
300 //  set all GPIO leds to led_display.leds
301
302         case LED_Set:{
303                         struct lcd_display led_display;
304
305
306                         if (copy_from_user
307                             (&led_display, (struct lcd_display *) arg,
308                              sizeof(struct lcd_display)))
309                                 return -EFAULT;
310
311                         led_state = led_display.leds;
312                         LEDSet(led_state);
313
314                         break;
315                 }
316
317
318 //  set only bit led_display.leds
319
320         case LED_Bit_Set:{
321                         unsigned int i;
322                         int bit = 1;
323                         struct lcd_display led_display;
324
325
326                         if (copy_from_user
327                             (&led_display, (struct lcd_display *) arg,
328                              sizeof(struct lcd_display)))
329                                 return -EFAULT;
330
331                         for (i = 0; i < (int) led_display.leds; i++) {
332                                 bit = 2 * bit;
333                         }
334
335                         led_state = led_state | bit;
336                         LEDSet(led_state);
337                         break;
338                 }
339
340 //  clear only bit led_display.leds
341
342         case LED_Bit_Clear:{
343                         unsigned int i;
344                         int bit = 1;
345                         struct lcd_display led_display;
346
347
348                         if (copy_from_user
349                             (&led_display, (struct lcd_display *) arg,
350                              sizeof(struct lcd_display)))
351                                 return -EFAULT;
352
353                         for (i = 0; i < (int) led_display.leds; i++) {
354                                 bit = 2 * bit;
355                         }
356
357                         led_state = led_state & ~bit;
358                         LEDSet(led_state);
359                         break;
360                 }
361
362
363         case BUTTON_Read:{
364                         button_display.buttons = GPIRead;
365                         if (copy_to_user
366                             ((struct lcd_display *) arg, &button_display,
367                              sizeof(struct lcd_display)))
368                                 return -EFAULT;
369                         break;
370                 }
371
372         case LINK_Check:{
373                         button_display.buttons =
374                             *((volatile unsigned long *) (0xB0100060));
375                         if (copy_to_user
376                             ((struct lcd_display *) arg, &button_display,
377                              sizeof(struct lcd_display)))
378                                 return -EFAULT;
379                         break;
380                 }
381
382         case LINK_Check_2:{
383                         int iface_num;
384
385                         /* panel-utils should pass in the desired interface status is wanted for
386                          * in "buttons" of the structure.  We will set this to non-zero if the
387                          * link is in fact up for the requested interface.  --DaveM
388                          */
389                         if (copy_from_user
390                             (&button_display, (struct lcd_display *) arg,
391                              sizeof(button_display)))
392                                 return -EFAULT;
393                         iface_num = button_display.buttons;
394 #if defined(CONFIG_TULIP) && 0
395                         if (iface_num >= 0 &&
396                             iface_num < MAX_INTERFACES &&
397                             linkcheck_callbacks[iface_num] != NULL) {
398                                 button_display.buttons =
399                                     linkcheck_callbacks[iface_num]
400                                     (linkcheck_cookies[iface_num]);
401                         } else
402 #endif
403                                 button_display.buttons = 0;
404
405                         if (__copy_to_user
406                             ((struct lcd_display *) arg, &button_display,
407                              sizeof(struct lcd_display)))
408                                 return -EFAULT;
409                         break;
410                 }
411
412         default:
413                 return -EINVAL;
414
415         }
416
417         return 0;
418
419 }
420
421 static int lcd_open(struct inode *inode, struct file *file)
422 {
423         if (!lcd_present)
424                 return -ENXIO;
425         else
426                 return 0;
427 }
428
429 /* Only RESET or NEXT counts as button pressed */
430
431 static inline int button_pressed(void)
432 {
433         unsigned long buttons = GPIRead;
434
435         if ((buttons == BUTTON_Next) || (buttons == BUTTON_Next_B)
436             || (buttons == BUTTON_Reset_B))
437                 return buttons;
438         return 0;
439 }
440
441 /* LED daemon sits on this and we wake him up once a key is pressed. */
442
443 static int lcd_waiters = 0;
444
445 static ssize_t lcd_read(struct file *file, char *buf,
446                      size_t count, loff_t *ofs)
447 {
448         long buttons_now;
449
450         if (lcd_waiters > 0)
451                 return -EINVAL;
452
453         lcd_waiters++;
454         while (((buttons_now = (long) button_pressed()) == 0) &&
455                !(signal_pending(current))) {
456                 msleep_interruptible(2000);
457         }
458         lcd_waiters--;
459
460         if (signal_pending(current))
461                 return -ERESTARTSYS;
462         return buttons_now;
463 }
464
465 /*
466  *      The various file operations we support.
467  */
468
469 static const struct file_operations lcd_fops = {
470         .read = lcd_read,
471         .ioctl = lcd_ioctl,
472         .open = lcd_open,
473 };
474
475 static struct miscdevice lcd_dev = {
476         MISC_DYNAMIC_MINOR,
477         "lcd",
478         &lcd_fops
479 };
480
481 static int lcd_init(void)
482 {
483         int ret;
484         unsigned long data;
485
486         pr_info("%s\n", LCD_DRIVER);
487         ret = misc_register(&lcd_dev);
488         if (ret) {
489                 printk(KERN_WARNING LCD "Unable to register misc device.\n");
490                 return ret;
491         }
492
493         /* Check region? Naaah! Just snarf it up. */
494 /*      request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/
495
496         udelay(150);
497         data = LCDReadData;
498         if ((data & 0x000000FF) == (0x00)) {
499                 lcd_present = 0;
500                 pr_info(LCD "LCD Not Present\n");
501         } else {
502                 lcd_present = 1;
503                 WRITE_GAL(kGal_DevBank2PReg, kGal_DevBank2Cfg);
504                 WRITE_GAL(kGal_DevBank3PReg, kGal_DevBank3Cfg);
505         }
506
507         return 0;
508 }
509
510 static void __exit lcd_exit(void)
511 {
512         misc_deregister(&lcd_dev);
513 }
514
515 module_init(lcd_init);
516 module_exit(lcd_exit);
517
518 MODULE_AUTHOR("Andrew Bose");
519 MODULE_LICENSE("GPL");