diff options
-rw-r--r-- | drivers/video/broadsheetfb.c | 501 | ||||
-rw-r--r-- | include/video/broadsheetfb.h | 5 |
2 files changed, 505 insertions, 1 deletions
diff --git a/drivers/video/broadsheetfb.c b/drivers/video/broadsheetfb.c index 57dc1a0065c2..ebda6876d3a9 100644 --- a/drivers/video/broadsheetfb.c +++ b/drivers/video/broadsheetfb.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/list.h> | 31 | #include <linux/list.h> |
32 | #include <linux/firmware.h> | ||
32 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
33 | 34 | ||
34 | #include <video/broadsheetfb.h> | 35 | #include <video/broadsheetfb.h> |
@@ -306,6 +307,473 @@ static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg) | |||
306 | return broadsheet_get_data(par); | 307 | return broadsheet_get_data(par); |
307 | } | 308 | } |
308 | 309 | ||
310 | /* functions for waveform manipulation */ | ||
311 | static int is_broadsheet_pll_locked(struct broadsheetfb_par *par) | ||
312 | { | ||
313 | return broadsheet_read_reg(par, 0x000A) & 0x0001; | ||
314 | } | ||
315 | |||
316 | static int broadsheet_setup_plls(struct broadsheetfb_par *par) | ||
317 | { | ||
318 | int retry_count = 0; | ||
319 | u16 tmp; | ||
320 | |||
321 | /* disable arral saemipu mode */ | ||
322 | broadsheet_write_reg(par, 0x0006, 0x0000); | ||
323 | |||
324 | broadsheet_write_reg(par, 0x0010, 0x0004); | ||
325 | broadsheet_write_reg(par, 0x0012, 0x5949); | ||
326 | broadsheet_write_reg(par, 0x0014, 0x0040); | ||
327 | broadsheet_write_reg(par, 0x0016, 0x0000); | ||
328 | |||
329 | do { | ||
330 | if (retry_count++ > 100) | ||
331 | return -ETIMEDOUT; | ||
332 | mdelay(1); | ||
333 | } while (!is_broadsheet_pll_locked(par)); | ||
334 | |||
335 | tmp = broadsheet_read_reg(par, 0x0006); | ||
336 | tmp &= ~0x1; | ||
337 | broadsheet_write_reg(par, 0x0006, tmp); | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int broadsheet_setup_spi(struct broadsheetfb_par *par) | ||
343 | { | ||
344 | |||
345 | broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1)); | ||
346 | broadsheet_write_reg(par, 0x0208, 0x0001); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int broadsheet_setup_spiflash(struct broadsheetfb_par *par, | ||
352 | u16 *orig_sfmcd) | ||
353 | { | ||
354 | |||
355 | *orig_sfmcd = broadsheet_read_reg(par, 0x0204); | ||
356 | broadsheet_write_reg(par, 0x0208, 0); | ||
357 | broadsheet_write_reg(par, 0x0204, 0); | ||
358 | broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1)); | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int broadsheet_spiflash_wait_for_bit(struct broadsheetfb_par *par, | ||
364 | u16 reg, int bitnum, int val, | ||
365 | int timeout) | ||
366 | { | ||
367 | u16 tmp; | ||
368 | |||
369 | do { | ||
370 | tmp = broadsheet_read_reg(par, reg); | ||
371 | if (((tmp >> bitnum) & 1) == val) | ||
372 | return 0; | ||
373 | mdelay(1); | ||
374 | } while (timeout--); | ||
375 | |||
376 | return -ETIMEDOUT; | ||
377 | } | ||
378 | |||
379 | static int broadsheet_spiflash_write_byte(struct broadsheetfb_par *par, u8 data) | ||
380 | { | ||
381 | broadsheet_write_reg(par, 0x0202, (data | 0x100)); | ||
382 | |||
383 | return broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100); | ||
384 | } | ||
385 | |||
386 | static int broadsheet_spiflash_read_byte(struct broadsheetfb_par *par, u8 *data) | ||
387 | { | ||
388 | int err; | ||
389 | u16 tmp; | ||
390 | |||
391 | broadsheet_write_reg(par, 0x0202, 0); | ||
392 | |||
393 | err = broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100); | ||
394 | if (err) | ||
395 | return err; | ||
396 | |||
397 | tmp = broadsheet_read_reg(par, 0x200); | ||
398 | |||
399 | *data = tmp & 0xFF; | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int broadsheet_spiflash_wait_for_status(struct broadsheetfb_par *par, | ||
405 | int timeout) | ||
406 | { | ||
407 | u8 tmp; | ||
408 | int err; | ||
409 | |||
410 | do { | ||
411 | broadsheet_write_reg(par, 0x0208, 1); | ||
412 | |||
413 | err = broadsheet_spiflash_write_byte(par, 0x05); | ||
414 | if (err) | ||
415 | goto failout; | ||
416 | |||
417 | err = broadsheet_spiflash_read_byte(par, &tmp); | ||
418 | if (err) | ||
419 | goto failout; | ||
420 | |||
421 | broadsheet_write_reg(par, 0x0208, 0); | ||
422 | |||
423 | if (!(tmp & 0x1)) | ||
424 | return 0; | ||
425 | |||
426 | mdelay(5); | ||
427 | } while (timeout--); | ||
428 | |||
429 | dev_err(par->info->device, "Timed out waiting for spiflash status\n"); | ||
430 | return -ETIMEDOUT; | ||
431 | |||
432 | failout: | ||
433 | broadsheet_write_reg(par, 0x0208, 0); | ||
434 | return err; | ||
435 | } | ||
436 | |||
437 | static int broadsheet_spiflash_op_on_address(struct broadsheetfb_par *par, | ||
438 | u8 op, u32 addr) | ||
439 | { | ||
440 | int i; | ||
441 | u8 tmp; | ||
442 | int err; | ||
443 | |||
444 | broadsheet_write_reg(par, 0x0208, 1); | ||
445 | |||
446 | err = broadsheet_spiflash_write_byte(par, op); | ||
447 | if (err) | ||
448 | return err; | ||
449 | |||
450 | for (i = 2; i >= 0; i--) { | ||
451 | tmp = ((addr >> (i * 8)) & 0xFF); | ||
452 | err = broadsheet_spiflash_write_byte(par, tmp); | ||
453 | if (err) | ||
454 | return err; | ||
455 | } | ||
456 | |||
457 | return err; | ||
458 | } | ||
459 | |||
460 | static int broadsheet_verify_spiflash(struct broadsheetfb_par *par, | ||
461 | int *flash_type) | ||
462 | { | ||
463 | int err = 0; | ||
464 | u8 sig; | ||
465 | |||
466 | err = broadsheet_spiflash_op_on_address(par, 0xAB, 0x00000000); | ||
467 | if (err) | ||
468 | goto failout; | ||
469 | |||
470 | err = broadsheet_spiflash_read_byte(par, &sig); | ||
471 | if (err) | ||
472 | goto failout; | ||
473 | |||
474 | if ((sig != 0x10) && (sig != 0x11)) { | ||
475 | dev_err(par->info->device, "Unexpected flash type\n"); | ||
476 | err = -EINVAL; | ||
477 | goto failout; | ||
478 | } | ||
479 | |||
480 | *flash_type = sig; | ||
481 | |||
482 | failout: | ||
483 | broadsheet_write_reg(par, 0x0208, 0); | ||
484 | return err; | ||
485 | } | ||
486 | |||
487 | static int broadsheet_setup_for_wfm_write(struct broadsheetfb_par *par, | ||
488 | u16 *initial_sfmcd, int *flash_type) | ||
489 | |||
490 | { | ||
491 | int err; | ||
492 | |||
493 | err = broadsheet_setup_plls(par); | ||
494 | if (err) | ||
495 | return err; | ||
496 | |||
497 | broadsheet_write_reg(par, 0x0106, 0x0203); | ||
498 | |||
499 | err = broadsheet_setup_spi(par); | ||
500 | if (err) | ||
501 | return err; | ||
502 | |||
503 | err = broadsheet_setup_spiflash(par, initial_sfmcd); | ||
504 | if (err) | ||
505 | return err; | ||
506 | |||
507 | return broadsheet_verify_spiflash(par, flash_type); | ||
508 | } | ||
509 | |||
510 | static int broadsheet_spiflash_write_control(struct broadsheetfb_par *par, | ||
511 | int mode) | ||
512 | { | ||
513 | int err; | ||
514 | |||
515 | broadsheet_write_reg(par, 0x0208, 1); | ||
516 | if (mode) | ||
517 | err = broadsheet_spiflash_write_byte(par, 0x06); | ||
518 | else | ||
519 | err = broadsheet_spiflash_write_byte(par, 0x04); | ||
520 | |||
521 | broadsheet_write_reg(par, 0x0208, 0); | ||
522 | return err; | ||
523 | } | ||
524 | |||
525 | static int broadsheet_spiflash_erase_sector(struct broadsheetfb_par *par, | ||
526 | int addr) | ||
527 | { | ||
528 | int err; | ||
529 | |||
530 | broadsheet_spiflash_write_control(par, 1); | ||
531 | |||
532 | err = broadsheet_spiflash_op_on_address(par, 0xD8, addr); | ||
533 | |||
534 | broadsheet_write_reg(par, 0x0208, 0); | ||
535 | |||
536 | if (err) | ||
537 | return err; | ||
538 | |||
539 | err = broadsheet_spiflash_wait_for_status(par, 1000); | ||
540 | |||
541 | return err; | ||
542 | } | ||
543 | |||
544 | static int broadsheet_spiflash_read_range(struct broadsheetfb_par *par, | ||
545 | int addr, int size, char *data) | ||
546 | { | ||
547 | int err; | ||
548 | int i; | ||
549 | |||
550 | err = broadsheet_spiflash_op_on_address(par, 0x03, addr); | ||
551 | if (err) | ||
552 | goto failout; | ||
553 | |||
554 | for (i = 0; i < size; i++) { | ||
555 | err = broadsheet_spiflash_read_byte(par, &data[i]); | ||
556 | if (err) | ||
557 | goto failout; | ||
558 | } | ||
559 | |||
560 | failout: | ||
561 | broadsheet_write_reg(par, 0x0208, 0); | ||
562 | return err; | ||
563 | } | ||
564 | |||
565 | #define BS_SPIFLASH_PAGE_SIZE 256 | ||
566 | static int broadsheet_spiflash_write_page(struct broadsheetfb_par *par, | ||
567 | int addr, const char *data) | ||
568 | { | ||
569 | int err; | ||
570 | int i; | ||
571 | |||
572 | broadsheet_spiflash_write_control(par, 1); | ||
573 | |||
574 | err = broadsheet_spiflash_op_on_address(par, 0x02, addr); | ||
575 | if (err) | ||
576 | goto failout; | ||
577 | |||
578 | for (i = 0; i < BS_SPIFLASH_PAGE_SIZE; i++) { | ||
579 | err = broadsheet_spiflash_write_byte(par, data[i]); | ||
580 | if (err) | ||
581 | goto failout; | ||
582 | } | ||
583 | |||
584 | broadsheet_write_reg(par, 0x0208, 0); | ||
585 | |||
586 | err = broadsheet_spiflash_wait_for_status(par, 100); | ||
587 | |||
588 | failout: | ||
589 | return err; | ||
590 | } | ||
591 | |||
592 | static int broadsheet_spiflash_write_sector(struct broadsheetfb_par *par, | ||
593 | int addr, const char *data, int sector_size) | ||
594 | { | ||
595 | int i; | ||
596 | int err; | ||
597 | |||
598 | for (i = 0; i < sector_size; i += BS_SPIFLASH_PAGE_SIZE) { | ||
599 | err = broadsheet_spiflash_write_page(par, addr + i, &data[i]); | ||
600 | if (err) | ||
601 | return err; | ||
602 | } | ||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | /* | ||
607 | * The caller must guarantee that the data to be rewritten is entirely | ||
608 | * contained within this sector. That is, data_start_addr + data_len | ||
609 | * must be less than sector_start_addr + sector_size. | ||
610 | */ | ||
611 | static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par, | ||
612 | int sector_size, int data_start_addr, | ||
613 | int data_len, const char *data) | ||
614 | { | ||
615 | int err; | ||
616 | char *sector_buffer; | ||
617 | int tail_start_addr; | ||
618 | int start_sector_addr; | ||
619 | |||
620 | sector_buffer = kzalloc(sizeof(char)*sector_size, GFP_KERNEL); | ||
621 | if (!sector_buffer) | ||
622 | return -ENOMEM; | ||
623 | |||
624 | /* the start address of the sector is the 0th byte of that sector */ | ||
625 | start_sector_addr = (data_start_addr / sector_size) * sector_size; | ||
626 | |||
627 | /* | ||
628 | * check if there is head data that we need to readback into our sector | ||
629 | * buffer first | ||
630 | */ | ||
631 | if (data_start_addr != start_sector_addr) { | ||
632 | /* | ||
633 | * we need to read every byte up till the start address of our | ||
634 | * data and we put it into our sector buffer. | ||
635 | */ | ||
636 | err = broadsheet_spiflash_read_range(par, start_sector_addr, | ||
637 | data_start_addr, sector_buffer); | ||
638 | if (err) | ||
639 | return err; | ||
640 | } | ||
641 | |||
642 | /* now we copy our data into the right place in the sector buffer */ | ||
643 | memcpy(sector_buffer + data_start_addr, data, data_len); | ||
644 | |||
645 | /* | ||
646 | * now we check if there is a tail section of the sector that we need to | ||
647 | * readback. | ||
648 | */ | ||
649 | tail_start_addr = (data_start_addr + data_len) % sector_size; | ||
650 | |||
651 | if (tail_start_addr) { | ||
652 | int tail_len; | ||
653 | |||
654 | tail_len = sector_size - tail_start_addr; | ||
655 | |||
656 | /* now we read this tail into our sector buffer */ | ||
657 | err = broadsheet_spiflash_read_range(par, tail_start_addr, | ||
658 | tail_len, sector_buffer + tail_start_addr); | ||
659 | if (err) | ||
660 | return err; | ||
661 | } | ||
662 | |||
663 | /* if we got here we have the full sector that we want to rewrite. */ | ||
664 | |||
665 | /* first erase the sector */ | ||
666 | err = broadsheet_spiflash_erase_sector(par, start_sector_addr); | ||
667 | if (err) | ||
668 | return err; | ||
669 | |||
670 | /* now write it */ | ||
671 | err = broadsheet_spiflash_write_sector(par, start_sector_addr, | ||
672 | sector_buffer, sector_size); | ||
673 | return err; | ||
674 | } | ||
675 | |||
676 | static int broadsheet_write_spiflash(struct broadsheetfb_par *par, u32 wfm_addr, | ||
677 | const u8 *wfm, int bytecount, int flash_type) | ||
678 | { | ||
679 | int sector_size; | ||
680 | int err; | ||
681 | int cur_addr; | ||
682 | int writecount; | ||
683 | int maxlen; | ||
684 | int offset = 0; | ||
685 | |||
686 | switch (flash_type) { | ||
687 | case 0x10: | ||
688 | sector_size = 32*1024; | ||
689 | break; | ||
690 | case 0x11: | ||
691 | default: | ||
692 | sector_size = 64*1024; | ||
693 | break; | ||
694 | } | ||
695 | |||
696 | while (bytecount) { | ||
697 | cur_addr = wfm_addr + offset; | ||
698 | maxlen = roundup(cur_addr, sector_size) - cur_addr; | ||
699 | writecount = min(bytecount, maxlen); | ||
700 | |||
701 | err = broadsheet_spiflash_rewrite_sector(par, sector_size, | ||
702 | cur_addr, writecount, wfm + offset); | ||
703 | if (err) | ||
704 | return err; | ||
705 | |||
706 | offset += writecount; | ||
707 | bytecount -= writecount; | ||
708 | } | ||
709 | |||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | static int broadsheet_store_waveform_to_spiflash(struct broadsheetfb_par *par, | ||
714 | const u8 *wfm, size_t wfm_size) | ||
715 | { | ||
716 | int err = 0; | ||
717 | u16 initial_sfmcd = 0; | ||
718 | int flash_type = 0; | ||
719 | |||
720 | err = broadsheet_setup_for_wfm_write(par, &initial_sfmcd, &flash_type); | ||
721 | if (err) | ||
722 | goto failout; | ||
723 | |||
724 | err = broadsheet_write_spiflash(par, 0x886, wfm, wfm_size, flash_type); | ||
725 | |||
726 | failout: | ||
727 | broadsheet_write_reg(par, 0x0204, initial_sfmcd); | ||
728 | return err; | ||
729 | } | ||
730 | |||
731 | static ssize_t broadsheet_loadstore_waveform(struct device *dev, | ||
732 | struct device_attribute *attr, | ||
733 | const char *buf, size_t len) | ||
734 | { | ||
735 | int err; | ||
736 | struct fb_info *info = dev_get_drvdata(dev); | ||
737 | struct broadsheetfb_par *par = info->par; | ||
738 | const struct firmware *fw_entry; | ||
739 | |||
740 | if (len < 1) | ||
741 | return -EINVAL; | ||
742 | |||
743 | err = request_firmware(&fw_entry, "broadsheet.wbf", dev); | ||
744 | if (err < 0) { | ||
745 | dev_err(dev, "Failed to get broadsheet waveform\n"); | ||
746 | goto err_failed; | ||
747 | } | ||
748 | |||
749 | /* try to enforce reasonable min max on waveform */ | ||
750 | if ((fw_entry->size < 8*1024) || (fw_entry->size > 64*1024)) { | ||
751 | dev_err(dev, "Invalid waveform\n"); | ||
752 | err = -EINVAL; | ||
753 | goto err_failed; | ||
754 | } | ||
755 | |||
756 | mutex_lock(&(par->io_lock)); | ||
757 | err = broadsheet_store_waveform_to_spiflash(par, fw_entry->data, | ||
758 | fw_entry->size); | ||
759 | |||
760 | mutex_unlock(&(par->io_lock)); | ||
761 | if (err < 0) { | ||
762 | dev_err(dev, "Failed to store broadsheet waveform\n"); | ||
763 | goto err_failed; | ||
764 | } | ||
765 | |||
766 | dev_info(dev, "Stored broadsheet waveform, size %zd\n", fw_entry->size); | ||
767 | |||
768 | return len; | ||
769 | |||
770 | err_failed: | ||
771 | return err; | ||
772 | } | ||
773 | static DEVICE_ATTR(loadstore_waveform, S_IWUSR, NULL, | ||
774 | broadsheet_loadstore_waveform); | ||
775 | |||
776 | /* upper level functions that manipulate the display and other stuff */ | ||
309 | static void __devinit broadsheet_init_display(struct broadsheetfb_par *par) | 777 | static void __devinit broadsheet_init_display(struct broadsheetfb_par *par) |
310 | { | 778 | { |
311 | u16 args[5]; | 779 | u16 args[5]; |
@@ -366,6 +834,21 @@ static void __devinit broadsheet_init_display(struct broadsheetfb_par *par) | |||
366 | par->board->wait_for_rdy(par); | 834 | par->board->wait_for_rdy(par); |
367 | } | 835 | } |
368 | 836 | ||
837 | static void __devinit broadsheet_identify(struct broadsheetfb_par *par) | ||
838 | { | ||
839 | u16 rev, prc; | ||
840 | struct device *dev = par->info->device; | ||
841 | |||
842 | rev = broadsheet_read_reg(par, BS_REG_REV); | ||
843 | prc = broadsheet_read_reg(par, BS_REG_PRC); | ||
844 | dev_info(dev, "Broadsheet Rev 0x%x, Product Code 0x%x\n", rev, prc); | ||
845 | |||
846 | if (prc != 0x0047) | ||
847 | dev_warn(dev, "Unrecognized Broadsheet Product Code\n"); | ||
848 | if (rev != 0x0100) | ||
849 | dev_warn(dev, "Unrecognized Broadsheet Revision\n"); | ||
850 | } | ||
851 | |||
369 | static void __devinit broadsheet_init(struct broadsheetfb_par *par) | 852 | static void __devinit broadsheet_init(struct broadsheetfb_par *par) |
370 | { | 853 | { |
371 | broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN); | 854 | broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN); |
@@ -380,6 +863,7 @@ static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par, | |||
380 | u16 args[5]; | 863 | u16 args[5]; |
381 | unsigned char *buf = (unsigned char *)par->info->screen_base; | 864 | unsigned char *buf = (unsigned char *)par->info->screen_base; |
382 | 865 | ||
866 | mutex_lock(&(par->io_lock)); | ||
383 | /* y1 must be a multiple of 4 so drop the lower bits */ | 867 | /* y1 must be a multiple of 4 so drop the lower bits */ |
384 | y1 &= 0xFFFC; | 868 | y1 &= 0xFFFC; |
385 | /* y2 must be a multiple of 4 , but - 1 so up the lower bits */ | 869 | /* y2 must be a multiple of 4 , but - 1 so up the lower bits */ |
@@ -409,6 +893,7 @@ static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par, | |||
409 | broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); | 893 | broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); |
410 | 894 | ||
411 | par->board->wait_for_rdy(par); | 895 | par->board->wait_for_rdy(par); |
896 | mutex_unlock(&(par->io_lock)); | ||
412 | 897 | ||
413 | } | 898 | } |
414 | 899 | ||
@@ -416,6 +901,7 @@ static void broadsheetfb_dpy_update(struct broadsheetfb_par *par) | |||
416 | { | 901 | { |
417 | u16 args[5]; | 902 | u16 args[5]; |
418 | 903 | ||
904 | mutex_lock(&(par->io_lock)); | ||
419 | args[0] = 0x3 << 4; | 905 | args[0] = 0x3 << 4; |
420 | broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args); | 906 | broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args); |
421 | 907 | ||
@@ -435,7 +921,7 @@ static void broadsheetfb_dpy_update(struct broadsheetfb_par *par) | |||
435 | broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); | 921 | broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); |
436 | 922 | ||
437 | par->board->wait_for_rdy(par); | 923 | par->board->wait_for_rdy(par); |
438 | 924 | mutex_unlock(&(par->io_lock)); | |
439 | } | 925 | } |
440 | 926 | ||
441 | /* this is called back from the deferred io workqueue */ | 927 | /* this is called back from the deferred io workqueue */ |
@@ -641,6 +1127,8 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev) | |||
641 | par->read_reg = broadsheet_read_reg; | 1127 | par->read_reg = broadsheet_read_reg; |
642 | init_waitqueue_head(&par->waitq); | 1128 | init_waitqueue_head(&par->waitq); |
643 | 1129 | ||
1130 | mutex_init(&par->io_lock); | ||
1131 | |||
644 | info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; | 1132 | info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; |
645 | 1133 | ||
646 | info->fbdefio = &broadsheetfb_defio; | 1134 | info->fbdefio = &broadsheetfb_defio; |
@@ -667,13 +1155,20 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev) | |||
667 | if (retval < 0) | 1155 | if (retval < 0) |
668 | goto err_free_irq; | 1156 | goto err_free_irq; |
669 | 1157 | ||
1158 | broadsheet_identify(par); | ||
1159 | |||
670 | broadsheet_init(par); | 1160 | broadsheet_init(par); |
671 | 1161 | ||
672 | retval = register_framebuffer(info); | 1162 | retval = register_framebuffer(info); |
673 | if (retval < 0) | 1163 | if (retval < 0) |
674 | goto err_free_irq; | 1164 | goto err_free_irq; |
1165 | |||
675 | platform_set_drvdata(dev, info); | 1166 | platform_set_drvdata(dev, info); |
676 | 1167 | ||
1168 | retval = device_create_file(&dev->dev, &dev_attr_loadstore_waveform); | ||
1169 | if (retval < 0) | ||
1170 | goto err_unreg_fb; | ||
1171 | |||
677 | printk(KERN_INFO | 1172 | printk(KERN_INFO |
678 | "fb%d: Broadsheet frame buffer, using %dK of video memory\n", | 1173 | "fb%d: Broadsheet frame buffer, using %dK of video memory\n", |
679 | info->node, videomemorysize >> 10); | 1174 | info->node, videomemorysize >> 10); |
@@ -681,6 +1176,8 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev) | |||
681 | 1176 | ||
682 | return 0; | 1177 | return 0; |
683 | 1178 | ||
1179 | err_unreg_fb: | ||
1180 | unregister_framebuffer(info); | ||
684 | err_free_irq: | 1181 | err_free_irq: |
685 | board->cleanup(par); | 1182 | board->cleanup(par); |
686 | err_cmap: | 1183 | err_cmap: |
@@ -701,6 +1198,8 @@ static int __devexit broadsheetfb_remove(struct platform_device *dev) | |||
701 | 1198 | ||
702 | if (info) { | 1199 | if (info) { |
703 | struct broadsheetfb_par *par = info->par; | 1200 | struct broadsheetfb_par *par = info->par; |
1201 | |||
1202 | device_remove_file(info->dev, &dev_attr_loadstore_waveform); | ||
704 | unregister_framebuffer(info); | 1203 | unregister_framebuffer(info); |
705 | fb_deferred_io_cleanup(info); | 1204 | fb_deferred_io_cleanup(info); |
706 | par->board->cleanup(par); | 1205 | par->board->cleanup(par); |
diff --git a/include/video/broadsheetfb.h b/include/video/broadsheetfb.h index d65b6689e92c..548d28f4ec67 100644 --- a/include/video/broadsheetfb.h +++ b/include/video/broadsheetfb.h | |||
@@ -29,6 +29,10 @@ | |||
29 | #define BS_CMD_UPD_FULL 0x33 | 29 | #define BS_CMD_UPD_FULL 0x33 |
30 | #define BS_CMD_UPD_GDRV_CLR 0x37 | 30 | #define BS_CMD_UPD_GDRV_CLR 0x37 |
31 | 31 | ||
32 | /* Broadsheet register interface defines */ | ||
33 | #define BS_REG_REV 0x00 | ||
34 | #define BS_REG_PRC 0x02 | ||
35 | |||
32 | /* Broadsheet pin interface specific defines */ | 36 | /* Broadsheet pin interface specific defines */ |
33 | #define BS_CS 0x01 | 37 | #define BS_CS 0x01 |
34 | #define BS_DC 0x02 | 38 | #define BS_DC 0x02 |
@@ -46,6 +50,7 @@ struct broadsheetfb_par { | |||
46 | u16 (*read_reg)(struct broadsheetfb_par *, u16 reg); | 50 | u16 (*read_reg)(struct broadsheetfb_par *, u16 reg); |
47 | wait_queue_head_t waitq; | 51 | wait_queue_head_t waitq; |
48 | int panel_index; | 52 | int panel_index; |
53 | struct mutex io_lock; | ||
49 | }; | 54 | }; |
50 | 55 | ||
51 | /* board specific routines */ | 56 | /* board specific routines */ |