summaryrefslogtreecommitdiff
path: root/firmware/drivers/tuner/si4700.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/tuner/si4700.c')
-rw-r--r--firmware/drivers/tuner/si4700.c164
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)
42extern 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
215static bool tuner_present = false; 213static bool tuner_present = false;
216static uint16_t cache[16]; 214static uint16_t cache[16];
215static struct mutex fmr_mutex SHAREDBSS_ATTR;
216#ifdef HAVE_RDS_CAP
217static 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 */
219static void si4700_read(int len) 221static 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 */
282static inline int si4700_st(void) 284bool 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
288static void si4700_sleep(int snooze) 290static 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
326bool si4700_detect(void) 345bool 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
337void si4700_init(void) 355void 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 */
422int si4700_set(int setting, int value) 444int 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 */
560bool 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 */
579void si4700_rds_set_event(void)
580{
581 mutex_lock(&fmr_mutex);
582 rds_event = 1;
583 mutex_unlock(&fmr_mutex);
584}
585
586char * 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