summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/tuner/lv24020lp.c77
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 */
359static void lv24020lp_write_or(unsigned int address, unsigned int bits) 358static 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
364static void lv24020lp_write_and(unsigned int address, unsigned int bits) 363static 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
593static void fine_step_tune(int (*setcmp)(int regval), int regval, int step) 598static 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: