mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
Meizu: implement i2c for the meizu fmradio and update the tea5760 tuner driver
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21703 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
8d4d4610b6
commit
4e965b4b6c
5 changed files with 296 additions and 38 deletions
|
@ -28,10 +28,20 @@
|
||||||
#include "fmradio.h"
|
#include "fmradio.h"
|
||||||
#include "fmradio_i2c.h" /* physical interface driver */
|
#include "fmradio_i2c.h" /* physical interface driver */
|
||||||
|
|
||||||
#define I2C_ADR 0xC0
|
#define I2C_ADR 0x22
|
||||||
static unsigned char write_bytes[7] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
static void tea5760uk_set_clear(int byte, unsigned char bits, int set)
|
static bool tuner_present = false;
|
||||||
|
static unsigned char write_bytes[7] = {
|
||||||
|
0x00, /* INTREG LSB */
|
||||||
|
0x80, /* FRQSET MSB */
|
||||||
|
0x00, /* FRQSET LSB */
|
||||||
|
0x08, /* TNCTRL MSB */
|
||||||
|
0xD2, /* TNCTRL LSB */
|
||||||
|
0x00, /* TESTREG MSB */
|
||||||
|
0x40 /* TESTREG LSB */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void tea5760_set_clear(int byte, unsigned char bits, int set)
|
||||||
{
|
{
|
||||||
write_bytes[byte] &= ~bits;
|
write_bytes[byte] &= ~bits;
|
||||||
if (set)
|
if (set)
|
||||||
|
@ -39,58 +49,60 @@ static void tea5760uk_set_clear(int byte, unsigned char bits, int set)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tuner abstraction layer: set something to the tuner */
|
/* tuner abstraction layer: set something to the tuner */
|
||||||
int tea5760uk_set(int setting, int value)
|
int tea5760_set(int setting, int value)
|
||||||
{
|
{
|
||||||
switch(setting)
|
switch(setting)
|
||||||
{
|
{
|
||||||
case RADIO_SLEEP:
|
case RADIO_SLEEP:
|
||||||
/* init values */
|
if (value) {
|
||||||
write_bytes[0] |= (1<<7); /* mute */
|
/* sleep / standby mode */
|
||||||
#if CONFIG_TUNER_XTAL == 32768
|
tea5760_set_clear(3, (1<<6), 0);
|
||||||
/* 32.768kHz, soft mute, stereo noise cancelling */
|
}
|
||||||
write_bytes[3] |= (1<<4) | (1<<3) | (1<<1);
|
else {
|
||||||
#else
|
/* active mode */
|
||||||
/* soft mute, stereo noise cancelling */
|
tea5760_set_clear(3, (1<<6), 1);
|
||||||
write_bytes[3] |= (1<<3) | (1<<1);
|
/* disable hard mute */
|
||||||
#endif
|
tea5760_set_clear(4, (1<<7), 0);
|
||||||
/* sleep / standby mode */
|
}
|
||||||
tea5760uk_set_clear(3, (1<<6), value);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RADIO_FREQUENCY:
|
case RADIO_FREQUENCY:
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
#if CONFIG_TUNER_XTAL == 32768
|
|
||||||
|
/* low side injection */
|
||||||
|
tea5760_set_clear(4, (1<<4), 0);
|
||||||
n = (4 * (value - 225000) + 16384) / 32768;
|
n = (4 * (value - 225000) + 16384) / 32768;
|
||||||
#else
|
|
||||||
n = (4 * (value - 225000)) / 50000;
|
/* set frequency in preset mode */
|
||||||
#endif
|
write_bytes[1] = (n >> 8) & 0x3F;
|
||||||
write_bytes[6] = (write_bytes[6] & 0xC0) | (n >> 8);
|
write_bytes[2] = n;
|
||||||
write_bytes[7] = n;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RADIO_SCAN_FREQUENCY:
|
case RADIO_SCAN_FREQUENCY:
|
||||||
tea5760uk_set(RADIO_FREQUENCY, value);
|
tea5760_set(RADIO_FREQUENCY, value);
|
||||||
sleep(HZ/30);
|
sleep(40*HZ/1000);
|
||||||
return tea5760uk_get(RADIO_TUNED);
|
return tea5760_get(RADIO_TUNED);
|
||||||
|
|
||||||
case RADIO_MUTE:
|
case RADIO_MUTE:
|
||||||
tea5760uk_set_clear(3, (1<<2), value);
|
tea5760_set_clear(3, (1<<2), value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RADIO_REGION:
|
case RADIO_REGION:
|
||||||
{
|
{
|
||||||
const struct tea5760uk_region_data *rd =
|
const struct tea5760_region_data *rd =
|
||||||
&tea5760uk_region_data[value];
|
&tea5760_region_data[value];
|
||||||
|
|
||||||
tea5760uk_set_clear(4, (1<<1), rd->deemphasis);
|
tea5760_set_clear(4, (1<<1), rd->deemphasis);
|
||||||
tea5760uk_set_clear(3, (1<<5), rd->band);
|
tea5760_set_clear(3, (1<<5), rd->band);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case RADIO_FORCE_MONO:
|
|
||||||
tea5760uk_set_clear(4, (1<<3), value);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RADIO_FORCE_MONO:
|
||||||
|
tea5760_set_clear(4, (1<<3), value);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +112,7 @@ int tea5760uk_set(int setting, int value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tuner abstraction layer: read something from the tuner */
|
/* tuner abstraction layer: read something from the tuner */
|
||||||
int tea5760uk_get(int setting)
|
int tea5760_get(int setting)
|
||||||
{
|
{
|
||||||
unsigned char read_bytes[16];
|
unsigned char read_bytes[16];
|
||||||
int val = -1; /* default for unsupported query */
|
int val = -1; /* default for unsupported query */
|
||||||
|
@ -110,7 +122,7 @@ int tea5760uk_get(int setting)
|
||||||
switch(setting)
|
switch(setting)
|
||||||
{
|
{
|
||||||
case RADIO_PRESENT:
|
case RADIO_PRESENT:
|
||||||
val = 1; /* true */
|
val = tuner_present ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RADIO_TUNED:
|
case RADIO_TUNED:
|
||||||
|
@ -130,8 +142,31 @@ int tea5760uk_get(int setting)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tea5760uk_dbg_info(struct tea5760uk_dbg_info *info)
|
void tea5760_init(void)
|
||||||
{
|
{
|
||||||
fmradio_i2c_read(I2C_ADR, info->read_regs, 5);
|
unsigned char buf[16];
|
||||||
memcpy(info->write_regs, write_bytes, 5);
|
unsigned short manid, chipid;
|
||||||
|
|
||||||
|
/* read all registers */
|
||||||
|
fmradio_i2c_read(I2C_ADR, buf, sizeof(buf));
|
||||||
|
|
||||||
|
/* check device id */
|
||||||
|
manid = (buf[12] << 8) | buf[13];
|
||||||
|
chipid = (buf[14] << 8) | buf[15];
|
||||||
|
if ((manid == 0x202B) && (chipid == 0x5760))
|
||||||
|
{
|
||||||
|
tuner_present = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write initial values */
|
||||||
|
tea5760_set_clear(3, (1<<1), 1); /* soft mute on */
|
||||||
|
tea5760_set_clear(3, (1<<0), 1); /* stereo noise cancellation on */
|
||||||
|
fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tea5760_dbg_info(struct tea5760_dbg_info *info)
|
||||||
|
{
|
||||||
|
fmradio_i2c_read(I2C_ADR, info->read_regs, sizeof(info->read_regs));
|
||||||
|
memcpy(info->write_regs, write_bytes, sizeof(info->write_regs));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
56
firmware/export/tea5760.h
Normal file
56
firmware/export/tea5760.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
* Tuner header for the Philips TEA5760
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 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 _TEA5760_H_
|
||||||
|
#define _TEA5760_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "tuner.h"
|
||||||
|
|
||||||
|
#define HAVE_RADIO_REGION
|
||||||
|
|
||||||
|
struct tea5760_region_data
|
||||||
|
{
|
||||||
|
unsigned char deemphasis; /* 1: 50us, 0: 75us */
|
||||||
|
unsigned char band; /* 0: europe, 1: japan (BL in TEA spec)*/
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
extern const struct tea5760_region_data tea5760_region_data[TUNER_NUM_REGIONS];
|
||||||
|
|
||||||
|
struct tea5760_dbg_info
|
||||||
|
{
|
||||||
|
unsigned char read_regs[16];
|
||||||
|
unsigned char write_regs[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
int tea5760_set(int setting, int value);
|
||||||
|
int tea5760_get(int setting);
|
||||||
|
void tea5760_init(void);
|
||||||
|
void tea5760_dbg_info(struct tea5760_dbg_info *info);
|
||||||
|
|
||||||
|
#ifndef CONFIG_TUNER_MULTI
|
||||||
|
#define tuner_set tea5760_set
|
||||||
|
#define tuner_get tea5760_get
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _TEA5760_H_ */
|
||||||
|
|
|
@ -96,6 +96,11 @@ extern int (*tuner_get)(int setting);
|
||||||
#include "s1a0903x01.h"
|
#include "s1a0903x01.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Philips TEA5760 **/
|
||||||
|
#if (CONFIG_TUNER & TEA5760)
|
||||||
|
#include "tea5760.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Philips TEA5767 **/
|
/** Philips TEA5767 **/
|
||||||
#if (CONFIG_TUNER & TEA5767)
|
#if (CONFIG_TUNER & TEA5767)
|
||||||
/* Ondio FM, FM Recorder, Recorder V2, iRiver h100/h300, iAudio x5 */
|
/* Ondio FM, FM Recorder, Recorder V2, iRiver h100/h300, iAudio x5 */
|
||||||
|
|
146
firmware/target/arm/s5l8700/fmradio-i2c-meizu.c
Normal file
146
firmware/target/arm/s5l8700/fmradio-i2c-meizu.c
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 by 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
FM radio i2c interface, allows the radio driver to talk to the tuner chip.
|
||||||
|
|
||||||
|
It is implemented using the generic i2c driver, which does "bit-banged"
|
||||||
|
I2C with a couple of GPIO pins.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "inttypes.h"
|
||||||
|
#include "s5l8700.h"
|
||||||
|
#include "generic_i2c.h"
|
||||||
|
#include "fmradio_i2c.h"
|
||||||
|
|
||||||
|
#define I2C_GPIO PDAT3
|
||||||
|
#define I2C_GPIO_DIR PCON3
|
||||||
|
#define I2C_SCL_PIN 4
|
||||||
|
#define I2C_SDA_PIN 2
|
||||||
|
|
||||||
|
#define SCL_DIR_MASK (3<<(4*I2C_SCL_PIN))
|
||||||
|
#define SCL_DIR_OUT (1<<(4*I2C_SCL_PIN))
|
||||||
|
#define SCL_DIR_IN 0
|
||||||
|
#define SDA_DIR_MASK (3<<(4*I2C_SDA_PIN))
|
||||||
|
#define SDA_DIR_OUT (1<<(4*I2C_SDA_PIN))
|
||||||
|
#define SDA_DIR_IN 0
|
||||||
|
|
||||||
|
static int fm_i2c_bus;
|
||||||
|
|
||||||
|
static void fm_scl_hi(void)
|
||||||
|
{
|
||||||
|
I2C_GPIO |= 1 << I2C_SCL_PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fm_scl_lo(void)
|
||||||
|
{
|
||||||
|
I2C_GPIO &= ~(1 << I2C_SCL_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fm_sda_hi(void)
|
||||||
|
{
|
||||||
|
I2C_GPIO |= 1 << I2C_SDA_PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fm_sda_lo(void)
|
||||||
|
{
|
||||||
|
I2C_GPIO &= ~(1 << I2C_SDA_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fm_sda_input(void)
|
||||||
|
{
|
||||||
|
I2C_GPIO_DIR = (I2C_GPIO_DIR & ~SDA_DIR_MASK) | SDA_DIR_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fm_sda_output(void)
|
||||||
|
{
|
||||||
|
I2C_GPIO_DIR = (I2C_GPIO_DIR & ~SDA_DIR_MASK) | SDA_DIR_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fm_scl_input(void)
|
||||||
|
{
|
||||||
|
I2C_GPIO_DIR = (I2C_GPIO_DIR & ~SCL_DIR_MASK) | SCL_DIR_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fm_scl_output(void)
|
||||||
|
{
|
||||||
|
I2C_GPIO_DIR = (I2C_GPIO_DIR & ~SCL_DIR_MASK) | SCL_DIR_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fm_sda(void)
|
||||||
|
{
|
||||||
|
return (I2C_GPIO & (1 << I2C_SDA_PIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fm_scl(void)
|
||||||
|
{
|
||||||
|
return (I2C_GPIO & (1 << I2C_SCL_PIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simple and crude delay, used for all delays in the generic i2c driver */
|
||||||
|
static void fm_delay(void)
|
||||||
|
{
|
||||||
|
volatile int i;
|
||||||
|
|
||||||
|
/* this loop is uncalibrated and could use more sophistication */
|
||||||
|
for (i = 0; i < 20; i++) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* interface towards the generic i2c driver */
|
||||||
|
static const struct i2c_interface fm_i2c_interface = {
|
||||||
|
.scl_hi = fm_scl_hi,
|
||||||
|
.scl_lo = fm_scl_lo,
|
||||||
|
.sda_hi = fm_sda_hi,
|
||||||
|
.sda_lo = fm_sda_lo,
|
||||||
|
.sda_input = fm_sda_input,
|
||||||
|
.sda_output = fm_sda_output,
|
||||||
|
.scl_input = fm_scl_input,
|
||||||
|
.scl_output = fm_scl_output,
|
||||||
|
.scl = fm_scl,
|
||||||
|
.sda = fm_sda,
|
||||||
|
|
||||||
|
.delay_hd_sta = fm_delay,
|
||||||
|
.delay_hd_dat = fm_delay,
|
||||||
|
.delay_su_dat = fm_delay,
|
||||||
|
.delay_su_sto = fm_delay,
|
||||||
|
.delay_su_sta = fm_delay,
|
||||||
|
.delay_thigh = fm_delay
|
||||||
|
};
|
||||||
|
|
||||||
|
/* initialise i2c for fmradio */
|
||||||
|
void fmradio_i2c_init(void)
|
||||||
|
{
|
||||||
|
fm_i2c_bus = i2c_add_node(&fm_i2c_interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fmradio_i2c_write(unsigned char address, const unsigned char* buf, int count)
|
||||||
|
{
|
||||||
|
return i2c_write_data(fm_i2c_bus, address, -1, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count)
|
||||||
|
{
|
||||||
|
return i2c_read_data(fm_i2c_bus, address, -1, buf, count);
|
||||||
|
}
|
||||||
|
|
|
@ -49,6 +49,16 @@ const unsigned char lv24020lp_region_data[TUNER_NUM_REGIONS] =
|
||||||
};
|
};
|
||||||
#endif /* (CONFIG_TUNER & LV24020LP) */
|
#endif /* (CONFIG_TUNER & LV24020LP) */
|
||||||
|
|
||||||
|
#if (CONFIG_TUNER & TEA5760)
|
||||||
|
const struct tea5760_region_data tea5760_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 */
|
||||||
|
};
|
||||||
|
#endif /* (CONFIG_TUNER & TEA5760) */
|
||||||
|
|
||||||
#if (CONFIG_TUNER & TEA5767)
|
#if (CONFIG_TUNER & TEA5767)
|
||||||
const struct tea5767_region_data tea5767_region_data[TUNER_NUM_REGIONS] =
|
const struct tea5767_region_data tea5767_region_data[TUNER_NUM_REGIONS] =
|
||||||
{
|
{
|
||||||
|
@ -95,6 +105,12 @@ void tuner_init(void)
|
||||||
lv24020lp_get,
|
lv24020lp_get,
|
||||||
lv24020lp_init())
|
lv24020lp_init())
|
||||||
#endif
|
#endif
|
||||||
|
#if (CONFIG_TUNER & TEA5760)
|
||||||
|
TUNER_TYPE_CASE(TEA5760,
|
||||||
|
tea5760_set,
|
||||||
|
tea5760_get,
|
||||||
|
tea5760_init())
|
||||||
|
#endif
|
||||||
#if (CONFIG_TUNER & TEA5767)
|
#if (CONFIG_TUNER & TEA5767)
|
||||||
TUNER_TYPE_CASE(TEA5767,
|
TUNER_TYPE_CASE(TEA5767,
|
||||||
tea5767_set,
|
tea5767_set,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue