Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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