diff options
Diffstat (limited to 'firmware/drivers/tuner/lv24020lp.c')
-rw-r--r-- | firmware/drivers/tuner/lv24020lp.c | 77 |
1 files changed, 41 insertions, 36 deletions
diff --git a/firmware/drivers/tuner/lv24020lp.c b/firmware/drivers/tuner/lv24020lp.c index 865a3bec97..a1dc15f41d 100644 --- a/firmware/drivers/tuner/lv24020lp.c +++ b/firmware/drivers/tuner/lv24020lp.c | |||
@@ -266,6 +266,7 @@ static void lv24020lp_send_byte(unsigned int byte) | |||
266 | 266 | ||
267 | GPIOH_OUTPUT_VAL = (GPIOH_OUTPUT_VAL & ~(1 << FM_DATA_PIN)) | | 267 | GPIOH_OUTPUT_VAL = (GPIOH_OUTPUT_VAL & ~(1 << FM_DATA_PIN)) | |
268 | (byte & (1 << FM_DATA_PIN)); | 268 | (byte & (1 << FM_DATA_PIN)); |
269 | udelay(FM_CLK_DELAY); | ||
269 | 270 | ||
270 | GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); | 271 | GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); |
271 | udelay(FM_CLK_DELAY); | 272 | udelay(FM_CLK_DELAY); |
@@ -280,6 +281,7 @@ static void lv24020lp_end_write(void) | |||
280 | /* switch back to read mode */ | 281 | /* switch back to read mode */ |
281 | GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN); | 282 | GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN); |
282 | GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN); | 283 | GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN); |
284 | udelay(FM_CLK_DELAY); | ||
283 | } | 285 | } |
284 | 286 | ||
285 | /* prepare a write cycle on the tuner */ | 287 | /* prepare a write cycle on the tuner */ |
@@ -294,7 +296,6 @@ static unsigned int lv24020lp_begin_write(unsigned int address) | |||
294 | /* Prepare 3-wire bus pins for write cycle */ | 296 | /* Prepare 3-wire bus pins for write cycle */ |
295 | GPIOH_OUTPUT_VAL |= (1 << FM_NRW_PIN); | 297 | GPIOH_OUTPUT_VAL |= (1 << FM_NRW_PIN); |
296 | GPIOH_OUTPUT_EN |= (1 << FM_DATA_PIN); | 298 | GPIOH_OUTPUT_EN |= (1 << FM_DATA_PIN); |
297 | |||
298 | udelay(FM_CLK_DELAY); | 299 | udelay(FM_CLK_DELAY); |
299 | 300 | ||
300 | /* current block == register block? */ | 301 | /* current block == register block? */ |
@@ -310,8 +311,6 @@ static unsigned int lv24020lp_begin_write(unsigned int address) | |||
310 | lv24020lp_send_byte(BLK_SEL); | 311 | lv24020lp_send_byte(BLK_SEL); |
311 | 312 | ||
312 | lv24020lp_end_write(); | 313 | lv24020lp_end_write(); |
313 | |||
314 | udelay(FM_CLK_DELAY); | ||
315 | } | 314 | } |
316 | } | 315 | } |
317 | 316 | ||
@@ -356,14 +355,14 @@ static void lv24020lp_write(unsigned int address, unsigned int data) | |||
356 | } | 355 | } |
357 | 356 | ||
358 | /* helpers to set/clear register bits */ | 357 | /* helpers to set/clear register bits */ |
359 | static void lv24020lp_write_or(unsigned int address, unsigned int bits) | 358 | static void lv24020lp_write_set(unsigned int address, unsigned int bits) |
360 | { | 359 | { |
361 | lv24020lp_write(address, lv24020lp_regs[address] | bits); | 360 | lv24020lp_write(address, lv24020lp_regs[address] | bits); |
362 | } | 361 | } |
363 | 362 | ||
364 | static void lv24020lp_write_and(unsigned int address, unsigned int bits) | 363 | static void lv24020lp_write_clear(unsigned int address, unsigned int bits) |
365 | { | 364 | { |
366 | lv24020lp_write(address, lv24020lp_regs[address] & bits); | 365 | lv24020lp_write(address, lv24020lp_regs[address] & ~bits); |
367 | } | 366 | } |
368 | 367 | ||
369 | /* read a byte from a tuner register */ | 368 | /* read a byte from a tuner register */ |
@@ -393,6 +392,7 @@ static unsigned int lv24020lp_read(unsigned int address) | |||
393 | toread |= (GPIOH_INPUT_VAL & (1 << FM_DATA_PIN)) << i; | 392 | toread |= (GPIOH_INPUT_VAL & (1 << FM_DATA_PIN)) << i; |
394 | 393 | ||
395 | GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); | 394 | GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN); |
395 | udelay(FM_CLK_DELAY); | ||
396 | } | 396 | } |
397 | 397 | ||
398 | return toread >> FM_DATA_PIN; | 398 | return toread >> FM_DATA_PIN; |
@@ -445,25 +445,25 @@ static int tuner_measure(unsigned char type, int scale, int duration) | |||
445 | int64_t finval; | 445 | int64_t finval; |
446 | 446 | ||
447 | /* enable measuring */ | 447 | /* enable measuring */ |
448 | lv24020lp_write_or(MSRC_SEL, type); | 448 | lv24020lp_write_set(MSRC_SEL, type); |
449 | lv24020lp_write_and(CNT_CTRL, ~CNT_SEL); | 449 | lv24020lp_write_clear(CNT_CTRL, CNT_SEL); |
450 | lv24020lp_write_or(RADIO_CTRL1, EN_MEAS); | 450 | lv24020lp_write_set(RADIO_CTRL1, EN_MEAS); |
451 | 451 | ||
452 | /* reset counter */ | 452 | /* reset counter */ |
453 | lv24020lp_write_or(CNT_CTRL, CNT1_CLR); | 453 | lv24020lp_write_set(CNT_CTRL, CNT1_CLR); |
454 | lv24020lp_write_and(CNT_CTRL, ~CNT1_CLR); | 454 | lv24020lp_write_clear(CNT_CTRL, CNT1_CLR); |
455 | 455 | ||
456 | /* start counter, delay for specified time and stop it */ | 456 | /* start counter, delay for specified time and stop it */ |
457 | lv24020lp_write_or(CNT_CTRL, CNT_EN); | 457 | lv24020lp_write_set(CNT_CTRL, CNT_EN); |
458 | udelay(duration*1000 - 16); | 458 | udelay(duration*1000 - 16); |
459 | lv24020lp_write_and(CNT_CTRL, ~CNT_EN); | 459 | lv24020lp_write_clear(CNT_CTRL, CNT_EN); |
460 | 460 | ||
461 | /* read tick count */ | 461 | /* read tick count */ |
462 | finval = (lv24020lp_read(CNT_H) << 8) | lv24020lp_read(CNT_L); | 462 | finval = (lv24020lp_read(CNT_H) << 8) | lv24020lp_read(CNT_L); |
463 | 463 | ||
464 | /* restore measure mode */ | 464 | /* restore measure mode */ |
465 | lv24020lp_write_and(RADIO_CTRL1, ~EN_MEAS); | 465 | lv24020lp_write_clear(RADIO_CTRL1, EN_MEAS); |
466 | lv24020lp_write_and(MSRC_SEL, ~type); | 466 | lv24020lp_write_clear(MSRC_SEL, type); |
467 | 467 | ||
468 | /* convert value */ | 468 | /* convert value */ |
469 | if (type == MSS_FM) | 469 | if (type == MSS_FM) |
@@ -590,6 +590,11 @@ static void set_frequency(int freq) | |||
590 | TUNER_LOG_SYNC(); | 590 | TUNER_LOG_SYNC(); |
591 | } | 591 | } |
592 | 592 | ||
593 | #define TOO_SMALL (1 << 0) | ||
594 | #define TOO_BIG (1 << 1) | ||
595 | #define APPROACH_UP_1 (1 << 2) | ||
596 | #define APPROACH_DOWN_1 (1 << 3) | ||
597 | |||
593 | static void fine_step_tune(int (*setcmp)(int regval), int regval, int step) | 598 | static void fine_step_tune(int (*setcmp)(int regval), int regval, int step) |
594 | { | 599 | { |
595 | /* Registers are not always stable, timeout if best fit not found soon | 600 | /* Registers are not always stable, timeout if best fit not found soon |
@@ -612,27 +617,27 @@ static void fine_step_tune(int (*setcmp)(int regval), int regval, int step) | |||
612 | 617 | ||
613 | if (cmp < 0) | 618 | if (cmp < 0) |
614 | { | 619 | { |
615 | flags |= 1; | 620 | flags |= TOO_SMALL; |
616 | if (step == 1) | 621 | if (step == 1) |
617 | flags |= 4; | 622 | flags |= APPROACH_UP_1; |
618 | } | 623 | } |
619 | else | 624 | else |
620 | { | 625 | { |
621 | step = -step; | 626 | step = -step; |
622 | flags |= 2; | 627 | flags |= TOO_BIG; |
623 | if (step == -1) | 628 | if (step == -1) |
624 | step |= 8; | 629 | step |= APPROACH_DOWN_1; |
625 | } | 630 | } |
626 | 631 | ||
627 | if ((flags & 0xc) == 0xc) | 632 | if ((flags & APPROACH_UP_1) && (flags & APPROACH_DOWN_1)) |
628 | break; | 633 | break; /* approached with step=1: best fit value found */ |
629 | 634 | ||
630 | if ((flags & 0x3) == 0x3) | 635 | if ((flags & TOO_SMALL) && (flags & TOO_BIG)) |
631 | { | 636 | { |
632 | step /= 2; | 637 | step /= 2; |
633 | if (step == 0) | 638 | if (step == 0) |
634 | step = 1; | 639 | step = 1; |
635 | flags &= ~3; | 640 | flags &= ~(TOO_SMALL | TOO_BIG); |
636 | } | 641 | } |
637 | } | 642 | } |
638 | } | 643 | } |
@@ -678,14 +683,14 @@ static void set_sleep(bool sleep) | |||
678 | enable_afc(false); | 683 | enable_afc(false); |
679 | 684 | ||
680 | /* 2. Calibrate the IF frequency at 110 kHz: */ | 685 | /* 2. Calibrate the IF frequency at 110 kHz: */ |
681 | lv24020lp_write_and(RADIO_CTRL2, ~IF_PM_L); | 686 | lv24020lp_write_clear(RADIO_CTRL2, IF_PM_L); |
682 | fine_step_tune(if_setcmp, 0x80, 8); | 687 | fine_step_tune(if_setcmp, 0x80, 8); |
683 | lv24020lp_write_or(RADIO_CTRL2, IF_PM_L); | 688 | lv24020lp_write_set(RADIO_CTRL2, IF_PM_L); |
684 | 689 | ||
685 | /* 3. Calibrate the stereo decoder clock at 38.3 kHz: */ | 690 | /* 3. Calibrate the stereo decoder clock at 38.3 kHz: */ |
686 | lv24020lp_write_or(STEREO_CTRL, SD_PM); | 691 | lv24020lp_write_set(STEREO_CTRL, SD_PM); |
687 | fine_step_tune(sd_setcmp, 0x80, 8); | 692 | fine_step_tune(sd_setcmp, 0x80, 8); |
688 | lv24020lp_write_and(STEREO_CTRL, ~SD_PM); | 693 | lv24020lp_write_clear(STEREO_CTRL, SD_PM); |
689 | 694 | ||
690 | /* calculate FM tuning coefficients */ | 695 | /* calculate FM tuning coefficients */ |
691 | lv24020lp_write(FM_CAP, sw_cap_low); | 696 | lv24020lp_write(FM_CAP, sw_cap_low); |
@@ -704,8 +709,8 @@ static void set_sleep(bool sleep) | |||
704 | 709 | ||
705 | /* set various audio level settings */ | 710 | /* set various audio level settings */ |
706 | lv24020lp_write(AUDIO_CTRL1, TONE_LVL_SET(0) | VOL_LVL_SET(0)); | 711 | lv24020lp_write(AUDIO_CTRL1, TONE_LVL_SET(0) | VOL_LVL_SET(0)); |
707 | lv24020lp_write_or(RADIO_CTRL2, AGCSP); | 712 | lv24020lp_write_set(RADIO_CTRL2, AGCSP); |
708 | lv24020lp_write_or(RADIO_CTRL3, VOLSH); | 713 | lv24020lp_write_set(RADIO_CTRL3, VOLSH); |
709 | lv24020lp_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR); | 714 | lv24020lp_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR); |
710 | lv24020lp_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) | | 715 | lv24020lp_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) | |
711 | PW_RAD); | 716 | PW_RAD); |
@@ -834,7 +839,7 @@ void lv24020lp_power(bool status) | |||
834 | { | 839 | { |
835 | /* Power off */ | 840 | /* Power off */ |
836 | if (tuner_status & TUNER_PRESENT) | 841 | if (tuner_status & TUNER_PRESENT) |
837 | lv24020lp_write_and(PW_SCTRL, ~PW_RAD); | 842 | lv24020lp_write_clear(PW_SCTRL, PW_RAD); |
838 | 843 | ||
839 | tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE); | 844 | tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE); |
840 | } | 845 | } |
@@ -864,23 +869,23 @@ int lv24020lp_set(int setting, int value) | |||
864 | 869 | ||
865 | case RADIO_MUTE: | 870 | case RADIO_MUTE: |
866 | if (value) | 871 | if (value) |
867 | lv24020lp_write_and(RADIO_CTRL3, ~AMUTE_L); | 872 | lv24020lp_write_clear(RADIO_CTRL3, AMUTE_L); |
868 | else | 873 | else |
869 | lv24020lp_write_or(RADIO_CTRL3, AMUTE_L); | 874 | lv24020lp_write_set(RADIO_CTRL3, AMUTE_L); |
870 | break; | 875 | break; |
871 | 876 | ||
872 | case RADIO_REGION: | 877 | case RADIO_REGION: |
873 | if (lv24020lp_region_data[value]) | 878 | if (lv24020lp_region_data[value]) |
874 | lv24020lp_write_or(AUDIO_CTRL2, DEEMP); | 879 | lv24020lp_write_set(AUDIO_CTRL2, DEEMP); |
875 | else | 880 | else |
876 | lv24020lp_write_and(AUDIO_CTRL2, ~DEEMP); | 881 | lv24020lp_write_clear(AUDIO_CTRL2, DEEMP); |
877 | break; | 882 | break; |
878 | 883 | ||
879 | case RADIO_FORCE_MONO: | 884 | case RADIO_FORCE_MONO: |
880 | if (value) | 885 | if (value) |
881 | lv24020lp_write_or(STEREO_CTRL, ST_M); | 886 | lv24020lp_write_set(STEREO_CTRL, ST_M); |
882 | else | 887 | else |
883 | lv24020lp_write_and(STEREO_CTRL, ~ST_M); | 888 | lv24020lp_write_clear(STEREO_CTRL, ST_M); |
884 | break; | 889 | break; |
885 | 890 | ||
886 | default: | 891 | default: |