mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 12:45:26 -05:00
Support for mystery FM chip in some Sansa Clip+, FS #11403 by me
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26864 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
267a446887
commit
fcea117d21
11 changed files with 507 additions and 33 deletions
|
|
@ -2324,6 +2324,14 @@ static bool dbg_save_roms(void)
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
#if CONFIG_TUNER
|
#if CONFIG_TUNER
|
||||||
|
|
||||||
|
#ifdef CONFIG_TUNER_MULTI
|
||||||
|
static int tuner_type = 0;
|
||||||
|
#define IF_TUNER_TYPE(type) if(tuner_type==type)
|
||||||
|
#else
|
||||||
|
#define IF_TUNER_TYPE(type)
|
||||||
|
#endif
|
||||||
|
|
||||||
static int radio_callback(int btn, struct gui_synclist *lists)
|
static int radio_callback(int btn, struct gui_synclist *lists)
|
||||||
{
|
{
|
||||||
(void)lists;
|
(void)lists;
|
||||||
|
|
@ -2368,32 +2376,39 @@ static int radio_callback(int btn, struct gui_synclist *lists)
|
||||||
(unsigned)nfo.write_regs[4]);
|
(unsigned)nfo.write_regs[4]);
|
||||||
#endif /* TEA5767 */
|
#endif /* TEA5767 */
|
||||||
#if (CONFIG_TUNER & SI4700)
|
#if (CONFIG_TUNER & SI4700)
|
||||||
struct si4700_dbg_info nfo;
|
IF_TUNER_TYPE(SI4700)
|
||||||
si4700_dbg_info(&nfo);
|
{
|
||||||
simplelist_addline(SIMPLELIST_ADD_LINE, "SI4700 regs:");
|
struct si4700_dbg_info nfo;
|
||||||
/* Registers */
|
int i;
|
||||||
simplelist_addline(SIMPLELIST_ADD_LINE,
|
si4700_dbg_info(&nfo);
|
||||||
"%04X %04X %04X %04X",
|
simplelist_addline(SIMPLELIST_ADD_LINE, "SI4700 regs:");
|
||||||
(unsigned)nfo.regs[0], (unsigned)nfo.regs[1],
|
for (i = 0; i < 16; i += 4) {
|
||||||
(unsigned)nfo.regs[2], (unsigned)nfo.regs[3]);
|
simplelist_addline(SIMPLELIST_ADD_LINE,"%02X: %04X %04X %04X %04X",
|
||||||
simplelist_addline(SIMPLELIST_ADD_LINE,
|
i, nfo.regs[i], nfo.regs[i+1], nfo.regs[i+2], nfo.regs[i+3]);
|
||||||
"%04X %04X %04X %04X",
|
}
|
||||||
(unsigned)nfo.regs[4], (unsigned)nfo.regs[5],
|
}
|
||||||
(unsigned)nfo.regs[6], (unsigned)nfo.regs[7]);
|
|
||||||
simplelist_addline(SIMPLELIST_ADD_LINE,
|
|
||||||
"%04X %04X %04X %04X",
|
|
||||||
(unsigned)nfo.regs[8], (unsigned)nfo.regs[9],
|
|
||||||
(unsigned)nfo.regs[10], (unsigned)nfo.regs[11]);
|
|
||||||
simplelist_addline(SIMPLELIST_ADD_LINE,
|
|
||||||
"%04X %04X %04X %04X",
|
|
||||||
(unsigned)nfo.regs[12], (unsigned)nfo.regs[13],
|
|
||||||
(unsigned)nfo.regs[14], (unsigned)nfo.regs[15]);
|
|
||||||
#endif /* SI4700 */
|
#endif /* SI4700 */
|
||||||
|
#if (CONFIG_TUNER & FMCLIPPLUS)
|
||||||
|
IF_TUNER_TYPE(FMCLIPPLUS)
|
||||||
|
{
|
||||||
|
struct fmclipplus_dbg_info nfo;
|
||||||
|
int i;
|
||||||
|
fmclipplus_dbg_info(&nfo);
|
||||||
|
simplelist_addline(SIMPLELIST_ADD_LINE, "FM Clip+ regs:");
|
||||||
|
for (i = 0; i < 32; i += 4) {
|
||||||
|
simplelist_addline(SIMPLELIST_ADD_LINE,"%02X: %04X %04X %04X %04X",
|
||||||
|
i, nfo.regs[i], nfo.regs[i+1], nfo.regs[i+2], nfo.regs[i+3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* FMCLIPPLUS */
|
||||||
return ACTION_REDRAW;
|
return ACTION_REDRAW;
|
||||||
}
|
}
|
||||||
static bool dbg_fm_radio(void)
|
static bool dbg_fm_radio(void)
|
||||||
{
|
{
|
||||||
struct simplelist_info info;
|
struct simplelist_info info;
|
||||||
|
#ifdef CONFIG_TUNER_MULTI
|
||||||
|
tuner_type = tuner_detect_type();
|
||||||
|
#endif
|
||||||
info.scroll_all = true;
|
info.scroll_all = true;
|
||||||
simplelist_info_init(&info, "FM Radio", 1, NULL);
|
simplelist_info_init(&info, "FM Radio", 1, NULL);
|
||||||
simplelist_set_line_count(0);
|
simplelist_set_line_count(0);
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,9 @@ drivers/tuner/si4700.c
|
||||||
#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
|
#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
|
||||||
drivers/tuner/ipod_remote_tuner.c
|
drivers/tuner/ipod_remote_tuner.c
|
||||||
#endif /* (CONFIG_TUNER & IPOD_REMOTE_TUNER) */
|
#endif /* (CONFIG_TUNER & IPOD_REMOTE_TUNER) */
|
||||||
|
#if (CONFIG_TUNER & FMCLIPPLUS)
|
||||||
|
drivers/tuner/fmclipplus.c
|
||||||
|
#endif /* (CONFIG_TUNER & FMCLIPPLUS) */
|
||||||
#endif /*SIMULATOR */
|
#endif /*SIMULATOR */
|
||||||
#endif /* CONFIG_TUNER */
|
#endif /* CONFIG_TUNER */
|
||||||
#endif /* BOOTLOADER */
|
#endif /* BOOTLOADER */
|
||||||
|
|
@ -1251,6 +1254,7 @@ target/arm/as3525/sansa-clipplus/backlight-clip.c
|
||||||
target/arm/powermgmt-ascodec.c
|
target/arm/powermgmt-ascodec.c
|
||||||
target/arm/as3525/sansa-clipplus/powermgmt-clipplus.c
|
target/arm/as3525/sansa-clipplus/powermgmt-clipplus.c
|
||||||
target/arm/as3525/sansa-clipplus/lcd-as-clip-plus.S
|
target/arm/as3525/sansa-clipplus/lcd-as-clip-plus.S
|
||||||
|
target/arm/as3525/sansa-clipplus/tuner-clipplus.c
|
||||||
#endif /* !BOOTLOADER */
|
#endif /* !BOOTLOADER */
|
||||||
#endif /* !SIMULATOR */
|
#endif /* !SIMULATOR */
|
||||||
#endif /* SANSA_CLIPPLUS */
|
#endif /* SANSA_CLIPPLUS */
|
||||||
|
|
|
||||||
328
firmware/drivers/tuner/fmclipplus.c
Normal file
328
firmware/drivers/tuner/fmclipplus.c
Normal file
|
|
@ -0,0 +1,328 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Tuner "middleware" for unidentified Silicon Labs chip present in some
|
||||||
|
* Sansa Clip+ players
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Bertrik Sikken
|
||||||
|
* Copyright (C) 2008 Nils Wallménius (si4700 code that this was based on)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "tuner.h" /* tuner abstraction interface */
|
||||||
|
#include "fmradio.h"
|
||||||
|
#include "fmradio_i2c.h" /* physical interface driver */
|
||||||
|
|
||||||
|
#define SEEK_THRESHOLD 0x10
|
||||||
|
|
||||||
|
#define I2C_ADR 0x20
|
||||||
|
|
||||||
|
/** Registers and bits **/
|
||||||
|
#define POWERCFG 0x2
|
||||||
|
#define CHANNEL 0x3
|
||||||
|
#define SYSCONFIG1 0x4
|
||||||
|
#define SYSCONFIG2 0x5
|
||||||
|
#define SYSCONFIG3 0x6
|
||||||
|
|
||||||
|
#define READCHAN 0xA
|
||||||
|
#define STATUSRSSI 0xB
|
||||||
|
#define IDENT 0xC
|
||||||
|
|
||||||
|
|
||||||
|
/* POWERCFG (0x2) */
|
||||||
|
#define POWERCFG_DMUTE (0x1 << 14)
|
||||||
|
#define POWERCFG_MONO (0x1 << 13)
|
||||||
|
#define POWERCFG_ENABLE (0x1 << 0)
|
||||||
|
|
||||||
|
/* CHANNEL (0x3) */
|
||||||
|
#define CHANNEL_CHAN (0x3ff << 6)
|
||||||
|
#define CHANNEL_CHANw(x) (((x) << 6) & CHANNEL_CHAN)
|
||||||
|
#define CHANNEL_TUNE (0x1 << 4)
|
||||||
|
#define CHANNEL_BAND (0x3 << 2)
|
||||||
|
#define CHANNEL_BANDw(x) (((x) << 2) & CHANNEL_BAND)
|
||||||
|
#define CHANNEL_BANDr(x) (((x) & CHANNEL_BAND) >> 2)
|
||||||
|
#define CHANNEL_BAND_875_1080 (0x0 << 2) /* tenth-megahertz */
|
||||||
|
#define CHANNEL_BAND_760_1080 (0x1 << 2)
|
||||||
|
#define CHANNEL_BAND_760_900 (0x2 << 2)
|
||||||
|
#define CHANNEL_SPACE (0x3 << 0)
|
||||||
|
#define CHANNEL_SPACEw(x) (((x) << 0) & CHANNEL_SPACE)
|
||||||
|
#define CHANNEL_SPACEr(x) (((x) & CHANNEL_SPACE) >> 0)
|
||||||
|
#define CHANNEL_SPACE_200KHZ (0x0 << 0)
|
||||||
|
#define CHANNEL_SPACE_100KHZ (0x1 << 0)
|
||||||
|
#define CHANNEL_SPACE_50KHZ (0x2 << 0)
|
||||||
|
|
||||||
|
/* SYSCONFIG1 (0x4) */
|
||||||
|
#define SYSCONFIG1_DE (0x1 << 11)
|
||||||
|
|
||||||
|
/* READCHAN (0xA) */
|
||||||
|
#define READCHAN_READCHAN (0x3ff << 0)
|
||||||
|
#define READCHAN_READCHANr(x) (((x) & READCHAN_READCHAN) >> 0)
|
||||||
|
#define READCHAN_STC (0x1 << 14)
|
||||||
|
|
||||||
|
/* STATUSRSSI (0xB) */
|
||||||
|
#define STATUSRSSI_RSSI (0x3F << 10)
|
||||||
|
#define STATUSRSSI_RSSIr(x) (((x) & STATUSRSSI_RSSI) >> 10)
|
||||||
|
#define STATUSRSSI_AFCRL (0x1 << 8)
|
||||||
|
|
||||||
|
static const uint16_t initvals[32] = {
|
||||||
|
0x8110, 0x4580, 0xC401, 0x1B90,
|
||||||
|
0x0400, 0x866F, 0x8000, 0x4712,
|
||||||
|
0x5EC6, 0x0000, 0x406E, 0x2D80,
|
||||||
|
0x5803, 0x5804, 0x5804, 0x5804,
|
||||||
|
|
||||||
|
0x0047, 0x9000, 0xF587, 0x0009,
|
||||||
|
0x00F1, 0x41C0, 0x41E0, 0x506F,
|
||||||
|
0x5592, 0x007D, 0x10A0, 0x0780,
|
||||||
|
0x311D, 0x4006, 0x1F9B, 0x4C2B
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool tuner_present = false;
|
||||||
|
static int curr_frequency = 87500000; /* Current station frequency (HZ) */
|
||||||
|
static uint16_t cache[32];
|
||||||
|
|
||||||
|
/* reads <len> registers from radio at offset 0x0A into cache */
|
||||||
|
static void fmclipplus_read(int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char buf[64];
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
uint16_t data;
|
||||||
|
|
||||||
|
fmradio_i2c_read(I2C_ADR, buf, len * 2);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
data = ptr[0] << 8 | ptr[1];
|
||||||
|
cache[(i + READCHAN) & 0x1F] = data;
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* writes <len> registers from cache to radio at offset 0x02 */
|
||||||
|
static void fmclipplus_write(int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char buf[64];
|
||||||
|
unsigned char *ptr = buf;
|
||||||
|
uint16_t data;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
data = cache[(i + POWERCFG) & 0x1F];
|
||||||
|
*ptr++ = (data >> 8) & 0xFF;
|
||||||
|
*ptr++ = data & 0xFF;
|
||||||
|
}
|
||||||
|
fmradio_i2c_write(I2C_ADR, buf, len * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t fmclipplus_read_reg(int reg)
|
||||||
|
{
|
||||||
|
fmclipplus_read(((reg - READCHAN) & 0x1F) + 1);
|
||||||
|
return cache[reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fmclipplus_write_reg(int reg, uint16_t value)
|
||||||
|
{
|
||||||
|
cache[reg] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fmclipplus_write_cache(void)
|
||||||
|
{
|
||||||
|
fmclipplus_write(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fmclipplus_write_masked(int reg, uint16_t bits, uint16_t mask)
|
||||||
|
{
|
||||||
|
fmclipplus_write_reg(reg, (cache[reg] & ~mask) | (bits & mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fmclipplus_write_clear(int reg, uint16_t mask)
|
||||||
|
{
|
||||||
|
fmclipplus_write_reg(reg, cache[reg] & ~mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fmclipplus_sleep(int snooze)
|
||||||
|
{
|
||||||
|
if (snooze) {
|
||||||
|
fmclipplus_write_masked(POWERCFG, 0, 0xFF);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fmclipplus_write_masked(POWERCFG, 1, 0xFF);
|
||||||
|
}
|
||||||
|
fmclipplus_write_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fmclipplus_detect(void)
|
||||||
|
{
|
||||||
|
return ((fmclipplus_read_reg(IDENT) & 0xFF00) == 0x5800);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmclipplus_init(void)
|
||||||
|
{
|
||||||
|
if (fmclipplus_detect()) {
|
||||||
|
tuner_present = true;
|
||||||
|
|
||||||
|
// send pre-initialisation value
|
||||||
|
fmclipplus_write_reg(POWERCFG, 0x200);
|
||||||
|
fmclipplus_write(2);
|
||||||
|
sleep(HZ * 10 / 100);
|
||||||
|
|
||||||
|
// write initialisation values
|
||||||
|
memcpy(cache, initvals, sizeof(cache));
|
||||||
|
fmclipplus_write(32);
|
||||||
|
sleep(HZ * 70 / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fmclipplus_set_frequency(int freq)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* check BAND and spacings */
|
||||||
|
fmclipplus_read_reg(STATUSRSSI);
|
||||||
|
int start = CHANNEL_BANDr(cache[CHANNEL]) & 1 ? 76000000 : 87000000;
|
||||||
|
int chan = (freq - start) / 50000;
|
||||||
|
|
||||||
|
curr_frequency = freq;
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
/* tune and wait a bit */
|
||||||
|
fmclipplus_write_masked(CHANNEL, CHANNEL_CHANw(chan) | CHANNEL_TUNE,
|
||||||
|
CHANNEL_CHAN | CHANNEL_TUNE);
|
||||||
|
fmclipplus_write_cache();
|
||||||
|
sleep(HZ * 70 / 1000);
|
||||||
|
fmclipplus_write_clear(CHANNEL, CHANNEL_TUNE);
|
||||||
|
fmclipplus_write_cache();
|
||||||
|
|
||||||
|
/* check if tuning was successful */
|
||||||
|
fmclipplus_read_reg(STATUSRSSI);
|
||||||
|
if (cache[READCHAN] & READCHAN_STC) {
|
||||||
|
if (READCHAN_READCHANr(cache[READCHAN]) == chan) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fmclipplus_tuned(void)
|
||||||
|
{
|
||||||
|
/* Primitive tuning check: sufficient level and AFC not railed */
|
||||||
|
uint16_t status = fmclipplus_read_reg(STATUSRSSI);
|
||||||
|
if (STATUSRSSI_RSSIr(status) >= SEEK_THRESHOLD &&
|
||||||
|
(status & STATUSRSSI_AFCRL) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fmclipplus_set_region(int region)
|
||||||
|
{
|
||||||
|
const struct fmclipplus_region_data *rd = &fmclipplus_region_data[region];
|
||||||
|
uint16_t bandspacing = CHANNEL_BANDw(rd->band) |
|
||||||
|
CHANNEL_SPACEw(CHANNEL_SPACE_50KHZ);
|
||||||
|
uint16_t oldbs = cache[CHANNEL] & (CHANNEL_BAND | CHANNEL_SPACE);
|
||||||
|
|
||||||
|
fmclipplus_write_masked(SYSCONFIG1, rd->deemphasis ? SYSCONFIG1_DE : 0,
|
||||||
|
SYSCONFIG1_DE);
|
||||||
|
fmclipplus_write_masked(CHANNEL, bandspacing, CHANNEL_BAND | CHANNEL_SPACE);
|
||||||
|
fmclipplus_write_cache();
|
||||||
|
|
||||||
|
/* Retune if this region change would change the channel number. */
|
||||||
|
if (oldbs != bandspacing) {
|
||||||
|
fmclipplus_set_frequency(curr_frequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fmclipplus_st(void)
|
||||||
|
{
|
||||||
|
/* TODO not implemented yet */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tuner abstraction layer: set something to the tuner */
|
||||||
|
int fmclipplus_set(int setting, int value)
|
||||||
|
{
|
||||||
|
switch (setting) {
|
||||||
|
case RADIO_SLEEP:
|
||||||
|
if (value != 2) {
|
||||||
|
fmclipplus_sleep(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RADIO_FREQUENCY:
|
||||||
|
fmclipplus_set_frequency(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RADIO_SCAN_FREQUENCY:
|
||||||
|
fmclipplus_set_frequency(value);
|
||||||
|
return fmclipplus_tuned();
|
||||||
|
|
||||||
|
case RADIO_MUTE:
|
||||||
|
fmclipplus_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE,
|
||||||
|
POWERCFG_DMUTE);
|
||||||
|
fmclipplus_write_masked(SYSCONFIG1, (3 << 9), (3 << 9));
|
||||||
|
fmclipplus_write_masked(SYSCONFIG2, (0xF << 0), (0xF << 0));
|
||||||
|
fmclipplus_write_cache();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RADIO_REGION:
|
||||||
|
fmclipplus_set_region(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RADIO_FORCE_MONO:
|
||||||
|
fmclipplus_write_masked(POWERCFG, value ? POWERCFG_MONO : 0,
|
||||||
|
POWERCFG_MONO);
|
||||||
|
fmclipplus_write_cache();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tuner abstraction layer: read something from the tuner */
|
||||||
|
int fmclipplus_get(int setting)
|
||||||
|
{
|
||||||
|
int val = -1; /* default for unsupported query */
|
||||||
|
|
||||||
|
switch (setting) {
|
||||||
|
case RADIO_PRESENT:
|
||||||
|
val = tuner_present ? 1 : 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RADIO_TUNED:
|
||||||
|
val = fmclipplus_tuned();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RADIO_STEREO:
|
||||||
|
val = fmclipplus_st();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmclipplus_dbg_info(struct fmclipplus_dbg_info *nfo)
|
||||||
|
{
|
||||||
|
fmclipplus_read(32);
|
||||||
|
memcpy(nfo->regs, cache, sizeof (nfo->regs));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -316,30 +316,39 @@ static void si4700_sleep(int snooze)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool si4700_detect(void)
|
||||||
|
{
|
||||||
|
bool detected;
|
||||||
|
|
||||||
|
tuner_power(true);
|
||||||
|
detected = (si4700_read_reg(DEVICEID) == 0x1242);
|
||||||
|
tuner_power(false);
|
||||||
|
|
||||||
|
return detected;
|
||||||
|
}
|
||||||
|
|
||||||
void si4700_init(void)
|
void si4700_init(void)
|
||||||
{
|
{
|
||||||
tuner_power(true);
|
|
||||||
|
|
||||||
/* read all registers */
|
|
||||||
si4700_read(16);
|
|
||||||
si4700_sleep(0);
|
|
||||||
|
|
||||||
/* check device id */
|
/* check device id */
|
||||||
if (cache[DEVICEID] == 0x1242)
|
if (si4700_detect()) {
|
||||||
{
|
|
||||||
tuner_present = true;
|
tuner_present = true;
|
||||||
|
|
||||||
|
tuner_power(true);
|
||||||
|
|
||||||
|
/* read all registers */
|
||||||
|
si4700_read(16);
|
||||||
|
si4700_sleep(0);
|
||||||
|
|
||||||
#ifdef USE_INTERNAL_OSCILLATOR
|
#ifdef USE_INTERNAL_OSCILLATOR
|
||||||
/* Enable the internal oscillator
|
/* Enable the internal oscillator
|
||||||
(Si4702-16 needs this register to be initialised to 0x100) */
|
(Si4702-16 needs this register to be initialised to 0x100) */
|
||||||
si4700_write_set(TEST1, TEST1_XOSCEN | 0x100);
|
si4700_write_set(TEST1, TEST1_XOSCEN | 0x100);
|
||||||
sleep(HZ/2);
|
sleep(HZ/2);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
si4700_sleep(1);
|
||||||
|
tuner_power(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
si4700_sleep(1);
|
|
||||||
|
|
||||||
tuner_power(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void si4700_set_frequency(int freq)
|
static void si4700_set_frequency(int freq)
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
#define TEA5760 0x10 /* Philips */
|
#define TEA5760 0x10 /* Philips */
|
||||||
#define LV240000 0x20 /* Sanyo */
|
#define LV240000 0x20 /* Sanyo */
|
||||||
#define IPOD_REMOTE_TUNER 0x40 /* Apple */
|
#define IPOD_REMOTE_TUNER 0x40 /* Apple */
|
||||||
|
#define FMCLIPPLUS 0x80 /* Mystery SiLabs FM tuner in some clip+ */
|
||||||
|
|
||||||
/* CONFIG_CODEC */
|
/* CONFIG_CODEC */
|
||||||
#define MAS3587F 3587
|
#define MAS3587F 3587
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@
|
||||||
#define AB_REPEAT_ENABLE 1
|
#define AB_REPEAT_ENABLE 1
|
||||||
|
|
||||||
/* FM Tuner */
|
/* FM Tuner */
|
||||||
#define CONFIG_TUNER SI4700 /* in fact SI4702 */
|
#define CONFIG_TUNER (SI4700|FMCLIPPLUS) /* in fact SI4702 */
|
||||||
//#define HAVE_TUNER_PWR_CTRL
|
//#define HAVE_TUNER_PWR_CTRL
|
||||||
|
|
||||||
/* Define this for LCD backlight available */
|
/* Define this for LCD backlight available */
|
||||||
|
|
|
||||||
54
firmware/export/fmclipplus.h
Normal file
54
firmware/export/fmclipplus.h
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Tuner header for the Silicon Labs Mystery radio chip in some Sansa Clip+
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Bertrik Sikken
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _FMCLIPPLUS_H_
|
||||||
|
#define _FMCLIPPLUS_H_
|
||||||
|
|
||||||
|
#define HAVE_RADIO_REGION
|
||||||
|
|
||||||
|
struct fmclipplus_region_data
|
||||||
|
{
|
||||||
|
unsigned char deemphasis; /* 0: 75us, 1: 50us */
|
||||||
|
unsigned char band; /* 0: us/europe, 1: japan */
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
extern const struct fmclipplus_region_data fmclipplus_region_data[TUNER_NUM_REGIONS];
|
||||||
|
|
||||||
|
struct fmclipplus_dbg_info
|
||||||
|
{
|
||||||
|
uint16_t regs[32]; /* Read registers */
|
||||||
|
};
|
||||||
|
|
||||||
|
bool fmclipplus_detect(void);
|
||||||
|
void fmclipplus_init(void);
|
||||||
|
int fmclipplus_set(int setting, int value);
|
||||||
|
int fmclipplus_get(int setting);
|
||||||
|
void fmclipplus_dbg_info(struct fmclipplus_dbg_info *nfo);
|
||||||
|
|
||||||
|
#ifndef CONFIG_TUNER_MULTI
|
||||||
|
#define tuner_set fmclipplus_set
|
||||||
|
#define tuner_get fmclipplus_get
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _FMCLIPPLUS_H_ */
|
||||||
|
|
@ -41,6 +41,7 @@ struct si4700_dbg_info
|
||||||
uint16_t regs[16]; /* Read registers */
|
uint16_t regs[16]; /* Read registers */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool si4700_detect(void);
|
||||||
void si4700_init(void);
|
void si4700_init(void);
|
||||||
int si4700_set(int setting, int value);
|
int si4700_set(int setting, int value);
|
||||||
int si4700_get(int setting);
|
int si4700_get(int setting);
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ char* tuner_get_rds_info(int setting);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifdef CONFIG_TUNER_MULTI
|
#ifdef CONFIG_TUNER_MULTI
|
||||||
|
extern int tuner_detect_type(void);
|
||||||
extern int (*tuner_set)(int setting, int value);
|
extern int (*tuner_set)(int setting, int value);
|
||||||
extern int (*tuner_get)(int setting);
|
extern int (*tuner_get)(int setting);
|
||||||
#endif /* CONFIG_TUNER_MULTI */
|
#endif /* CONFIG_TUNER_MULTI */
|
||||||
|
|
@ -131,6 +132,11 @@ extern int (*tuner_get)(int setting);
|
||||||
#include "si4700.h"
|
#include "si4700.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Silicon Labs mystery radio chip in some Sansa Clip+ */
|
||||||
|
#if (CONFIG_TUNER & FMCLIPPLUS)
|
||||||
|
#include "fmclipplus.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Apple remote tuner */
|
/* Apple remote tuner */
|
||||||
#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
|
#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
|
||||||
#include "ipod_remote_tuner.h"
|
#include "ipod_remote_tuner.h"
|
||||||
|
|
|
||||||
38
firmware/target/arm/as3525/sansa-clipplus/tuner-clipplus.c
Normal file
38
firmware/target/arm/as3525/sansa-clipplus/tuner-clipplus.c
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Multi-tuner detection module to select between the si4700 and a yet
|
||||||
|
* unidentified Silicon Labs FM tuner chip found in some Sansa Clip+ players.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Bertrik Sikken
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "tuner.h"
|
||||||
|
|
||||||
|
int tuner_detect_type(void)
|
||||||
|
{
|
||||||
|
if (si4700_detect()) {
|
||||||
|
return SI4700;
|
||||||
|
} else if (fmclipplus_detect()) {
|
||||||
|
return FMCLIPPLUS;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -89,6 +89,18 @@ const struct si4700_region_data si4700_region_data[TUNER_NUM_REGIONS] =
|
||||||
};
|
};
|
||||||
#endif /* (CONFIG_TUNER & SI4700) */
|
#endif /* (CONFIG_TUNER & SI4700) */
|
||||||
|
|
||||||
|
#if (CONFIG_TUNER & FMCLIPPLUS)
|
||||||
|
const struct fmclipplus_region_data fmclipplus_region_data[TUNER_NUM_REGIONS] =
|
||||||
|
{
|
||||||
|
[REGION_EUROPE] = { 1, 0 }, /* 50uS, US/Europe band */
|
||||||
|
[REGION_US_CANADA] = { 0, 0 }, /* 75uS, US/Europe band */
|
||||||
|
[REGION_JAPAN] = { 1, 1 }, /* 50uS, Japanese band */
|
||||||
|
[REGION_KOREA] = { 1, 0 }, /* 50uS, US/Europe band */
|
||||||
|
[REGION_ITALY] = { 1, 0 }, /* 50uS, US/Europe band */
|
||||||
|
[REGION_OTHER] = { 1, 0 }, /* 50uS, US/Europe band */
|
||||||
|
};
|
||||||
|
#endif /* (CONFIG_TUNER & FMCLIPPLUS) */
|
||||||
|
|
||||||
#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
|
#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
|
||||||
const struct rmt_tuner_region_data
|
const struct rmt_tuner_region_data
|
||||||
rmt_tuner_region_data[TUNER_NUM_REGIONS] =
|
rmt_tuner_region_data[TUNER_NUM_REGIONS] =
|
||||||
|
|
@ -151,6 +163,12 @@ void tuner_init(void)
|
||||||
si4700_get,
|
si4700_get,
|
||||||
si4700_init())
|
si4700_init())
|
||||||
#endif
|
#endif
|
||||||
|
#if (CONFIG_TUNER & FMCLIPPLUS)
|
||||||
|
TUNER_TYPE_CASE(FMCLIPPLUS,
|
||||||
|
fmclipplus_set,
|
||||||
|
fmclipplus_get,
|
||||||
|
fmclipplus_init())
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SIMULATOR */
|
#endif /* SIMULATOR */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue