diff options
Diffstat (limited to 'firmware/drivers/tuner/si4700.c')
-rw-r--r-- | firmware/drivers/tuner/si4700.c | 164 |
1 files changed, 131 insertions, 33 deletions
diff --git a/firmware/drivers/tuner/si4700.c b/firmware/drivers/tuner/si4700.c index 848d25eeb0..bebbd0c881 100644 --- a/firmware/drivers/tuner/si4700.c +++ b/firmware/drivers/tuner/si4700.c | |||
@@ -29,21 +29,15 @@ | |||
29 | #include "tuner.h" /* tuner abstraction interface */ | 29 | #include "tuner.h" /* tuner abstraction interface */ |
30 | #include "fmradio.h" | 30 | #include "fmradio.h" |
31 | #include "fmradio_i2c.h" /* physical interface driver */ | 31 | #include "fmradio_i2c.h" /* physical interface driver */ |
32 | #include "rds.h" | ||
32 | 33 | ||
33 | /* some models use the internal 32 kHz oscillator which needs special attention | ||
34 | during initialisation, power-up and power-down. | ||
35 | */ | ||
36 | #if defined(SANSA_CLIP) || defined(SANSA_E200V2) || defined(SANSA_FUZE) || defined(SANSA_C200V2) | 34 | #if defined(SANSA_CLIP) || defined(SANSA_E200V2) || defined(SANSA_FUZE) || defined(SANSA_C200V2) |
37 | #define USE_INTERNAL_OSCILLATOR | 35 | /* some models use the internal 32 kHz oscillator which needs special attention |
36 | during initialisation, power-up and power-down. */ | ||
37 | #define SI4700_USE_INTERNAL_OSCILLATOR | ||
38 | #elif defined(TOSHIBA_GIGABEAT_S) | 38 | #elif defined(TOSHIBA_GIGABEAT_S) |
39 | #define SI4700_GPIO_SETUP (SYSCONFIG1_GPIO1_HI_Z | \ | 39 | /* gigabeat S uses the GPIO for stereo/mono detection */ |
40 | SYSCONFIG1_GPIO2_HI_Z | \ | 40 | #define SI4700_USE_MO_ST_I |
41 | SYSCONFIG1_GPIO3_MO_ST_I) | ||
42 | extern int si4700_st(void); | ||
43 | #endif | ||
44 | |||
45 | #ifndef SI4700_GPIO_SETUP | ||
46 | #define SI4700_GPIO_SETUP 0 | ||
47 | #endif | 41 | #endif |
48 | 42 | ||
49 | #define SEEK_THRESHOLD 0x16 | 43 | #define SEEK_THRESHOLD 0x16 |
@@ -81,7 +75,8 @@ extern int si4700_st(void); | |||
81 | 75 | ||
82 | /* CHIPID (0x1) */ | 76 | /* CHIPID (0x1) */ |
83 | 77 | ||
84 | #if 0 /* Informational */ | 78 | #if 0 |
79 | /* Informational */ | ||
85 | /* Si4700/01 */ | 80 | /* Si4700/01 */ |
86 | #define CHIPID_REV (0x3f << 10) | 81 | #define CHIPID_REV (0x3f << 10) |
87 | #define CHIPID_DEV (0x1 << 9) | 82 | #define CHIPID_DEV (0x1 << 9) |
@@ -98,7 +93,10 @@ extern int si4700_st(void); | |||
98 | /* 1000 before PU = Si4703 */ | 93 | /* 1000 before PU = Si4703 */ |
99 | /* 1001 after PU = Si4703 */ | 94 | /* 1001 after PU = Si4703 */ |
100 | #define CHIPID_FIRMWARE (0x3f << 0) | 95 | #define CHIPID_FIRMWARE (0x3f << 0) |
101 | #endif /* 0 */ | 96 | #endif |
97 | |||
98 | /* Indicates Si4701/2/3 after powerup */ | ||
99 | #define CHIPID_DEV_0 (0x1 << 9) | ||
102 | 100 | ||
103 | /* POWERCFG (0x2) */ | 101 | /* POWERCFG (0x2) */ |
104 | #define POWERCFG_DSMUTE (0x1 << 15) | 102 | #define POWERCFG_DSMUTE (0x1 << 15) |
@@ -214,6 +212,10 @@ extern int si4700_st(void); | |||
214 | 212 | ||
215 | static bool tuner_present = false; | 213 | static bool tuner_present = false; |
216 | static uint16_t cache[16]; | 214 | static uint16_t cache[16]; |
215 | static struct mutex fmr_mutex SHAREDBSS_ATTR; | ||
216 | #ifdef HAVE_RDS_CAP | ||
217 | static int rds_event = 0; | ||
218 | #endif | ||
217 | 219 | ||
218 | /* reads <len> registers from radio at offset 0x0A into cache */ | 220 | /* reads <len> registers from radio at offset 0x0A into cache */ |
219 | static void si4700_read(int len) | 221 | static void si4700_read(int len) |
@@ -277,19 +279,26 @@ static void si4700_write_clear(int reg, uint16_t mask) | |||
277 | si4700_write_reg(reg, cache[reg] & ~mask); | 279 | si4700_write_reg(reg, cache[reg] & ~mask); |
278 | } | 280 | } |
279 | 281 | ||
280 | #if (SI4700_GPIO_SETUP & SYSCONFIG1_GPIO3) != SYSCONFIG1_GPIO3_MO_ST_I | 282 | #ifndef SI4700_USE_MO_ST_I |
281 | /* Poll i2c for the stereo status */ | 283 | /* Poll i2c for the stereo status */ |
282 | static inline int si4700_st(void) | 284 | bool si4700_st(void) |
283 | { | 285 | { |
284 | return (si4700_read_reg(STATUSRSSI) & STATUSRSSI_ST) >> 8; | 286 | return (si4700_read_reg(STATUSRSSI) & STATUSRSSI_ST) >> 8; |
285 | } | 287 | } |
286 | #endif | 288 | #endif /* ndef SI4700_USE_MO_ST_I */ |
287 | 289 | ||
288 | static void si4700_sleep(int snooze) | 290 | static void si4700_sleep(int snooze) |
289 | { | 291 | { |
290 | if (snooze) | 292 | if (snooze) |
291 | { | 293 | { |
292 | /** power down **/ | 294 | /** power down **/ |
295 | #ifdef HAVE_RDS_CAP | ||
296 | if (cache[CHIPID] & CHIPID_DEV_0) { | ||
297 | si4700_rds_powerup(false); | ||
298 | si4700_write_clear(SYSCONFIG1, SYSCONFIG1_RDS | SYSCONFIG1_RDSIEN); | ||
299 | } | ||
300 | #endif | ||
301 | |||
293 | /* ENABLE high, DISABLE high */ | 302 | /* ENABLE high, DISABLE high */ |
294 | si4700_write_set(POWERCFG, | 303 | si4700_write_set(POWERCFG, |
295 | POWERCFG_DISABLE | POWERCFG_ENABLE); | 304 | POWERCFG_DISABLE | POWERCFG_ENABLE); |
@@ -307,9 +316,8 @@ static void si4700_sleep(int snooze) | |||
307 | /* init register cache */ | 316 | /* init register cache */ |
308 | si4700_read(16); | 317 | si4700_read(16); |
309 | 318 | ||
310 | #if SI4700_GPIO_SETUP != 0 | 319 | #ifdef SI4700_USE_MO_ST_I |
311 | si4700_write_masked(SYSCONFIG1, SI4700_GPIO_SETUP, | 320 | si4700_write_masked(SYSCONFIG1, SYSCONFIG1_GPIO3_MO_ST_I, |
312 | SYSCONFIG1_GPIO1 | SYSCONFIG1_GPIO2 | | ||
313 | SYSCONFIG1_GPIO3); | 321 | SYSCONFIG1_GPIO3); |
314 | #endif | 322 | #endif |
315 | /* set mono->stereo switching RSSI range to lowest setting */ | 323 | /* set mono->stereo switching RSSI range to lowest setting */ |
@@ -320,33 +328,43 @@ static void si4700_sleep(int snooze) | |||
320 | SYSCONFIG2_SKEETHw(SEEK_THRESHOLD) | | 328 | SYSCONFIG2_SKEETHw(SEEK_THRESHOLD) | |
321 | SYSCONFIG2_VOLUMEw(0xF), | 329 | SYSCONFIG2_VOLUMEw(0xF), |
322 | SYSCONFIG2_VOLUME | SYSCONFIG2_SEEKTH); | 330 | SYSCONFIG2_VOLUME | SYSCONFIG2_SEEKTH); |
331 | |||
332 | #ifdef HAVE_RDS_CAP | ||
333 | /* enable RDS and RDS interrupt if supported (bit 9 of CHIPID) */ | ||
334 | if (cache[CHIPID] & CHIPID_DEV_0) { | ||
335 | /* Is Si4701/2/3 - Enable RDS and interrupt */ | ||
336 | si4700_write_set(SYSCONFIG1, SYSCONFIG1_RDS | SYSCONFIG1_RDSIEN); | ||
337 | si4700_write_masked(SYSCONFIG1, SYSCONFIG1_GPIO2_STC_RDS_I, | ||
338 | SYSCONFIG1_GPIO2); | ||
339 | si4700_rds_powerup(true); | ||
340 | } | ||
341 | #endif | ||
323 | } | 342 | } |
324 | } | 343 | } |
325 | 344 | ||
326 | bool si4700_detect(void) | 345 | bool si4700_detect(void) |
327 | { | 346 | { |
328 | bool detected; | 347 | if (!tuner_present) { |
329 | 348 | tuner_power(true); | |
330 | tuner_power(true); | 349 | tuner_present = (si4700_read_reg(DEVICEID) == 0x1242); |
331 | detected = (si4700_read_reg(DEVICEID) == 0x1242); | 350 | tuner_power(false); |
332 | tuner_power(false); | 351 | } |
333 | 352 | return tuner_present; | |
334 | return detected; | ||
335 | } | 353 | } |
336 | 354 | ||
337 | void si4700_init(void) | 355 | void si4700_init(void) |
338 | { | 356 | { |
339 | /* check device id */ | 357 | /* check device id */ |
340 | if (si4700_detect()) { | 358 | if (si4700_detect()) { |
341 | tuner_present = true; | 359 | mutex_init(&fmr_mutex); |
342 | 360 | ||
343 | tuner_power(true); | 361 | tuner_power(true); |
344 | 362 | ||
345 | /* read all registers */ | 363 | /* read all registers */ |
346 | si4700_read(16); | 364 | si4700_read(16); |
347 | si4700_sleep(0); | 365 | si4700_sleep(0); |
348 | 366 | ||
349 | #ifdef USE_INTERNAL_OSCILLATOR | 367 | #ifdef SI4700_USE_INTERNAL_OSCILLATOR |
350 | /* Enable the internal oscillator | 368 | /* Enable the internal oscillator |
351 | (Si4702-16 needs this register to be initialised to 0x100) */ | 369 | (Si4702-16 needs this register to be initialised to 0x100) */ |
352 | si4700_write_set(TEST1, TEST1_XOSCEN | 0x100); | 370 | si4700_write_set(TEST1, TEST1_XOSCEN | 0x100); |
@@ -355,6 +373,10 @@ void si4700_init(void) | |||
355 | 373 | ||
356 | si4700_sleep(1); | 374 | si4700_sleep(1); |
357 | tuner_power(false); | 375 | tuner_power(false); |
376 | |||
377 | #ifdef HAVE_RDS_CAP | ||
378 | si4700_rds_init(); | ||
379 | #endif | ||
358 | } | 380 | } |
359 | } | 381 | } |
360 | 382 | ||
@@ -421,6 +443,10 @@ static void si4700_set_region(int region) | |||
421 | /* tuner abstraction layer: set something to the tuner */ | 443 | /* tuner abstraction layer: set something to the tuner */ |
422 | int si4700_set(int setting, int value) | 444 | int si4700_set(int setting, int value) |
423 | { | 445 | { |
446 | int val = 1; | ||
447 | |||
448 | mutex_lock(&fmr_mutex); | ||
449 | |||
424 | switch(setting) | 450 | switch(setting) |
425 | { | 451 | { |
426 | case RADIO_SLEEP: | 452 | case RADIO_SLEEP: |
@@ -430,12 +456,19 @@ int si4700_set(int setting, int value) | |||
430 | break; | 456 | break; |
431 | 457 | ||
432 | case RADIO_FREQUENCY: | 458 | case RADIO_FREQUENCY: |
459 | #ifdef HAVE_RDS_CAP | ||
460 | rds_reset(); | ||
461 | #endif | ||
433 | si4700_set_frequency(value); | 462 | si4700_set_frequency(value); |
434 | break; | 463 | break; |
435 | 464 | ||
436 | case RADIO_SCAN_FREQUENCY: | 465 | case RADIO_SCAN_FREQUENCY: |
466 | #ifdef HAVE_RDS_CAP | ||
467 | rds_reset(); | ||
468 | #endif | ||
437 | si4700_set_frequency(value); | 469 | si4700_set_frequency(value); |
438 | return si4700_tuned(); | 470 | val = si4700_tuned(); |
471 | break; | ||
439 | 472 | ||
440 | case RADIO_MUTE: | 473 | case RADIO_MUTE: |
441 | si4700_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE, | 474 | si4700_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE, |
@@ -452,10 +485,13 @@ int si4700_set(int setting, int value) | |||
452 | break; | 485 | break; |
453 | 486 | ||
454 | default: | 487 | default: |
455 | return -1; | 488 | val = -1; |
489 | break; | ||
456 | } | 490 | } |
457 | 491 | ||
458 | return 1; | 492 | mutex_unlock(&fmr_mutex); |
493 | |||
494 | return val; | ||
459 | } | 495 | } |
460 | 496 | ||
461 | /* tuner abstraction layer: read something from the tuner */ | 497 | /* tuner abstraction layer: read something from the tuner */ |
@@ -463,6 +499,8 @@ int si4700_get(int setting) | |||
463 | { | 499 | { |
464 | int val = -1; /* default for unsupported query */ | 500 | int val = -1; /* default for unsupported query */ |
465 | 501 | ||
502 | mutex_lock(&fmr_mutex); | ||
503 | |||
466 | switch(setting) | 504 | switch(setting) |
467 | { | 505 | { |
468 | case RADIO_PRESENT: | 506 | case RADIO_PRESENT: |
@@ -488,8 +526,17 @@ int si4700_get(int setting) | |||
488 | case RADIO_RSSI_MAX: | 526 | case RADIO_RSSI_MAX: |
489 | val = RSSI_MAX; | 527 | val = RSSI_MAX; |
490 | break; | 528 | break; |
529 | |||
530 | #ifdef HAVE_RDS_CAP | ||
531 | case RADIO_EVENT: | ||
532 | val = rds_event; | ||
533 | rds_event = 0; | ||
534 | break; | ||
535 | #endif | ||
491 | } | 536 | } |
492 | 537 | ||
538 | mutex_unlock(&fmr_mutex); | ||
539 | |||
493 | return val; | 540 | return val; |
494 | } | 541 | } |
495 | 542 | ||
@@ -497,10 +544,61 @@ void si4700_dbg_info(struct si4700_dbg_info *nfo) | |||
497 | { | 544 | { |
498 | memset(nfo->regs, 0, sizeof (nfo->regs)); | 545 | memset(nfo->regs, 0, sizeof (nfo->regs)); |
499 | 546 | ||
547 | mutex_lock(&fmr_mutex); | ||
548 | |||
500 | if (tuner_powered()) | 549 | if (tuner_powered()) |
501 | { | 550 | { |
502 | si4700_read(16); | 551 | si4700_read(16); |
503 | memcpy(nfo->regs, cache, sizeof (nfo->regs)); | 552 | memcpy(nfo->regs, cache, sizeof (nfo->regs)); |
504 | } | 553 | } |
554 | |||
555 | mutex_unlock(&fmr_mutex); | ||
556 | } | ||
557 | |||
558 | #ifdef HAVE_RDS_CAP | ||
559 | /* Read raw RDS info for processing */ | ||
560 | bool si4700_rds_read_raw(uint16_t data[4]) | ||
561 | { | ||
562 | bool retval = false; | ||
563 | |||
564 | mutex_lock(&fmr_mutex); | ||
565 | |||
566 | if (tuner_powered()) | ||
567 | { | ||
568 | si4700_read_reg(RDSD); | ||
569 | memcpy(data, &cache[RDSA], 4 * sizeof (uint16_t)); | ||
570 | retval = true; | ||
571 | } | ||
572 | |||
573 | mutex_unlock(&fmr_mutex); | ||
574 | |||
575 | return retval; | ||
576 | } | ||
577 | |||
578 | /* Set the event flag */ | ||
579 | void si4700_rds_set_event(void) | ||
580 | { | ||
581 | mutex_lock(&fmr_mutex); | ||
582 | rds_event = 1; | ||
583 | mutex_unlock(&fmr_mutex); | ||
584 | } | ||
585 | |||
586 | char * si4700_get_rds_info(int setting) | ||
587 | { | ||
588 | char *text = NULL; | ||
589 | |||
590 | switch(setting) | ||
591 | { | ||
592 | case RADIO_RDS_NAME: | ||
593 | text = rds_get_ps(); | ||
594 | break; | ||
595 | |||
596 | case RADIO_RDS_TEXT: | ||
597 | text = rds_get_rt(); | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | return text; | ||
505 | } | 602 | } |
603 | #endif /* HAVE_RDS_CAP */ | ||
506 | 604 | ||