diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/tuner/lv24020lp.c | 152 |
1 files changed, 109 insertions, 43 deletions
diff --git a/firmware/drivers/tuner/lv24020lp.c b/firmware/drivers/tuner/lv24020lp.c index 9ec68f9a27..79d38443f2 100644 --- a/firmware/drivers/tuner/lv24020lp.c +++ b/firmware/drivers/tuner/lv24020lp.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "thread.h" | 24 | #include "thread.h" |
25 | #include "kernel.h" | 25 | #include "kernel.h" |
26 | #include "tuner.h" /* tuner abstraction interface */ | 26 | #include "tuner.h" /* tuner abstraction interface */ |
27 | #include "power.h" | ||
27 | #include "fmradio.h" /* physical interface driver */ | 28 | #include "fmradio.h" /* physical interface driver */ |
28 | #include "sound.h" | 29 | #include "sound.h" |
29 | #include "pp5024.h" | 30 | #include "pp5024.h" |
@@ -31,6 +32,8 @@ | |||
31 | 32 | ||
32 | #ifndef BOOTLOADER | 33 | #ifndef BOOTLOADER |
33 | 34 | ||
35 | static struct mutex tuner_mtx; | ||
36 | |||
34 | #if 0 | 37 | #if 0 |
35 | /* define to enable tuner logging */ | 38 | /* define to enable tuner logging */ |
36 | #define SANYO_TUNER_LOG | 39 | #define SANYO_TUNER_LOG |
@@ -338,6 +341,10 @@ static void lv24020lp_write(unsigned int address, unsigned int data) | |||
338 | break; | 341 | break; |
339 | } | 342 | } |
340 | 343 | ||
344 | /* Check if interface is turned on */ | ||
345 | if (!(tuner_status & TUNER_POWERED)) | ||
346 | return; | ||
347 | |||
341 | address = lv24020lp_begin_write(address); | 348 | address = lv24020lp_begin_write(address); |
342 | 349 | ||
343 | /* data first */ | 350 | /* data first */ |
@@ -365,6 +372,10 @@ static unsigned int lv24020lp_read(unsigned int address) | |||
365 | int i; | 372 | int i; |
366 | unsigned int toread; | 373 | unsigned int toread; |
367 | 374 | ||
375 | /* Check if interface is turned on */ | ||
376 | if (!(tuner_status & TUNER_POWERED)) | ||
377 | return 0; | ||
378 | |||
368 | address = lv24020lp_begin_write(address); | 379 | address = lv24020lp_begin_write(address); |
369 | 380 | ||
370 | /* address */ | 381 | /* address */ |
@@ -433,9 +444,6 @@ static int tuner_measure(unsigned char type, int scale, int duration) | |||
433 | { | 444 | { |
434 | int64_t finval; | 445 | int64_t finval; |
435 | 446 | ||
436 | if (!tuner_awake()) | ||
437 | return 0; | ||
438 | |||
439 | /* enable measuring */ | 447 | /* enable measuring */ |
440 | lv24020lp_write_or(MSRC_SEL, type); | 448 | lv24020lp_write_or(MSRC_SEL, type); |
441 | lv24020lp_write_and(CNT_CTRL, ~CNT_SEL); | 449 | lv24020lp_write_and(CNT_CTRL, ~CNT_SEL); |
@@ -463,19 +471,20 @@ static int tuner_measure(unsigned char type, int scale, int duration) | |||
463 | else | 471 | else |
464 | finval = scale*finval / duration; | 472 | finval = scale*finval / duration; |
465 | 473 | ||
474 | /* This function takes a loooong time and other stuff needs | ||
475 | running by now */ | ||
476 | yield(); | ||
477 | |||
466 | return (int)finval; | 478 | return (int)finval; |
467 | } | 479 | } |
468 | 480 | ||
469 | /* set the FM oscillator frequency */ | 481 | /* set the FM oscillator frequency */ |
470 | static void set_frequency(int freq) | 482 | static bool set_frequency(int freq) |
471 | { | 483 | { |
472 | int coef, cap_value, osc_value; | 484 | int coef, cap_value, osc_value; |
473 | int f1, f2, x1, x2; | 485 | int f1, f2, x1, x2; |
474 | int count; | 486 | int count; |
475 | 487 | ||
476 | if (!tuner_awake()) | ||
477 | return; | ||
478 | |||
479 | TUNER_LOG_OPEN(); | 488 | TUNER_LOG_OPEN(); |
480 | 489 | ||
481 | TUNER_LOG("set_frequency(%d)\n", freq); | 490 | TUNER_LOG("set_frequency(%d)\n", freq); |
@@ -579,6 +588,8 @@ static void set_frequency(int freq) | |||
579 | TUNER_LOG("\n"); | 588 | TUNER_LOG("\n"); |
580 | 589 | ||
581 | TUNER_LOG_SYNC(); | 590 | TUNER_LOG_SYNC(); |
591 | |||
592 | return true; | ||
582 | } | 593 | } |
583 | 594 | ||
584 | static void fine_step_tune(int (*setcmp)(int regval), int regval, int step) | 595 | static void fine_step_tune(int (*setcmp)(int regval), int regval, int step) |
@@ -639,10 +650,10 @@ static int if_setcmp(int regval) | |||
639 | /* This register is bounces around by a few hundred Hz and doesn't seem | 650 | /* This register is bounces around by a few hundred Hz and doesn't seem |
640 | to be precisely tuneable. Just do 110000 +/- 500 since it's not very | 651 | to be precisely tuneable. Just do 110000 +/- 500 since it's not very |
641 | critical it seems. */ | 652 | critical it seems. */ |
642 | if (abs(if_set - 109500) <= 500) | 653 | if (abs(if_set - 110000) <= 500) |
643 | return 0; | 654 | return 0; |
644 | 655 | ||
645 | return if_set < 109500 ? -1 : 1; | 656 | return if_set < 110000 ? -1 : 1; |
646 | } | 657 | } |
647 | 658 | ||
648 | static int sd_setcmp(int regval) | 659 | static int sd_setcmp(int regval) |
@@ -666,8 +677,6 @@ static void set_sleep(bool sleep) | |||
666 | (TUNER_PRESENT | TUNER_POWERED)) | 677 | (TUNER_PRESENT | TUNER_POWERED)) |
667 | return; | 678 | return; |
668 | 679 | ||
669 | tuner_status |= TUNER_AWAKE; | ||
670 | |||
671 | enable_afc(false); | 680 | enable_afc(false); |
672 | 681 | ||
673 | /* 2. Calibrate the IF frequency at 110 kHz: */ | 682 | /* 2. Calibrate the IF frequency at 110 kHz: */ |
@@ -702,9 +711,79 @@ static void set_sleep(bool sleep) | |||
702 | lv24020lp_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR); | 711 | lv24020lp_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR); |
703 | lv24020lp_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) | | 712 | lv24020lp_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) | |
704 | PW_RAD); | 713 | PW_RAD); |
714 | |||
715 | tuner_status |= TUNER_AWAKE; | ||
716 | } | ||
717 | |||
718 | static int lp24020lp_tuned(void) | ||
719 | { | ||
720 | return RSS_FS(lv24020lp_read(RADIO_STAT)) < 0x1f; | ||
721 | } | ||
722 | |||
723 | static int lv24020lp_debug_info(int setting) | ||
724 | { | ||
725 | int val = -1; | ||
726 | |||
727 | if (setting >= LV24020LP_DEBUG_FIRST && setting <= LV24020LP_DEBUG_LAST) | ||
728 | { | ||
729 | val = 0; | ||
730 | |||
731 | if (tuner_awake()) | ||
732 | { | ||
733 | switch (setting) | ||
734 | { | ||
735 | /* tuner-specific debug info */ | ||
736 | case LV24020LP_CTRL_STAT: | ||
737 | val = lv24020lp_read(CTRL_STAT); | ||
738 | break; | ||
739 | |||
740 | case LV24020LP_REG_STAT: | ||
741 | val = lv24020lp_read(RADIO_STAT); | ||
742 | break; | ||
743 | |||
744 | case LV24020LP_MSS_FM: | ||
745 | val = tuner_measure(MSS_FM, 1, 16); | ||
746 | break; | ||
747 | |||
748 | case LV24020LP_MSS_IF: | ||
749 | val = tuner_measure(MSS_IF, 1000, 16); | ||
750 | break; | ||
751 | |||
752 | case LV24020LP_MSS_SD: | ||
753 | val = tuner_measure(MSS_SD, 1000, 16); | ||
754 | break; | ||
755 | |||
756 | case LV24020LP_IF_SET: | ||
757 | val = if_set; | ||
758 | break; | ||
759 | |||
760 | case LV24020LP_SD_SET: | ||
761 | val = sd_set; | ||
762 | break; | ||
763 | } | ||
764 | } | ||
765 | } | ||
766 | |||
767 | return val; | ||
705 | } | 768 | } |
706 | 769 | ||
707 | /** Public interfaces **/ | 770 | /** Public interfaces **/ |
771 | void lv24020lp_init(void) | ||
772 | { | ||
773 | mutex_init(&tuner_mtx); | ||
774 | } | ||
775 | |||
776 | void lv24020lp_lock(void) | ||
777 | { | ||
778 | mutex_lock(&tuner_mtx); | ||
779 | } | ||
780 | |||
781 | void lv24020lp_unlock(void) | ||
782 | { | ||
783 | mutex_unlock(&tuner_mtx); | ||
784 | } | ||
785 | |||
786 | /* This function expects the driver to be locked externally */ | ||
708 | void lv24020lp_power(bool status) | 787 | void lv24020lp_power(bool status) |
709 | { | 788 | { |
710 | static const unsigned char tuner_defaults[][2] = | 789 | static const unsigned char tuner_defaults[][2] = |
@@ -734,7 +813,7 @@ void lv24020lp_power(bool status) | |||
734 | 813 | ||
735 | if (status) | 814 | if (status) |
736 | { | 815 | { |
737 | tuner_status |= TUNER_POWERED | TUNER_PRESENCE_CHECKED; | 816 | tuner_status |= (TUNER_PRESENCE_CHECKED | TUNER_POWERED); |
738 | 817 | ||
739 | /* if tuner is present, CHIP ID is 0x09 */ | 818 | /* if tuner is present, CHIP ID is 0x09 */ |
740 | if (lv24020lp_read(CHIP_ID) == 0x09) | 819 | if (lv24020lp_read(CHIP_ID) == 0x09) |
@@ -750,16 +829,16 @@ void lv24020lp_power(bool status) | |||
750 | lv24020lp_write(tuner_defaults[i][0], tuner_defaults[i][1]); | 829 | lv24020lp_write(tuner_defaults[i][0], tuner_defaults[i][1]); |
751 | 830 | ||
752 | /* Complete the startup calibration if the tuner is woken */ | 831 | /* Complete the startup calibration if the tuner is woken */ |
753 | udelay(100000); | 832 | sleep(HZ/10); |
754 | } | 833 | } |
755 | } | 834 | } |
756 | else | 835 | else |
757 | { | 836 | { |
837 | tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE); | ||
838 | |||
758 | /* Power off */ | 839 | /* Power off */ |
759 | if (tuner_status & TUNER_PRESENT) | 840 | if (tuner_status & TUNER_PRESENT) |
760 | lv24020lp_write_and(PW_SCTRL, ~PW_RAD); | 841 | lv24020lp_write_and(PW_SCTRL, ~PW_RAD); |
761 | |||
762 | tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE); | ||
763 | } | 842 | } |
764 | } | 843 | } |
765 | 844 | ||
@@ -767,6 +846,8 @@ int lv24020lp_set(int setting, int value) | |||
767 | { | 846 | { |
768 | int val = 1; | 847 | int val = 1; |
769 | 848 | ||
849 | mutex_lock(&tuner_mtx); | ||
850 | |||
770 | switch(setting) | 851 | switch(setting) |
771 | { | 852 | { |
772 | case RADIO_SLEEP: | 853 | case RADIO_SLEEP: |
@@ -780,7 +861,7 @@ int lv24020lp_set(int setting, int value) | |||
780 | case RADIO_SCAN_FREQUENCY: | 861 | case RADIO_SCAN_FREQUENCY: |
781 | /* TODO: really implement this */ | 862 | /* TODO: really implement this */ |
782 | set_frequency(value); | 863 | set_frequency(value); |
783 | val = lv24020lp_get(RADIO_TUNED); | 864 | val = lp24020lp_tuned(); |
784 | break; | 865 | break; |
785 | 866 | ||
786 | case RADIO_MUTE: | 867 | case RADIO_MUTE: |
@@ -791,13 +872,11 @@ int lv24020lp_set(int setting, int value) | |||
791 | break; | 872 | break; |
792 | 873 | ||
793 | case RADIO_REGION: | 874 | case RADIO_REGION: |
794 | { | ||
795 | if (lv24020lp_region_data[value]) | 875 | if (lv24020lp_region_data[value]) |
796 | lv24020lp_write_or(AUDIO_CTRL2, DEEMP); | 876 | lv24020lp_write_or(AUDIO_CTRL2, DEEMP); |
797 | else | 877 | else |
798 | lv24020lp_write_and(AUDIO_CTRL2, ~DEEMP); | 878 | lv24020lp_write_and(AUDIO_CTRL2, ~DEEMP); |
799 | break; | 879 | break; |
800 | } | ||
801 | 880 | ||
802 | case RADIO_FORCE_MONO: | 881 | case RADIO_FORCE_MONO: |
803 | if (value) | 882 | if (value) |
@@ -807,9 +886,11 @@ int lv24020lp_set(int setting, int value) | |||
807 | break; | 886 | break; |
808 | 887 | ||
809 | default: | 888 | default: |
810 | val = -1; | 889 | value = -1; |
811 | } | 890 | } |
812 | 891 | ||
892 | mutex_unlock(&tuner_mtx); | ||
893 | |||
813 | return val; | 894 | return val; |
814 | } | 895 | } |
815 | 896 | ||
@@ -817,11 +898,13 @@ int lv24020lp_get(int setting) | |||
817 | { | 898 | { |
818 | int val = -1; | 899 | int val = -1; |
819 | 900 | ||
901 | mutex_lock(&tuner_mtx); | ||
902 | |||
820 | switch(setting) | 903 | switch(setting) |
821 | { | 904 | { |
822 | case RADIO_TUNED: | 905 | case RADIO_TUNED: |
823 | /* TODO: really implement this */ | 906 | /* TODO: really implement this */ |
824 | val = RSS_FS(lv24020lp_read(RADIO_STAT)) < 0x1f; | 907 | val = lp24020lp_tuned(); |
825 | break; | 908 | break; |
826 | 909 | ||
827 | case RADIO_STEREO: | 910 | case RADIO_STEREO: |
@@ -833,38 +916,21 @@ int lv24020lp_get(int setting) | |||
833 | bool fmstatus = true; | 916 | bool fmstatus = true; |
834 | 917 | ||
835 | if (!(tuner_status & TUNER_PRESENCE_CHECKED)) | 918 | if (!(tuner_status & TUNER_PRESENCE_CHECKED)) |
836 | fmstatus = tuner_power(true); | 919 | fmstatus = tuner_power_nolock(true); |
837 | 920 | ||
838 | val = (tuner_status & TUNER_PRESENT) != 0; | 921 | val = (tuner_status & TUNER_PRESENT) != 0; |
839 | 922 | ||
840 | if (!fmstatus) | 923 | if (!fmstatus) |
841 | tuner_power(false); | 924 | tuner_power_nolock(false); |
842 | break; | 925 | break; |
843 | } | 926 | } |
844 | 927 | ||
845 | /* tuner-specific debug info */ | 928 | default: |
846 | case LV24020LP_CTRL_STAT: | 929 | val = lv24020lp_debug_info(setting); |
847 | return lv24020lp_read(CTRL_STAT); | ||
848 | |||
849 | case LV24020LP_REG_STAT: | ||
850 | return lv24020lp_read(RADIO_STAT); | ||
851 | |||
852 | case LV24020LP_MSS_FM: | ||
853 | return tuner_measure(MSS_FM, 1, 16); | ||
854 | |||
855 | case LV24020LP_MSS_IF: | ||
856 | return tuner_measure(MSS_IF, 1000, 16); | ||
857 | |||
858 | case LV24020LP_MSS_SD: | ||
859 | return tuner_measure(MSS_SD, 1000, 16); | ||
860 | |||
861 | case LV24020LP_IF_SET: | ||
862 | return if_set; | ||
863 | |||
864 | case LV24020LP_SD_SET: | ||
865 | return sd_set; | ||
866 | } | 930 | } |
867 | 931 | ||
932 | mutex_unlock(&tuner_mtx); | ||
933 | |||
868 | return val; | 934 | return val; |
869 | } | 935 | } |
870 | #endif /* BOOTLOADER */ | 936 | #endif /* BOOTLOADER */ |