mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 17:02:46 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
11
drivers/media/radio/s610/Kconfig
Executable file
11
drivers/media/radio/s610/Kconfig
Executable file
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# SAMSUNG's S610 FM driver based on SPEEDY driver.
|
||||
#
|
||||
menu "Samsung S610 FM driver (SPEEDY based)"
|
||||
config RADIO_S610
|
||||
tristate "Samsung S610 FM Radio"
|
||||
depends on VIDEO_V4L2 && RADIO_S5E7570
|
||||
help
|
||||
Choose Y here if you have this FM radio chip.
|
||||
|
||||
endmenu
|
9
drivers/media/radio/s610/Makefile
Executable file
9
drivers/media/radio/s610/Makefile
Executable file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Makefile for SAMSUNG Radio driver based s610
|
||||
# FM radio.
|
||||
#
|
||||
obj-$(CONFIG_RADIO_S610) += fm_s5e7570.o
|
||||
fm_s5e7570-objs := radio-s610.o \
|
||||
fm_low.o \
|
||||
fm_ctrl.o \
|
||||
fm_rds.o
|
618
drivers/media/radio/s610/fm_ctrl.c
Executable file
618
drivers/media/radio/s610/fm_ctrl.c
Executable file
|
@ -0,0 +1,618 @@
|
|||
/****************************************************************************
|
||||
Copyright (C) 2015 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include "fm_low_struc.h"
|
||||
#include "radio-s610.h"
|
||||
#include "fm_ctrl.h"
|
||||
|
||||
extern struct s610_radio *gradio;
|
||||
|
||||
void fm_pwron(void)
|
||||
{
|
||||
fmspeedy_set_reg_field(0xFFF226, 0, 0x0001, 1); /* FM reset assert */
|
||||
fmspeedy_set_reg(0xFFF212, 0); /* last power on */
|
||||
fmspeedy_set_reg(0xFFF211, 0); /* first power on */
|
||||
fmspeedy_set_reg_field(0xFFF227, 0, 0x0001, 1); /* FM reset deassert */
|
||||
fmspeedy_set_reg(0xFFF210, 0); /* FM isolaton disable */
|
||||
}
|
||||
|
||||
void fm_pwroff(void)
|
||||
{
|
||||
fmspeedy_set_reg_field(0xFFF226, 0, 0x0001, 1); /* FM reset assert */
|
||||
fmspeedy_set_reg(0xFFF210, 1); /* FM isolaton enable */
|
||||
fmspeedy_set_reg(0xFFF211, 1); /* first power off */
|
||||
fmspeedy_set_reg(0xFFF212, 1); /* last power off */
|
||||
}
|
||||
|
||||
void fmspeedy_wakeup(void)
|
||||
{
|
||||
write32(gradio->fmspeedy_base + FMSPDY_CTL, SPDY_WAKEUP);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
void fm_speedy_m_int_enable(void)
|
||||
{
|
||||
u32 getval;
|
||||
|
||||
getval = read32(gradio->fmspeedy_base + FMSPDY_INTR_MASK);
|
||||
getval &= 0xFFDF;
|
||||
write32(gradio->fmspeedy_base + FMSPDY_INTR_MASK, getval);
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x7F);
|
||||
}
|
||||
|
||||
void fm_speedy_m_int_disable(void)
|
||||
{
|
||||
write32(gradio->fmspeedy_base + FMSPDY_INTR_MASK, 0xFFFF);
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x7F);
|
||||
}
|
||||
|
||||
void fm_en_speedy_m_int(void)
|
||||
{
|
||||
u32 getval;
|
||||
|
||||
getval = read32(gradio->fmspeedy_base + FMSPDY_INTR_MASK);
|
||||
getval &= 0xFFDF;
|
||||
write32(gradio->fmspeedy_base + FMSPDY_INTR_MASK, getval);
|
||||
}
|
||||
|
||||
void fm_dis_speedy_m_int(void)
|
||||
{
|
||||
u32 getval;
|
||||
|
||||
getval = read32(gradio->fmspeedy_base + FMSPDY_INTR_MASK);
|
||||
getval |= 0x0020;
|
||||
write32(gradio->fmspeedy_base + FMSPDY_INTR_MASK, getval);
|
||||
}
|
||||
|
||||
void fm_speedy_m_int_stat_clear(void)
|
||||
{
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
}
|
||||
|
||||
void wait_atomic(void)
|
||||
{
|
||||
while (1) {
|
||||
if (!atomic_read(&gradio->is_doing))
|
||||
break;
|
||||
gradio->wait_atomic++;
|
||||
}
|
||||
}
|
||||
|
||||
u32 fmspeedy_get_reg_core(u32 addr)
|
||||
{
|
||||
u16 ii = 0, jj = 0;
|
||||
u32 status1, status2;
|
||||
u32 retval = 0;
|
||||
|
||||
fm_dis_speedy_m_int();
|
||||
|
||||
for (ii = 0; ii < 5; ii++) {
|
||||
if ((read32(gradio->fmspeedy_base + AUDIO_CTRL)
|
||||
& 0x200000) != 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
status2 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_MISC_STAT);
|
||||
if (((status1 & 0x1F) == 0) &&
|
||||
((status2 & 0x01) == 1))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & 0x1F) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
write32(gradio->fmspeedy_base + FMSPDY_CMD,
|
||||
FMSPDY_READ | FMSPDY_RANDOM
|
||||
| ((addr & 0x01FF) << 7));
|
||||
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base + FMSPDY_STAT);
|
||||
if ((status1 & STAT_DONE) == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
if ((status1 & RX_ALL_ERR) == 0) {
|
||||
fm_en_speedy_m_int();
|
||||
retval = read32(gradio->fmspeedy_base + FMSPDY_DATA);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fm_en_speedy_m_int();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
u32 fmspeedy_get_reg(u32 addr)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
spin_lock_irq(&gradio->slock);
|
||||
|
||||
wait_atomic();
|
||||
atomic_set(&gradio->is_doing, 1);
|
||||
data = fmspeedy_get_reg_core(addr);
|
||||
atomic_set(&gradio->is_doing, 0);
|
||||
|
||||
spin_unlock_irq(&gradio->slock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void fmspeedy_set_reg_core(u32 addr, u32 data)
|
||||
{
|
||||
u16 ii, jj;
|
||||
u32 status1, status2;
|
||||
|
||||
fm_dis_speedy_m_int();
|
||||
|
||||
for (ii = 0; ii < 5; ii++) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_DATA, data);
|
||||
|
||||
if ((read32(gradio->fmspeedy_base + AUDIO_CTRL)
|
||||
& 0x200000) != 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
status2 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_MISC_STAT);
|
||||
if (((status1 & 0x1F) == 0)
|
||||
&& ((status2 & 0x01) == 1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & 0x1F) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
write32(gradio->fmspeedy_base + FMSPDY_CMD,
|
||||
FMSPDY_WRITE | FMSPDY_RANDOM
|
||||
| ((addr & 0x01FF) << 7));
|
||||
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base + FMSPDY_STAT);
|
||||
if ((status1 & STAT_DONE) == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
if ((status1 & RX_ALL_ERR) == 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fm_en_speedy_m_int();
|
||||
|
||||
if (ii > 4)
|
||||
APIEBUG(gradio, "speedy_set_field write fail\n");
|
||||
}
|
||||
|
||||
void fmspeedy_set_reg(u32 addr, u32 data)
|
||||
{
|
||||
spin_lock_irq(&gradio->slock);
|
||||
|
||||
wait_atomic();
|
||||
atomic_set(&gradio->is_doing, 1);
|
||||
fmspeedy_set_reg_core(addr, data);
|
||||
atomic_set(&gradio->is_doing, 0);
|
||||
|
||||
spin_unlock_irq(&gradio->slock);
|
||||
|
||||
}
|
||||
|
||||
u32 fmspeedy_get_reg_field_core(u32 addr, u32 shift, u32 mask)
|
||||
{
|
||||
u16 ii, jj;
|
||||
u32 status1, status2;
|
||||
|
||||
fm_dis_speedy_m_int();
|
||||
|
||||
for (ii = 0; ii < 5; ii++) {
|
||||
if ((read32(gradio->fmspeedy_base
|
||||
+ AUDIO_CTRL) & 0x200000) != 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
status2 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_MISC_STAT);
|
||||
if (((status1 & 0x1F) == 0)
|
||||
&& ((status2 & 0x01) == 1))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & 0x1F) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
write32(gradio->fmspeedy_base + FMSPDY_CMD,
|
||||
FMSPDY_READ | FMSPDY_RANDOM
|
||||
| ((addr & 0x01FF) << 7));
|
||||
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & STAT_DONE) == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
if ((status1 & RX_ALL_ERR) == 0) {
|
||||
fm_en_speedy_m_int();
|
||||
return ((read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_DATA) & (mask))
|
||||
>> shift);
|
||||
}
|
||||
}
|
||||
fm_dis_speedy_m_int();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 fmspeedy_get_reg_field(u32 addr, u32 shift, u32 mask)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
spin_lock_irq(&gradio->slock);
|
||||
|
||||
wait_atomic();
|
||||
atomic_set(&gradio->is_doing, 1);
|
||||
data = fmspeedy_get_reg_field_core(addr, shift, mask);
|
||||
atomic_set(&gradio->is_doing, 0);
|
||||
|
||||
spin_unlock_irq(&gradio->slock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void fmspeedy_set_reg_field_core(u32 addr, u32 shift, u32 mask, u32 data)
|
||||
{
|
||||
u32 value, value1;
|
||||
u16 ii, jj;
|
||||
u32 status1, status2;
|
||||
|
||||
fm_dis_speedy_m_int();
|
||||
|
||||
for (ii = 0; ii < 5; ii++) {
|
||||
if ((read32(gradio->fmspeedy_base
|
||||
+ AUDIO_CTRL) & 0x200000) != 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
status2 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_MISC_STAT);
|
||||
if (((status1 & 0x1F) == 0)
|
||||
&& ((status2 & 0x01) == 1))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & 0x1F) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
write32(gradio->fmspeedy_base + FMSPDY_CMD,
|
||||
FMSPDY_READ | FMSPDY_RANDOM
|
||||
| ((addr & 0x01FF) << 7));
|
||||
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & STAT_DONE) == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
if ((status1 & RX_ALL_ERR) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ii > 4) || (jj > 99)) {
|
||||
fm_en_speedy_m_int();
|
||||
APIEBUG(gradio, "speedy_set_field write fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
value = (read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_DATA) & ~(mask))
|
||||
| ((data) << (shift));
|
||||
|
||||
#else
|
||||
value1 = read32(gradio->fmspeedy_base + FMSPDY_DATA);
|
||||
value = (value1 & ~(mask)) | ((data) << (shift));
|
||||
|
||||
if (addr == 0xFFF2A9)
|
||||
APIEBUG(gradio, "speedy read %x, %x\n", value1, value);
|
||||
|
||||
#endif
|
||||
|
||||
for (ii = 0; ii < 5; ii++) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_DATA, value);
|
||||
|
||||
if ((read32(gradio->fmspeedy_base
|
||||
+ AUDIO_CTRL) & 0x200000) != 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
status2 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_MISC_STAT);
|
||||
if (((status1 & 0x1F) == 0)
|
||||
&& ((status2 & 0x01) == 1))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & 0x1F) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
write32(gradio->fmspeedy_base + FMSPDY_CMD,
|
||||
FMSPDY_WRITE | FMSPDY_RANDOM
|
||||
| ((addr & 0x01FF) << 7));
|
||||
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & STAT_DONE) == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
udelay(10);
|
||||
|
||||
if ((status1 & RX_ALL_ERR) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
fm_en_speedy_m_int();
|
||||
|
||||
if ((ii > 4) || (jj > 99))
|
||||
APIEBUG(gradio, "speedy_set_field write fail\n");
|
||||
}
|
||||
|
||||
void fmspeedy_set_reg_field(u32 addr, u32 shift, u32 mask, u32 data)
|
||||
{
|
||||
spin_lock_irq(&gradio->slock);
|
||||
|
||||
wait_atomic();
|
||||
atomic_set(&gradio->is_doing, 1);
|
||||
fmspeedy_set_reg_field_core(addr, shift, mask, data);
|
||||
atomic_set(&gradio->is_doing, 0);
|
||||
|
||||
spin_unlock_irq(&gradio->slock);
|
||||
|
||||
}
|
||||
|
||||
u32 fmspeedy_get_reg_int_core(u32 addr)
|
||||
{
|
||||
u16 ii = 0, jj = 0;
|
||||
u32 status1, status2;
|
||||
u32 retval = 0;
|
||||
|
||||
for (ii = 0; ii < 5; ii++) {
|
||||
if ((read32(gradio->fmspeedy_base
|
||||
+ AUDIO_CTRL) & 0x200000) != 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
status2 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_MISC_STAT);
|
||||
if (((status1 & 0x1F) == 0)
|
||||
&& ((status2 & 0x01) == 1))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & 0x1F) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
write32(gradio->fmspeedy_base + FMSPDY_CMD,
|
||||
FMSPDY_READ | FMSPDY_RANDOM
|
||||
| ((addr & 0x01FF) << 7));
|
||||
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base + FMSPDY_STAT);
|
||||
if ((status1 & STAT_DONE) == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
if ((status1 & RX_ALL_ERR) == 0) {
|
||||
retval = read32(gradio->fmspeedy_base + FMSPDY_DATA);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
u32 fmspeedy_get_reg_int(u32 addr)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
|
||||
wait_atomic();
|
||||
atomic_set(&gradio->is_doing, 1);
|
||||
data = fmspeedy_get_reg_int_core(addr);
|
||||
atomic_set(&gradio->is_doing, 0);
|
||||
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void fmspeedy_set_reg_int_core(u32 addr, u32 data)
|
||||
{
|
||||
u16 ii, jj;
|
||||
u32 status1, status2;
|
||||
|
||||
for (ii = 0; ii < 5; ii++) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_DATA, data);
|
||||
|
||||
if ((read32(gradio->fmspeedy_base
|
||||
+ AUDIO_CTRL) & 0x200000) != 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
status2 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_MISC_STAT);
|
||||
if (((status1 & 0x1F) == 0)
|
||||
&& ((status2 & 0x01) == 1))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base
|
||||
+ FMSPDY_STAT);
|
||||
if ((status1 & 0x1F) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
write32(gradio->fmspeedy_base + FMSPDY_CMD,
|
||||
FMSPDY_WRITE | FMSPDY_RANDOM
|
||||
| ((addr & 0x01FF) << 7));
|
||||
|
||||
for (jj = 0; jj < 100; jj++) {
|
||||
udelay(2);
|
||||
status1 = read32(gradio->fmspeedy_base + FMSPDY_STAT);
|
||||
if ((status1 & STAT_DONE) == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (jj > 99)
|
||||
break;
|
||||
|
||||
if ((status1 & RX_ALL_ERR) == 0) {
|
||||
write32(gradio->fmspeedy_base + FMSPDY_STAT, 0x1F);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ii > 4)
|
||||
APIEBUG(gradio, "speedy_set retry fail\n");
|
||||
}
|
||||
|
||||
void fmspeedy_set_reg_int(u32 addr, u32 data)
|
||||
{
|
||||
|
||||
wait_atomic();
|
||||
atomic_set(&gradio->is_doing, 1);
|
||||
fmspeedy_set_reg_int_core(addr, data);
|
||||
atomic_set(&gradio->is_doing, 0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
NAME
|
||||
fm_audio_control - Audio out enable/disable
|
||||
|
||||
FUNCTION
|
||||
Setting registers for Audio
|
||||
****************************************************************************/
|
||||
void fm_audio_control(struct s610_radio *radio,
|
||||
bool audio_out, bool lr_switch,
|
||||
u32 req_time, u32 audio_addr)
|
||||
{
|
||||
write32(radio->fmspeedy_base + AUDIO_CTRL,
|
||||
((audio_out << 21) | (lr_switch << 20)
|
||||
| ((req_time & 0x07FF) << 9)
|
||||
| (audio_addr & 0x01FF)));
|
||||
udelay(15);
|
||||
}
|
||||
|
17
drivers/media/radio/s610/fm_ctrl.h
Executable file
17
drivers/media/radio/s610/fm_ctrl.h
Executable file
|
@ -0,0 +1,17 @@
|
|||
void fm_pwron(void);
|
||||
void fm_pwroff(void);
|
||||
void fmspeedy_wakeup(void);
|
||||
void fm_speedy_m_int_enable(void);
|
||||
void fm_speedy_m_int_disable(void);
|
||||
void fm_en_speedy_m_int(void);
|
||||
void fm_dis_speedy_m_int(void);
|
||||
void fm_speedy_m_int_stat_clear(void);
|
||||
u32 fmspeedy_get_reg(u32 addr);
|
||||
void fmspeedy_set_reg(u32 addr, u32 data);
|
||||
u32 fmspeedy_get_reg_field(u32 addr, u32 shift, u32 mask);
|
||||
void fmspeedy_set_reg_field(u32 addr, u32 shift, u32 mask, u32 data);
|
||||
u32 fmspeedy_get_reg_int(u32 addr);
|
||||
void fmspeedy_set_reg_int(u32 addr, u32 data);
|
||||
void fm_audio_control(struct s610_radio *radio, bool audio_out, bool lr_switch,
|
||||
u32 req_time, u32 audio_addr);
|
||||
|
2129
drivers/media/radio/s610/fm_low.c
Executable file
2129
drivers/media/radio/s610/fm_low.c
Executable file
File diff suppressed because it is too large
Load diff
154
drivers/media/radio/s610/fm_low_ref.h
Executable file
154
drivers/media/radio/s610/fm_low_ref.h
Executable file
|
@ -0,0 +1,154 @@
|
|||
#ifndef FM_LOW_REF_H
|
||||
#define FM_LOW_REF_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/******************************************************************************
|
||||
* definition
|
||||
******************************************************************************/
|
||||
#define ABS(a) (((a) < 0) ? -(a) : (a))
|
||||
|
||||
void fm_boot(struct s610_radio *radio);
|
||||
void fm_power_off(void);
|
||||
u16 if_count_device_to_host(struct s610_radio *radio, u16 val);
|
||||
static u16 aggr_rssi_host_to_device(u8 val);
|
||||
u8 aggr_rssi_device_to_host(u16 val);
|
||||
u16 rssi_device_to_host(u16 digi_rssi, u16 agc_gain, u16 rssi_adj);
|
||||
#ifdef USE_SPUR_CANCEL
|
||||
void fm_rx_en_spur_removal(struct s610_radio *radio);
|
||||
void fm_rx_dis_spur_removal(void);
|
||||
void fm_rx_check_spur(struct s610_radio *radio);
|
||||
void fm_rx_check_spur_mono(struct s610_radio *radio);
|
||||
#endif
|
||||
void fm_set_freq(struct s610_radio *radio, u32 freq, bool mix_hi);
|
||||
void fm_set_mute(bool mute);
|
||||
void fm_set_blend_mute(struct s610_radio *radio);
|
||||
static void fm_rds_flush_buffers(struct s610_radio *radio,
|
||||
bool clear_buffer);
|
||||
void fm_rds_enable(struct s610_radio *radio);
|
||||
void fm_rds_disable(struct s610_radio *radio);
|
||||
bool fm_radio_on(struct s610_radio *radio);
|
||||
void fm_radio_off(struct s610_radio *radio);
|
||||
void fm_rds_on(struct s610_radio *radio);
|
||||
void fm_rds_off(struct s610_radio *radio);
|
||||
void fm_initialize(struct s610_radio *radio);
|
||||
u16 fm_get_flags(struct s610_radio *radio);
|
||||
void fm_set_flags(struct s610_radio *radio, u16 flags);
|
||||
void fm_set_handler_if_count(void (*fn)(struct s610_radio *radio));
|
||||
void fm_set_handler_audio_pause(void (*fn)(struct s610_radio *radio));
|
||||
void fm_update_if_count(struct s610_radio *radio);
|
||||
void fm_update_if_count_int(struct s610_radio *radio);
|
||||
void fm_update_rssi(struct s610_radio *radio);
|
||||
void fm_update_snr(struct s610_radio *radio);
|
||||
void fm_update_sig_info(struct s610_radio *radio);
|
||||
void fm_update_rds_sync_status(struct s610_radio *radio,
|
||||
bool synced);
|
||||
u16 fm_update_rx_status(struct s610_radio *radio, u16 d_status);
|
||||
void fm_update_tuner_mode(struct s610_radio *radio);
|
||||
bool fm_check_rssi_level(u16 limit);
|
||||
int fm_host_read_rds_data(
|
||||
struct s610_radio *radio, u16 *num_of_block, u8 *rds_data);
|
||||
int low_get_search_lvl(struct s610_radio *radio, u16 *value);
|
||||
int low_set_if_limit(struct s610_radio *radio, u16 value);
|
||||
int low_set_search_lvl(struct s610_radio *radio, u16 value);
|
||||
int low_set_freq(struct s610_radio *radio, u32 value);
|
||||
int low_set_tuner_mode(struct s610_radio *radio, u16 value);
|
||||
int low_set_mute_state(struct s610_radio *radio, u16 value);
|
||||
int low_set_most_mode(struct s610_radio *radio, u16 value);
|
||||
int low_set_most_blend(struct s610_radio *radio, u16 value);
|
||||
int low_set_pause_lvl(struct s610_radio *radio, u16 value);
|
||||
int low_set_pause_dur(struct s610_radio *radio, u16 value);
|
||||
int low_set_demph_mode(struct s610_radio *radio, u16 value);
|
||||
int low_set_rds_cntr(struct s610_radio *radio, u16 value);
|
||||
int low_set_power(struct s610_radio *radio, u16 value);
|
||||
|
||||
void fm_set_interrupt_source(u16 sources, bool enable);
|
||||
void fm_isr(struct s610_radio *radio);
|
||||
void fm_rx_ana_start(void);
|
||||
void fm_rx_ana_stop(void);
|
||||
void fm_setup_iq_imbalance(void);
|
||||
void fm_rx_init(void);
|
||||
|
||||
void fm_lo_off(void);
|
||||
void fm_lo_prepare_setup(struct s610_radio *radio);
|
||||
void fm_lo_set(const struct_fm_lo_setup lo_set);
|
||||
void fm_lo_initialize(struct s610_radio *radio);
|
||||
void fm_sx_reset(void);
|
||||
void fm_sx_start(void);
|
||||
bool fm_aux_pll_initialize(void);
|
||||
void fm_aux_pll_off(void);
|
||||
void fm_set_band(struct s610_radio *radio, u8 index);
|
||||
void fm_set_freq_step(struct s610_radio *radio, u8 index);
|
||||
bool fm_band_trim(struct s610_radio *radio, u32 *freq);
|
||||
void fm_get_if_filter_config(struct s610_radio *radio);
|
||||
static bool fm_tuner_push_freq(struct s610_radio *radio,
|
||||
bool down);
|
||||
static void fm_tuner_enable_rds(struct s610_radio *radio,
|
||||
bool enable);
|
||||
void fm_set_rssi_thresh(struct s610_radio *radio,
|
||||
fm_tuner_state state);
|
||||
static void fm_tuner_control_mute(struct s610_radio *radio);
|
||||
void fm_tuner_set_force_mute(struct s610_radio *radio, bool mute);
|
||||
void fm_tuner_set_mute_audio(struct s610_radio *radio, bool mute);
|
||||
#ifdef MONO_SWITCH_INTERF
|
||||
void fm_check_interferer(struct s610_radio *radio);
|
||||
void fm_reset_force_mono_interf(struct s610_radio *radio);
|
||||
#endif
|
||||
void fm_timer_reset(fm_timer_t *timer, int usec,
|
||||
fm_callback_t *func, void *arg);
|
||||
void fm_start_if_counter(void);
|
||||
static void fm_preset_tuned(struct s610_radio *radio);
|
||||
static void fm_search_done(struct s610_radio *radio, u16 flags);
|
||||
static void fm_search_check_signal2(unsigned long data);
|
||||
static void fm_search_check_signal1(struct s610_radio *radio, bool rssi_oor);
|
||||
static void fm_search_tuned(unsigned long data);
|
||||
static void fm_start_tune(struct s610_radio *radio,
|
||||
fm_tuner_state new_state);
|
||||
static void fm_tuner_change_state(struct s610_radio *radio,
|
||||
fm_tuner_state new_state);
|
||||
void cancel_tuner_timer(struct s610_radio *radio);
|
||||
static void fm_tuner_exit_state(struct s610_radio *radio);
|
||||
void fm_set_tuner_mode(struct s610_radio *radio);
|
||||
static bool fm_tuner_on(struct s610_radio *radio);
|
||||
static void fm_tuner_off(struct s610_radio *radio);
|
||||
void fm_tuner_rds_on(struct s610_radio *radio);
|
||||
void fm_tuner_rds_off(struct s610_radio *radio);
|
||||
bool fm_tuner_set_power_state(struct s610_radio *radio,
|
||||
bool fm_on, bool rds_on);
|
||||
int init_low_struc(struct s610_radio *radio);
|
||||
|
||||
#ifdef ENABLE_RDS_WORK_QUEUE
|
||||
void s610_rds_work(struct work_struct *work);
|
||||
#endif /*ENABLE_RDS_WORK_QUEUE*/
|
||||
#ifdef ENABLE_IF_WORK_QUEUE
|
||||
void s610_if_work(struct work_struct *work);
|
||||
#endif /*ENABLE_RDS_WORK_QUEUE*/
|
||||
|
||||
void s610_sig2_work(struct work_struct *work);
|
||||
void s610_tune_work(struct work_struct *work);
|
||||
|
||||
#ifdef VOLUME_CTRL_S610
|
||||
void fm_set_audio_gain(struct s610_radio *radio, u16 gain);
|
||||
#endif /*VOLUME_CTRL_S610*/
|
||||
|
||||
extern void fmspeedy_wakeup(void);
|
||||
extern void fm_pwron(void);
|
||||
extern void fm_pwroff(void);
|
||||
extern void fmspeedy_set_reg_field(
|
||||
u32 addr, u32 shift, u32 mask, u32 data);
|
||||
extern void fmspeedy_set_reg(u32 addr, u32 data);
|
||||
extern u32 fmspeedy_get_reg(u32 addr);
|
||||
extern u32 fmspeedy_get_reg_int(u32 addr);
|
||||
extern void fmspeedy_set_reg_int(u32 addr, u32 data);
|
||||
extern u32 fmspeedy_get_reg_field(u32 addr, u32 shift, u32 mask);
|
||||
extern void fm_audio_control(struct s610_radio *radio,
|
||||
bool audio_out, bool lr_switch,
|
||||
u32 req_time, u32 audio_addr);
|
||||
extern bool fm_read_rds_data(struct s610_radio *radio,
|
||||
u16 *buffer, u16 *size, u16 *blocks);
|
||||
extern void fm_process_rds_data(struct s610_radio *radio);
|
||||
extern int read_fm_speedy_m(struct s610_radio *radio);
|
||||
#endif /*FM_LOW_REF_H*/
|
426
drivers/media/radio/s610/fm_low_struc.h
Executable file
426
drivers/media/radio/s610/fm_low_struc.h
Executable file
|
@ -0,0 +1,426 @@
|
|||
#ifndef FM_LOW_STRUC_H
|
||||
#define FM_LOW_STRUC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define EVT0 (0)
|
||||
#define EVT1 (1)
|
||||
#define S610_VER (EVT1)
|
||||
|
||||
#define USE_SPUR_CANCEL
|
||||
#define TC_ON_FREQ_NUM 4
|
||||
|
||||
#define USE_FILTER_SELECT_BY_FREQ
|
||||
#define MAX_FILTER_FREQ_NUM 6
|
||||
|
||||
#define USE_NEW_SCAN
|
||||
#define VOLUME_CTRL_S610
|
||||
/*#undef VOLUME_CTRL_S610*/
|
||||
|
||||
#define FM_LOW_DRV_DELAY_MS 1
|
||||
#define AGGR_RSSI_OFFSET (-114)
|
||||
|
||||
#undef TRUE
|
||||
#define TRUE (1)
|
||||
|
||||
#undef FALSE
|
||||
#define FALSE (0)
|
||||
|
||||
typedef u32 TIME;
|
||||
|
||||
/* TIME constants. */
|
||||
|
||||
#define SECOND HZ
|
||||
#define IDLE_TIME_MS (500)
|
||||
#define TUNE_TIME_FAST_MS (30)
|
||||
#define TUNE_TIME_SLOW_MS (60)
|
||||
#ifdef USE_NEW_SCAN
|
||||
#define SEARCH_DELAY_MS (20)
|
||||
#else
|
||||
#define SEARCH_DELAY_MS (15)
|
||||
#endif
|
||||
|
||||
#define FM_RDS_MEM_SIZE 480
|
||||
|
||||
#ifdef USE_SPUR_CANCEL
|
||||
#define EN_SPUR_REMOVAL (0x0001)
|
||||
#define DIS_SPUR_REMOVAL_MONO (0x0002)
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* DEFINITIONS AND MACROS
|
||||
******************************************************************************/
|
||||
/* == FM SPEEDY registers == */
|
||||
#define FM_SPEEDY_MA_BASE (0x14840000)
|
||||
#define FMSPDY_CTL (0x00000000)
|
||||
#define FMSPDY_STAT (0x00000004)
|
||||
#define FMSPDY_DISR (0x00000008)
|
||||
#define FMSPDY_INTR_MASK (0x0000000C)
|
||||
#define FMSPDY_DATA (0x00000010)
|
||||
#define FMSPDY_CMD (0x00000014)
|
||||
#define FMSPDY_ERR_CNT (0x00000018)
|
||||
#define FMSPDY_MISC_STAT (0x0000001C)
|
||||
#define FMSPDY_PRAMS (0x00000020)
|
||||
#define FM_SLV_INT (0x00000040)
|
||||
#define AUDIO_CTRL (0x00000024)
|
||||
#define AUDIO_FIFO (0x00000028)
|
||||
#define FM_SPEEDY_MA_SIZE 1024
|
||||
|
||||
/* FMSPDY Control Register Flags */
|
||||
#define SPDY_WAKEUP (1<<23)
|
||||
|
||||
/* FMSPDY Status Register Flags*/
|
||||
#define RX_FMT_ERR (1<<4)
|
||||
#define RX_NO_STOP (1<<3)
|
||||
#define RX_GLITCHED (1<<2)
|
||||
#define RX_TIMEOUT (1<<1)
|
||||
#define RX_ALL_ERR (RX_FMT_ERR|RX_NO_STOP|RX_GLITCHED|RX_TIMEOUT)
|
||||
#define STAT_DONE (1<<0)
|
||||
|
||||
/* FMSPDY Command Register Flags*/
|
||||
#define FMSPDY_READ (0<<17)
|
||||
#define FMSPDY_WRITE (1<<17)
|
||||
#define FMSPDY_RANDOM (1<<16)
|
||||
|
||||
#define write32(addr, data) __raw_writel(data, addr)
|
||||
#define read32(addr) __raw_readl((volatile void __iomem *)addr)
|
||||
#define SetBits(uAddr, uBaseBit, uMaskValue, uSetValue) \
|
||||
write32(uAddr, (read32(uAddr) & ~((uMaskValue)<<(uBaseBit))) | \
|
||||
(((uMaskValue)&(uSetValue))<<(uBaseBit)))
|
||||
#define GetBits(uAddr, uBaseBit, uMaskValue) \
|
||||
((read32(uAddr)>>(uBaseBit))&(uMaskValue))
|
||||
|
||||
|
||||
enum flags_enum {
|
||||
FLAG_TUNED = (1 << 0),
|
||||
FLAG_BD_LMT = (1 << 1),
|
||||
FLAG_SYN_LOS = (1 << 2),
|
||||
FLAG_BUF_FUL = (1 << 3),
|
||||
FLAG_AUD_PAU = (1 << 4),
|
||||
FLAG_CH_STAT = (1 << 5)
|
||||
};
|
||||
|
||||
enum fm_status_mask_enum {
|
||||
STATUS_MASK_RDS_AVA = (1 << 0),
|
||||
STATUS_MASK_STEREO = (1 << 1)
|
||||
};
|
||||
|
||||
enum fm_search_dir_mask_enum {
|
||||
SEARCH_DIR_MASK = (1 << 0)
|
||||
};
|
||||
|
||||
enum fm_tuner_mode_mask_enum {
|
||||
TUNER_MODE_MASK_TUN_MOD = (7 << 0),
|
||||
TUNER_MODE_MASK_NEXT = (1 << 3)
|
||||
};
|
||||
|
||||
enum fm_tuner_mode_enum {
|
||||
TUNER_MODE_NONE = 0,
|
||||
TUNER_MODE_PRESET = 1,
|
||||
TUNER_MODE_SEARCH = 2
|
||||
};
|
||||
|
||||
enum fm_mute_state_mask_enum {
|
||||
MUTE_STATE_MASK_SOFT = (1 << 0),
|
||||
MUTE_STATE_MASK_HARD = (1 << 1)
|
||||
};
|
||||
|
||||
enum fm_output_mode_mask_enum {
|
||||
MODE_MASK_MONO_STEREO = (1 << 0)
|
||||
};
|
||||
|
||||
enum fm_blend_mode_mask_enum {
|
||||
MODE_MASK_BLEND = (1 << 0)
|
||||
};
|
||||
|
||||
enum fm_rds_ctrl_mask_enum {
|
||||
RDS_CTRL_MASK_FLUSH = (1 << 0),
|
||||
RDS_CTRL_MASK_RESYNC = (1 << 1)
|
||||
};
|
||||
|
||||
enum fm_rds_system_mask_enum {
|
||||
RDS_SYSTEM_MASK_RDS = (1 << 0),
|
||||
RDS_SYSTEM_MASK_EBLK = (1 << 1)
|
||||
};
|
||||
|
||||
enum fm_power_mask_enum {
|
||||
PWR_MASK_FM = (1 << 0),
|
||||
PWR_MASK_RDS = (1 << 1)
|
||||
};
|
||||
|
||||
enum fm_deemph_mode_mask_enum {
|
||||
MODE_MASK_DEEMPH = (1 << 0)
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
HOST_RDS_ERRS_NONE = 0,
|
||||
HOST_RDS_ERRS_2CORR = 1,
|
||||
HOST_RDS_ERRS_5CORR = 2,
|
||||
HOST_RDS_ERRS_UNCORR = 3
|
||||
} fm_host_rds_errors_enum;
|
||||
|
||||
#define RDS_MEM_MAX_THRESH (48)
|
||||
|
||||
enum fm_host_rds_data_enum {
|
||||
HOST_RDS_DATA_BLKTYPE_POSI = 0,
|
||||
HOST_RDS_DATA_ERRORS_POSI = 3,
|
||||
HOST_RDS_DATA_AVAIL_MASK = (1 << 5)
|
||||
};
|
||||
|
||||
#define HOST_RDS_BLOCK_SIZE 3
|
||||
#define HOST_RDS_BLOCK_FMT_LSB 0
|
||||
#define HOST_RDS_BLOCK_FMT_MSB 1
|
||||
#define HOST_RDS_BLOCK_FMT_STATUS 2
|
||||
|
||||
enum fm_demod_stat_mask_enum {
|
||||
FM_DEMOD_BLEND_STEREO_MASK = (0x0001 << 4),
|
||||
FM_DEMOD_IF_OOR_MASK = (0x0001 << 7)
|
||||
};
|
||||
|
||||
enum fm_int_src_mask_enum {
|
||||
INT_IFC_READY_MASK = (0x0001 << 0),
|
||||
INT_AUDIO_PAU_MASK = (0x0001 << 3),
|
||||
INT_RDS_BYTES_MASK = (0x0001 << 4),
|
||||
};
|
||||
|
||||
#ifdef VOLUME_CTRL_S610
|
||||
enum fm_audio_gain_enum {
|
||||
AUDIO_ATTENUATION_Max = 0,
|
||||
AUDIO_ATTENUATION_42dB = 1,
|
||||
AUDIO_ATTENUATION_39dB = 2,
|
||||
AUDIO_ATTENUATION_36dB = 3,
|
||||
AUDIO_ATTENUATION_33dB = 4,
|
||||
AUDIO_ATTENUATION_30dB = 5,
|
||||
AUDIO_ATTENUATION_27dB = 6,
|
||||
AUDIO_ATTENUATION_24dB = 7,
|
||||
AUDIO_ATTENUATION_21dB = 8,
|
||||
AUDIO_ATTENUATION_18dB = 9,
|
||||
AUDIO_ATTENUATION_15dB = 10,
|
||||
AUDIO_ATTENUATION_12dB = 11,
|
||||
AUDIO_ATTENUATION_9dB = 12,
|
||||
AUDIO_ATTENUATION_6dB = 13,
|
||||
AUDIO_ATTENUATION_3dB = 14,
|
||||
AUDIO_ATTENUATION_0dB = 15
|
||||
};
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
u16 muffle_coeffs;
|
||||
u16 lpf_en;
|
||||
u16 lpf_auto;
|
||||
u16 lpf_bw;
|
||||
} soft_muffle_conf;
|
||||
|
||||
typedef struct {
|
||||
#ifdef USE_NEW_SCAN
|
||||
u16 weak_ifca_l;
|
||||
u16 weak_ifca_m;
|
||||
u16 weak_ifca_h;
|
||||
u16 normal_ifca_l;
|
||||
u16 normal_ifca_m;
|
||||
u16 normal_ifca_h;
|
||||
bool weak_sig;
|
||||
#else
|
||||
u16 ifca_l;
|
||||
u16 ifca_m;
|
||||
u16 ifca_h;
|
||||
#endif
|
||||
} search_config;
|
||||
|
||||
#ifdef MONO_SWITCH_INTERF
|
||||
typedef struct {
|
||||
s16 lo;
|
||||
s16 hi;
|
||||
} interf_rssi_thres;
|
||||
|
||||
typedef struct {
|
||||
u16 lo;
|
||||
u16 hi;
|
||||
} interf_snr_thres;
|
||||
#endif /* MONO_SWITCH_INTERF */
|
||||
|
||||
typedef struct {
|
||||
u16 demod_conf_ini;
|
||||
u16 rssi_adj_ini;
|
||||
soft_muffle_conf soft_muffle_conf_ini;
|
||||
u16 soft_mute_atten_max_ini;
|
||||
u16 stereo_thres_ini;
|
||||
u16 narrow_thres_ini;
|
||||
u16 snr_adj_ini;
|
||||
u16 snr_smooth_conf_ini;
|
||||
u16 mute_coeffs_soft;
|
||||
u16 mute_coeffs_dis;
|
||||
u16 blend_coeffs_soft;
|
||||
u16 blend_coeffs_switch;
|
||||
u16 blend_coeffs_dis;
|
||||
u16 rds_int_byte_count;
|
||||
search_config search_conf;
|
||||
#ifdef MONO_SWITCH_INTERF
|
||||
interf_rssi_thres interf_rssi;
|
||||
interf_snr_thres interf_snr;
|
||||
#endif
|
||||
u16 rds_error_limit;
|
||||
} fm_conf_ini_values;
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
bool rds_rx_enabled;
|
||||
bool fm_pwr_on;
|
||||
bool rds_pwr_on;
|
||||
bool force_mono;
|
||||
bool use_switched_blend;
|
||||
bool use_soft_mute;
|
||||
bool mute_forced;
|
||||
bool mute_audio;
|
||||
bool search_down;
|
||||
bool use_rbds;
|
||||
bool save_eblks;
|
||||
bool last_status_blend_stereo;
|
||||
bool last_status_rds_sync;
|
||||
#ifdef MONO_SWITCH_INTERF
|
||||
bool force_mono_interf;
|
||||
bool interf_checked;
|
||||
bool mono_switched_interf;
|
||||
TIME mono_interf_reset_time;
|
||||
#endif /* MONO_SWITCH_INTERF */
|
||||
u8 tuner_mode;
|
||||
u8 status;
|
||||
u8 rds_mem_thresh;
|
||||
u8 rssi;
|
||||
u8 band;
|
||||
u16 last_ifc;
|
||||
u16 snr;
|
||||
u16 rssi_limit_normal;
|
||||
u16 rssi_limit_search;
|
||||
u32 freq;
|
||||
u16 flags;
|
||||
u8 rds_unsync_uncorr_weight;
|
||||
u8 rds_unsync_blk_cnt;
|
||||
u16 rds_unsync_bit_cnt;
|
||||
} fm_state_s;
|
||||
|
||||
typedef enum {
|
||||
TUNER_OFF,
|
||||
TUNER_NOTTUNED,
|
||||
TUNER_IDLE,
|
||||
TUNER_PRESET,
|
||||
TUNER_SEARCH
|
||||
} fm_tuner_state;
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
fm_tuner_state tuner_state;
|
||||
bool curr_search_down;
|
||||
bool hit_band_limit;
|
||||
bool tune_done;
|
||||
u16 freq_step;
|
||||
u32 band_limit_lo;
|
||||
u32 band_limit_hi;
|
||||
} fm_tuner_state_s;
|
||||
|
||||
typedef enum {
|
||||
RDS_BLKTYPE_A = 0,
|
||||
RDS_BLKTYPE_B = 1,
|
||||
RDS_BLKTYPE_C = 2,
|
||||
RDS_BLKTYPE_C2 = 3,
|
||||
RDS_BLKTYPE_D = 4,
|
||||
RDS_BLKTYPE_E = 5,
|
||||
RDS_NUM_BLOCK_TYPES = 6
|
||||
} fm_rds_block_type_enum;
|
||||
|
||||
typedef enum {
|
||||
RDS_STATE_INIT,
|
||||
RDS_STATE_HAVE_DATA,
|
||||
RDS_STATE_PRE_SYNC,
|
||||
RDS_STATE_FULL_SYNC
|
||||
} fm_rds_state_enum;
|
||||
|
||||
typedef struct {
|
||||
unsigned current_state :3;
|
||||
u16 error_bits;
|
||||
u8 error_blks;
|
||||
} fm_rds_state_s;
|
||||
|
||||
typedef struct rds_buf_conf {
|
||||
u8 *base;
|
||||
u16 index;
|
||||
u16 outdex;
|
||||
u16 size;
|
||||
} rds_buf_conf;
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
typedef struct struct_fm_rx_setup {
|
||||
u32 fm_freq_hz;
|
||||
u32 fm_freq_khz;
|
||||
u16 demod_if;
|
||||
s16 lna_cdac;
|
||||
u16 spur_ctrl;
|
||||
s16 spur_freq;
|
||||
} struct_fm_rx_setup;
|
||||
|
||||
typedef struct struct_fm_lo_setup {
|
||||
u32 rx_lo_req_freq;
|
||||
u32 n_mmdiv;
|
||||
u32 frac_b1;
|
||||
u32 frac_b0;
|
||||
u32 n_lodiv;
|
||||
} struct_fm_lo_setup;
|
||||
|
||||
typedef struct struct_fm_rx_tune_info {
|
||||
struct_fm_rx_setup rx_setup;
|
||||
struct_fm_lo_setup lo_setup;
|
||||
} struct_fm_rx_tune_info;
|
||||
|
||||
/**********************************************/
|
||||
/* FM low struct
|
||||
**********************************************/
|
||||
typedef struct {
|
||||
u32 lo;
|
||||
u32 hi;
|
||||
} fm_band_s;
|
||||
|
||||
struct s610_low {
|
||||
/* fm low level struct - start */
|
||||
fm_conf_ini_values fm_config;
|
||||
fm_state_s fm_state;
|
||||
fm_tuner_state_s fm_tuner_state;
|
||||
fm_rds_state_s fm_rds_state;
|
||||
|
||||
u8 *rds_buffer_mem;
|
||||
rds_buf_conf rds_buffer_config;
|
||||
rds_buf_conf *rds_buffer;
|
||||
|
||||
struct_fm_rx_tune_info fm_tune_info;
|
||||
|
||||
fm_band_s fm_bands[2];
|
||||
|
||||
u16 fm_freq_steps[3];
|
||||
|
||||
#ifdef USE_SPUR_CANCEL
|
||||
u32 fm_spur[TC_ON_FREQ_NUM];
|
||||
#endif
|
||||
/* fm low level struct - end */
|
||||
};
|
||||
|
||||
typedef void fm_callback_t(unsigned long);
|
||||
typedef struct timer_list fm_timer_t;
|
||||
typedef void fm_linux_callback_t(u_long);
|
||||
|
||||
#define fm_set_flag_bits(radio, value) \
|
||||
fm_set_flags(radio, radio->low->fm_state.flags | (value))
|
||||
#define fm_clear_flag_bits(radio, value) \
|
||||
fm_set_flags(radio, radio->low->fm_state.flags & ~(value))
|
||||
#define fm_get_band(radio) (radio->low->fm_state.band)
|
||||
#define fm_get_freq_step(radio) (radio->low->fm_tuner_state.freq_step)
|
||||
|
||||
|
||||
#endif /*FM_LOW_STRUC_H*/
|
277
drivers/media/radio/s610/fm_rds.c
Executable file
277
drivers/media/radio/s610/fm_rds.c
Executable file
|
@ -0,0 +1,277 @@
|
|||
|
||||
#include "fm_low_struc.h"
|
||||
#include "radio-s610.h"
|
||||
#include "fm_rds.h"
|
||||
|
||||
void fm_rds_write_data(struct s610_radio *radio, u16 rds_data,
|
||||
fm_rds_block_type_enum blk_type, fm_host_rds_errors_enum errors)
|
||||
{
|
||||
u8 *buf_ptr;
|
||||
u16 usage;
|
||||
u16 capa;
|
||||
|
||||
/* API_ENTRY(radio);*/
|
||||
|
||||
capa = radio->low->rds_buffer->size;
|
||||
if (radio->low->rds_buffer->outdex
|
||||
> radio->low->rds_buffer->index)
|
||||
usage = radio->low->rds_buffer->size
|
||||
- radio->low->rds_buffer->outdex
|
||||
+ radio->low->rds_buffer->index;
|
||||
else
|
||||
usage = radio->low->rds_buffer->index
|
||||
- radio->low->rds_buffer->outdex;
|
||||
|
||||
if ((capa - usage) >= (HOST_RDS_BLOCK_SIZE * 4)) {
|
||||
buf_ptr = radio->low->rds_buffer->base
|
||||
+ radio->low->rds_buffer->index;
|
||||
|
||||
buf_ptr[HOST_RDS_BLOCK_FMT_LSB] = (u8)(rds_data & 0xff);
|
||||
buf_ptr[HOST_RDS_BLOCK_FMT_MSB] = (u8) (rds_data >> 8);
|
||||
|
||||
buf_ptr[HOST_RDS_BLOCK_FMT_STATUS] = (blk_type
|
||||
<< HOST_RDS_DATA_BLKTYPE_POSI)
|
||||
| (errors << HOST_RDS_DATA_ERRORS_POSI)
|
||||
| HOST_RDS_DATA_AVAIL_MASK;
|
||||
|
||||
/* Advances the buffer's index */
|
||||
radio->low->rds_buffer->index
|
||||
+= HOST_RDS_BLOCK_SIZE;
|
||||
|
||||
/* Check if the buffer's index wraps */
|
||||
if (radio->low->rds_buffer->index >=
|
||||
radio->low->rds_buffer->size) {
|
||||
radio->low->rds_buffer->index -=
|
||||
radio->low->rds_buffer->size;
|
||||
}
|
||||
|
||||
if (usage >= HOST_RDS_BLOCK_SIZE)
|
||||
radio->low->fm_state.status |= STATUS_MASK_RDS_AVA;
|
||||
|
||||
}
|
||||
|
||||
if (radio->low->fm_state.rds_mem_thresh != 0) {
|
||||
if (usage
|
||||
>= (radio->low->fm_state.rds_mem_thresh
|
||||
* HOST_RDS_BLOCK_SIZE)) {
|
||||
fm_set_flag_bits(radio, FLAG_BUF_FUL);
|
||||
radio->rds_cnt_mod++;
|
||||
if (!(radio->rds_cnt_mod % 100))
|
||||
APIEBUG(radio, ">N ");
|
||||
|
||||
radio->rds_n_count++;
|
||||
radio->rds_new = TRUE;
|
||||
atomic_set(&radio->is_rds_new, 1);
|
||||
wake_up_interruptible(&radio->core->rds_read_queue);
|
||||
}
|
||||
}
|
||||
|
||||
/* API_EXIT(radio);*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
u16 fm_rds_get_avail_bytes(struct s610_radio *radio)
|
||||
{
|
||||
u16 avail_bytes;
|
||||
|
||||
if (radio->low->rds_buffer->outdex >
|
||||
radio->low->rds_buffer->index)
|
||||
avail_bytes = (radio->low->rds_buffer->size
|
||||
- radio->low->rds_buffer->outdex
|
||||
+ radio->low->rds_buffer->index);
|
||||
else
|
||||
avail_bytes = (radio->low->rds_buffer->index
|
||||
- radio->low->rds_buffer->outdex);
|
||||
|
||||
return avail_bytes;
|
||||
}
|
||||
|
||||
|
||||
bool fm_read_rds_data(struct s610_radio *radio, u16 *buffer,
|
||||
u16 *size, u16 *blocks)
|
||||
{
|
||||
u16 avail_bytes;
|
||||
s16 avail_blocks;
|
||||
s16 orig_avail;
|
||||
u8 *buf_ptr;
|
||||
|
||||
if (radio->low->rds_buffer == NULL) {
|
||||
*size = 0;
|
||||
if (blocks)
|
||||
*blocks = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
orig_avail = avail_bytes = fm_rds_get_avail_bytes(radio);
|
||||
|
||||
if (avail_bytes > *size)
|
||||
avail_bytes = *size;
|
||||
|
||||
avail_blocks = avail_bytes / HOST_RDS_BLOCK_SIZE;
|
||||
avail_bytes = avail_blocks * HOST_RDS_BLOCK_SIZE;
|
||||
|
||||
if (avail_bytes == 0) {
|
||||
*size = 0;
|
||||
if (blocks)
|
||||
*blocks = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
buf_ptr = radio->low->rds_buffer->base
|
||||
+ radio->low->rds_buffer->outdex;
|
||||
(void) memcpy(buffer, buf_ptr, avail_bytes);
|
||||
|
||||
/* advances the buffer's outdex */
|
||||
radio->low->rds_buffer->outdex += avail_bytes;
|
||||
|
||||
/* Check if the buffer's outdex wraps */
|
||||
if (radio->low->rds_buffer->outdex >= radio->low->rds_buffer->size)
|
||||
radio->low->rds_buffer->outdex -= radio->low->rds_buffer->size;
|
||||
|
||||
if (orig_avail == avail_bytes) {
|
||||
buffer[(avail_blocks - 1) * HOST_RDS_BLOCK_SIZE
|
||||
+ HOST_RDS_BLOCK_FMT_STATUS] &=
|
||||
~HOST_RDS_DATA_AVAIL_MASK;
|
||||
radio->low->fm_state.status &= ~STATUS_MASK_RDS_AVA;
|
||||
}
|
||||
|
||||
*size = avail_bytes; /* number of bytes read */
|
||||
|
||||
if (blocks)
|
||||
*blocks = avail_bytes / HOST_RDS_BLOCK_SIZE;
|
||||
|
||||
/* Update RDS flags */
|
||||
if ((avail_bytes / HOST_RDS_BLOCK_SIZE)
|
||||
< radio->low->fm_state.rds_mem_thresh)
|
||||
fm_clear_flag_bits(radio, FLAG_BUF_FUL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void fm_rds_change_state(struct s610_radio *radio,
|
||||
fm_rds_state_enum new_state)
|
||||
{
|
||||
fm_rds_state_enum old_state =
|
||||
(fm_rds_state_enum) radio->low->fm_rds_state.current_state;
|
||||
|
||||
radio->low->fm_rds_state.current_state = new_state;
|
||||
|
||||
if ((old_state == RDS_STATE_FULL_SYNC)
|
||||
&& (new_state == RDS_STATE_HAVE_DATA)) {
|
||||
fm_update_rds_sync_status(radio, FALSE); /* unsynced */
|
||||
} else if ((old_state != RDS_STATE_FULL_SYNC)
|
||||
&& (new_state == RDS_STATE_FULL_SYNC)) {
|
||||
fm_update_rds_sync_status(radio, TRUE); /* synced */
|
||||
}
|
||||
}
|
||||
|
||||
void fm_rds_update_error_status(struct s610_radio *radio, u16 errors)
|
||||
{
|
||||
if (errors == 0) {
|
||||
radio->low->fm_rds_state.error_bits = 0;
|
||||
radio->low->fm_rds_state.error_blks = 0;
|
||||
} else {
|
||||
radio->low->fm_rds_state.error_bits += errors;
|
||||
radio->low->fm_rds_state.error_blks++;
|
||||
}
|
||||
|
||||
if (radio->low->fm_rds_state.error_blks
|
||||
>= radio->low->fm_state.rds_unsync_blk_cnt) {
|
||||
if (radio->low->fm_rds_state.error_bits
|
||||
>= radio->low->fm_state.rds_unsync_bit_cnt) {
|
||||
/* sync-loss */
|
||||
fm_rds_change_state(radio, RDS_STATE_HAVE_DATA);
|
||||
}
|
||||
radio->low->fm_rds_state.error_bits = 0;
|
||||
radio->low->fm_rds_state.error_blks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static fm_host_rds_errors_enum fm_rds_process_block(
|
||||
struct s610_radio *radio,
|
||||
u16 data, fm_rds_block_type_enum block_type,
|
||||
u16 err_count)
|
||||
{
|
||||
fm_host_rds_errors_enum error_type;
|
||||
|
||||
if (err_count == 0) {
|
||||
error_type = HOST_RDS_ERRS_NONE;
|
||||
} else if ((err_count <= 2)
|
||||
&& (err_count
|
||||
<= radio->low->fm_config.rds_error_limit)) {
|
||||
error_type = HOST_RDS_ERRS_2CORR;
|
||||
} else if ((err_count <= 5)
|
||||
&& (err_count
|
||||
<= radio->low->fm_config.rds_error_limit)) {
|
||||
error_type = HOST_RDS_ERRS_5CORR;
|
||||
} else {
|
||||
error_type = HOST_RDS_ERRS_UNCORR;
|
||||
}
|
||||
|
||||
/* Write the data into the buffer */
|
||||
if ((block_type != RDS_BLKTYPE_E)
|
||||
|| (radio->low->fm_state.save_eblks)) {
|
||||
fm_rds_write_data(radio, data, block_type, error_type);
|
||||
}
|
||||
|
||||
return error_type;
|
||||
}
|
||||
|
||||
void fm_process_rds_data(struct s610_radio *radio)
|
||||
{
|
||||
u32 fifo_data;
|
||||
u16 i;
|
||||
u16 avail_blocks;
|
||||
u16 data;
|
||||
u8 status;
|
||||
u16 err_count;
|
||||
fm_rds_block_type_enum block_type;
|
||||
|
||||
if (!radio->low->fm_state.rds_rx_enabled)
|
||||
return;
|
||||
|
||||
avail_blocks = (fmspeedy_get_reg_int(0xFFF2BF) + 1) / 4;
|
||||
|
||||
for (i = 0; i < avail_blocks; i++) {
|
||||
/* Fetch the RDS word data. */
|
||||
fifo_data = fmspeedy_get_reg_int(0xFFF3C0);
|
||||
|
||||
data = (u16)((fifo_data >> 16) & 0xFFFF);
|
||||
status = (u8)((fifo_data >> 8) & 0xFF);
|
||||
|
||||
block_type =
|
||||
(fm_rds_block_type_enum) ((status & RDS_BLK_TYPE_MASK)
|
||||
>> RDS_BLK_TYPE_SHIFT);
|
||||
err_count = (status & RDS_ERR_CNT_MASK);
|
||||
|
||||
switch (radio->low->fm_rds_state.current_state) {
|
||||
case RDS_STATE_INIT:
|
||||
fm_rds_change_state(radio, RDS_STATE_HAVE_DATA);
|
||||
break;
|
||||
case RDS_STATE_HAVE_DATA:
|
||||
if ((block_type == RDS_BLKTYPE_A)
|
||||
&& (err_count == 0)) {
|
||||
/* Move to full sync */
|
||||
fm_rds_change_state(radio,
|
||||
RDS_STATE_FULL_SYNC);
|
||||
fm_rds_process_block(radio,
|
||||
data, block_type, err_count);
|
||||
}
|
||||
break;
|
||||
case RDS_STATE_PRE_SYNC:
|
||||
break;
|
||||
case RDS_STATE_FULL_SYNC:
|
||||
if (fm_rds_process_block(radio,
|
||||
data, block_type, err_count)
|
||||
== HOST_RDS_ERRS_UNCORR) {
|
||||
fm_rds_update_error_status(radio,
|
||||
radio->low->fm_state.rds_unsync_uncorr_weight);
|
||||
} else {
|
||||
fm_rds_update_error_status(radio, err_count);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
drivers/media/radio/s610/fm_rds.h
Executable file
27
drivers/media/radio/s610/fm_rds.h
Executable file
|
@ -0,0 +1,27 @@
|
|||
#ifndef FM_RDS_H
|
||||
#define FM_RDS_H
|
||||
|
||||
void fm_rds_write_data(struct s610_radio *radio, u16 rds_data,
|
||||
fm_rds_block_type_enum blk_type, fm_host_rds_errors_enum errors);
|
||||
u16 fm_rds_get_avail_bytes(struct s610_radio *radio);
|
||||
bool fm_read_rds_data(struct s610_radio *radio, u16 *buffer,
|
||||
u16 *size, u16 *blocks);
|
||||
void fm_rds_change_state(struct s610_radio *radio,
|
||||
fm_rds_state_enum new_state);
|
||||
void fm_rds_update_error_status(struct s610_radio *radio, u16 errors);
|
||||
static fm_host_rds_errors_enum fm_rds_process_block(struct s610_radio *radio,
|
||||
u16 data, fm_rds_block_type_enum block_type, u16 err_count);
|
||||
void fm_process_rds_data(struct s610_radio *radio);
|
||||
|
||||
extern void fm_update_rds_sync_status(struct s610_radio *radio, bool synced);
|
||||
|
||||
extern int fm_set_flags(struct s610_radio *radio, u16 flags);
|
||||
extern void fm_timer_reset(fm_timer_t *timer, int usec, fm_callback_t *func,
|
||||
void *arg);
|
||||
extern u32 fmspeedy_get_reg_int(u32 addr);
|
||||
|
||||
#define RDS_BLK_TYPE_MASK 0xE0
|
||||
#define RDS_BLK_TYPE_SHIFT 5
|
||||
#define RDS_ERR_CNT_MASK 0x1F
|
||||
|
||||
#endif /*fm_rds.h*/
|
2250
drivers/media/radio/s610/radio-s610.c
Executable file
2250
drivers/media/radio/s610/radio-s610.c
Executable file
File diff suppressed because it is too large
Load diff
421
drivers/media/radio/s610/radio-s610.h
Executable file
421
drivers/media/radio/s610/radio-s610.h
Executable file
|
@ -0,0 +1,421 @@
|
|||
#ifndef RADIO_S610_H
|
||||
#define RADIO_S610_H
|
||||
|
||||
#define DRIVER_NAME "s610-radio"
|
||||
#define DRIVER_CARD "S610 FM Receiver"
|
||||
|
||||
#define ENABLE_RDS_WORK_QUEUE
|
||||
#undef ENABLE_RDS_WORK_QUEUE
|
||||
|
||||
#define ENABLE_IF_WORK_QUEUE
|
||||
/*#undef ENABLE_IF_WORK_QUEUE*/
|
||||
|
||||
#define USE_FM_LNA_ENABLE
|
||||
/*#undef USE_FM_LNA_ENABLE*/
|
||||
|
||||
#define USE_AUDIO_PM
|
||||
|
||||
/* DEBUG :: Print debug for debug *******/
|
||||
#define SUPPORT_FM_DEBUG
|
||||
#define SUPPORT_API_DEBUG
|
||||
#undef SUPPORT_FM_DEBUG
|
||||
#undef SUPPORT_API_DEBUG
|
||||
|
||||
#ifdef SUPPORT_FM_DEBUG
|
||||
#define FDEBUG(fm, fmt, args...) dev_info(fm->dev, fmt, ##args)
|
||||
#define FUNC_ENTRY(fm) dev_info(fm->dev, "+ %s(): entry\n", __func__)
|
||||
#define FUNC_EXIT(fm) dev_info(fm->dev, "- %s(): exit\n", __func__)
|
||||
#else
|
||||
#define FDEBUG(fm, fmt, args...)
|
||||
#define FUNC_ENTRY(fm)
|
||||
#define FUNC_EXIT(fm)
|
||||
#endif /*SUPPORT_FM_DEBUG*/
|
||||
|
||||
#ifdef SUPPORT_API_DEBUG
|
||||
#define API_ENTRY(fm) dev_info(fm->dev, "> API: %s(): entry\n", __func__)
|
||||
#define API_EXIT(fm) dev_info(fm->dev, "< API: %s(): exit\n", __func__)
|
||||
#define APIEBUG(fm, fmt, args...) dev_info(fm->dev, fmt, ##args)
|
||||
#else
|
||||
#define API_ENTRY(fm)
|
||||
#define API_EXIT(fm)
|
||||
#define APIEBUG(fm, fmt, args...)
|
||||
#endif
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wakelock.h>
|
||||
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-event.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define V4L2_CID_USER_S610_BASE (0x00980900 + 0x1070)
|
||||
enum s610_ctrl_id {
|
||||
V4L2_CID_S610_CH_SPACING = (V4L2_CID_USER_S610_BASE + 0x01),
|
||||
V4L2_CID_S610_CH_BAND = (V4L2_CID_USER_S610_BASE + 0x02),
|
||||
V4L2_CID_S610_SOFT_STEREO_BLEND = (V4L2_CID_USER_S610_BASE + 0x03),
|
||||
V4L2_CID_S610_SOFT_STEREO_BLEND_COEFF = (V4L2_CID_USER_S610_BASE+0x04),
|
||||
V4L2_CID_S610_SOFT_MUTE_COEFF = (V4L2_CID_USER_S610_BASE + 0x5),
|
||||
V4L2_CID_S610_RSSI_CURR = (V4L2_CID_USER_S610_BASE + 0x06),
|
||||
V4L2_CID_S610_SNR_CURR = (V4L2_CID_USER_S610_BASE + 0x07),
|
||||
V4L2_CID_S610_SEEK_CANCEL = (V4L2_CID_USER_S610_BASE + 0x08),
|
||||
V4L2_CID_S610_SEEK_MODE = (V4L2_CID_USER_S610_BASE + 0x09),
|
||||
V4L2_CID_S610_RDS_ON = (V4L2_CID_USER_S610_BASE + 0x0A),
|
||||
V4L2_CID_S610_IF_COUNT1 = (V4L2_CID_USER_S610_BASE + 0x0B),
|
||||
V4L2_CID_S610_IF_COUNT2 = (V4L2_CID_USER_S610_BASE + 0x0C),
|
||||
V4L2_CID_S610_RSSI_TH = (V4L2_CID_USER_S610_BASE + 0x0D)
|
||||
|
||||
};
|
||||
|
||||
enum fm_flag_get {
|
||||
FM_EVENT_TUNED = (1 << 0),
|
||||
FM_EVENT_BD_LMT = (1 << 1),
|
||||
FM_EVENT_SYN_LOS = (1 << 2),
|
||||
FM_EVENT_BUF_FUL = (1 << 3),
|
||||
FM_EVENT_AUD_PAU = (1 << 4),
|
||||
FM_EVENT_CH_STAT = (1 << 5)
|
||||
};
|
||||
|
||||
/* Tunner modes */
|
||||
enum fm_tuner_mode {
|
||||
FM_TUNER_STOP_SEARCH_MODE = 0,
|
||||
FM_TUNER_PRESET_MODE = 1,
|
||||
FM_TUNER_AUTONOMOUS_SEARCH_MODE = 2,
|
||||
FM_TUNER_AUTONOMOUS_SEARCH_MODE_NEXT = 10
|
||||
};
|
||||
|
||||
/* channel spacing */
|
||||
enum fm_channel_spacing {
|
||||
FM_CHANNEL_SPACING_50KHZ = 1,
|
||||
FM_CHANNEL_SPACING_100KHZ = 2,
|
||||
FM_CHANNEL_SPACING_200KHZ = 4
|
||||
};
|
||||
|
||||
#define FM_FREQ_MUL 50
|
||||
|
||||
/* Mute modes */
|
||||
enum fm_mute_mode {
|
||||
FM_MUTE_ON = 0,
|
||||
FM_MUTE_OFF = 1,
|
||||
FM_MUTE_ATTENUATE = 2
|
||||
};
|
||||
|
||||
/* Register set mute bits */
|
||||
enum fm_reg_mute {
|
||||
FM_RX_UNMUTE_MODE = 0x00,
|
||||
FM_RX_RF_DEP_MODE = 0x01,
|
||||
FM_RX_AC_MUTE_MODE = 0x02,
|
||||
FM_RX_HARD_MUTE_LEFT_MODE = 0x04,
|
||||
FM_RX_HARD_MUTE_RIGHT_MODE = 0x08,
|
||||
FM_RX_SOFT_MUTE_FORCE_MODE = 0x10
|
||||
};
|
||||
|
||||
/* FM RDS modes */
|
||||
enum fm_rds_mode {
|
||||
FM_RDS_DISABLE = 0,
|
||||
FM_RDS_ENABLE = 1
|
||||
};
|
||||
|
||||
/* RF dependent mute mode */
|
||||
#define FM_RX_RF_DEPENDENT_MUTE_ON 1
|
||||
#define FM_RX_RF_DEPENDENT_MUTE_OFF 0
|
||||
|
||||
#define FM_DRV_TURN_TIMEOUT (5*HZ) /* 5 seconds */
|
||||
#define FM_DRV_SEEK_TIMEOUT (20*HZ) /* 10 seconds */
|
||||
|
||||
/* Min and Max volume */
|
||||
#define FM_RX_VOLUME_MIN 0
|
||||
#define FM_RX_VOLUME_MAX 70
|
||||
|
||||
/* Volume gain step */
|
||||
#define FM_RX_VOLUME_GAIN_STEP 0x370
|
||||
|
||||
#define FM_SEARCH_DIRECTION_UP 0
|
||||
#define FM_SEARCH_DIRECTION_DOWN 1
|
||||
|
||||
/* undefined freq */
|
||||
#define FM_UNDEFINED_FREQ 0xFFFFFFFF
|
||||
|
||||
/* RDS system type (RDS/RBDS) */
|
||||
#define FM_RDS_SYSTEM_RDS 0
|
||||
#define FM_RDS_SYSTEM_RBDS 1
|
||||
|
||||
/* AF on/off */
|
||||
#define FM_RX_RDS_AF_SWITCH_MODE_ON 1
|
||||
#define FM_RX_RDS_AF_SWITCH_MODE_OFF 0
|
||||
|
||||
/* RX RDS */
|
||||
#define FM_RX_RDS_FLUSH_FIFO 0x1
|
||||
#define FM_RX_RDS_FIFO_THRESHOLD 48 /* tuples */
|
||||
#define FM_RDS_BLK_SIZE 3 /* 3 bytes */
|
||||
|
||||
/* default RSSI value for init */
|
||||
#define FM_DEFAULT_RSSI_THRESHOLD 0x92
|
||||
|
||||
/* Reset pre-tune value */
|
||||
#define RESET_PRETUNE_VALUE 103500
|
||||
|
||||
#define GPIO_LOW 0
|
||||
#define GPIO_HIGH 1
|
||||
|
||||
struct s610_radio;
|
||||
|
||||
enum s610_power_state {
|
||||
S610_POWER_DOWN = 0,
|
||||
S610_POWER_ON_FM = 1,
|
||||
S610_POWER_ON_RDS = 2
|
||||
};
|
||||
|
||||
/* FM region (Europe/US, Japan) info */
|
||||
struct region_info {
|
||||
u32 chanl_space;
|
||||
u32 bot_freq;
|
||||
u32 top_freq;
|
||||
u8 fm_band;
|
||||
};
|
||||
|
||||
struct s610_core {
|
||||
int chip_id;
|
||||
struct mutex cmd_lock; /* for serializing fm radio operations */
|
||||
/* enum s610_power_state power_state;*/
|
||||
u8 power_mode;
|
||||
wait_queue_head_t rds_read_queue;
|
||||
};
|
||||
|
||||
/**
|
||||
* s610_core_lock() - lock the core device to get an exclusive access
|
||||
* to it.
|
||||
*/
|
||||
static inline void s610_core_lock_init(struct s610_core *core)
|
||||
{
|
||||
mutex_init(&core->cmd_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* s610_core_lock() - lock the core device to get an exclusive access
|
||||
* to it.
|
||||
*/
|
||||
static inline void s610_core_lock(struct s610_core *core)
|
||||
{
|
||||
mutex_lock(&core->cmd_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* s610_core_lock() - lock the core device to get an exclusive access
|
||||
* to it.
|
||||
*/
|
||||
static inline int __must_check s610_core_lock_interruptible(
|
||||
struct s610_core *core)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&core->cmd_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* s610_core_unlock() - unlock the core device to relinquish an
|
||||
* exclusive access to it.
|
||||
*/
|
||||
static inline void s610_core_unlock(struct s610_core *core)
|
||||
{
|
||||
mutex_unlock(&core->cmd_lock);
|
||||
}
|
||||
|
||||
static inline int api_to_real(int freq)
|
||||
{
|
||||
return freq;
|
||||
}
|
||||
|
||||
static inline int real_to_api(int freq)
|
||||
{
|
||||
return freq;
|
||||
}
|
||||
|
||||
#define FREQ_MUL (10000000 / 625)
|
||||
|
||||
enum s610_freq_bands {
|
||||
S610_BAND_FM,
|
||||
S610_BAND_AM,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s610_radio - radio device
|
||||
*
|
||||
* @core: Pointer to underlying core device
|
||||
* @videodev: Pointer to video device created by V4L2 subsystem
|
||||
* @ops: Vtable of functions. See struct s610_radio_ops for details
|
||||
* @kref: Reference counter
|
||||
* @core_lock: An r/w semaphore to brebvent the deletion of underlying
|
||||
* core structure is the radio device is being used
|
||||
*/
|
||||
struct s610_radio {
|
||||
struct v4l2_device v4l2dev;
|
||||
struct video_device videodev;
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
|
||||
struct s610_core *core;
|
||||
struct s610_low *low;
|
||||
|
||||
u32 audmode;
|
||||
|
||||
int radio_region;
|
||||
struct region_info region; /* Current selected band */
|
||||
u8 mute_mode; /* Current mute mode */
|
||||
u32 freq; /* Current RX frquency */
|
||||
u8 deemphasis_mode; /* Current deemphasis mode */
|
||||
u8 rf_depend_mute; /* RF dependent soft mute mode */
|
||||
u16 volume; /* Current volume level */
|
||||
u16 rssi_threshold; /* Current RSSI threshold level */
|
||||
u8 rds_mode; /* RDS operation mode (RDS/RDBS) */
|
||||
u8 af_mode; /* Alternate frequency on/off */
|
||||
|
||||
u16 irq_flag; /* FM interrupt flag */
|
||||
u16 irq_mask; /* FM interrupt mask */
|
||||
unsigned int irq; /* AP interrupt line */
|
||||
|
||||
/* flags FR BL completion handler */
|
||||
struct completion flags_set_fr_comp;
|
||||
struct completion flags_seek_fr_comp;
|
||||
|
||||
/* set if counter completion handler */
|
||||
struct completion set_if_cnt_comp;
|
||||
|
||||
spinlock_t slock; /* To protect access to buffer */
|
||||
spinlock_t rds_lock; /* To protect access to buffer */
|
||||
|
||||
struct wake_lock wakelock;
|
||||
atomic_t is_doing;
|
||||
atomic_t is_rds_new;
|
||||
int wait_atomic;
|
||||
int wait_atomic_rds;
|
||||
|
||||
spinlock_t rds_buff_lock; /* To protect access to RDS buffer */
|
||||
u8 rds_flag; /* RX RDS on/off status */
|
||||
u8 rds_new; /* RX RDS new data status */
|
||||
u8 rds_buf[480];
|
||||
|
||||
struct mutex lock;
|
||||
struct workqueue_struct *work_queue;
|
||||
struct workqueue_struct *if_work_queue;
|
||||
|
||||
#ifdef ENABLE_RDS_WORK_QUEUE
|
||||
struct work_struct work;
|
||||
#endif /*ENABLE_RDS_WORK_QUEUE*/
|
||||
#ifdef ENABLE_IF_WORK_QUEUE
|
||||
struct work_struct if_work;
|
||||
#endif /*ENABLE_IF_WORK_QUEUE*/
|
||||
|
||||
struct delayed_work dwork_sig2;
|
||||
struct delayed_work dwork_tune;
|
||||
u16 dwork_idle_counter;
|
||||
u16 dwork_sig2_counter;
|
||||
u16 dwork_tune_counter;
|
||||
|
||||
u16 idle_fniarg;
|
||||
u16 sig2_fniarg;
|
||||
u16 tune_fniarg;
|
||||
|
||||
u16 freq_step;
|
||||
u8 speedy_error;
|
||||
u16 seek_mode;
|
||||
u32 seek_freq; /* seek start frquency */
|
||||
u32 seek_status;
|
||||
u32 wrap_around;
|
||||
void __iomem *fmspeedy_base;
|
||||
void __iomem *fm_speed_m_base;
|
||||
#ifdef USE_FM_LNA_ENABLE
|
||||
int elna_gpio;
|
||||
#endif /* USE_FM_EXTERN_PLL */
|
||||
struct platform_device *pdev;
|
||||
struct device *dev;
|
||||
struct clk *clk;
|
||||
#ifdef USE_AUDIO_PM
|
||||
struct device *a_dev;
|
||||
#endif /* USE_AUDIO_PM */
|
||||
|
||||
/* debug print counter */
|
||||
int idle_cnt_mod;
|
||||
int rds_cnt_mod;
|
||||
|
||||
/* Test RDS log */
|
||||
int rds_n_count;
|
||||
int rds_r_count;
|
||||
int rds_new_stat;
|
||||
int rds_read_cnt;
|
||||
/* Test RDS log end */
|
||||
};
|
||||
|
||||
extern bool fm_radio_on(struct s610_radio *radio);
|
||||
extern void fm_radio_off(struct s610_radio *radio);
|
||||
extern void fm_rds_on(struct s610_radio *radio);
|
||||
extern void fm_rds_off(struct s610_radio *radio);
|
||||
extern void fm_set_band(struct s610_radio *radio, u8 index);
|
||||
extern void fm_boot(struct s610_radio *radio);
|
||||
extern void fm_power_off(void);
|
||||
|
||||
extern int low_get_search_lvl(struct s610_radio *radio, u16 *value);
|
||||
extern u16 fm_get_flags(struct s610_radio *radio);
|
||||
extern int low_set_if_limit(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_search_lvl(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_freq(struct s610_radio *radio, u32 value);
|
||||
extern int low_set_tuner_mode(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_mute_state(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_most_mode(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_most_blend(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_pause_lvl(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_pause_dur(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_demph_mode(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_rds_cntr(struct s610_radio *radio, u16 value);
|
||||
extern int low_set_power(struct s610_radio *radio, u16 value);
|
||||
extern u8 aggr_rssi_device_to_host(u16 val);
|
||||
extern int fm_host_read_rds_data(
|
||||
struct s610_radio *radio, u16 *num_of_block, u8 *rds_data);
|
||||
extern void fm_isr(struct s610_radio *radio);
|
||||
extern void cancel_tuner_timer(struct s610_radio *radio);
|
||||
extern int init_low_struc(struct s610_radio *radio);
|
||||
extern void fm_speedy_m_int_enable(void);
|
||||
extern void fm_speedy_m_int_disable(void);
|
||||
#ifdef ENABLE_RDS_WORK_QUEUE
|
||||
extern void s610_rds_work(struct work_struct *work);
|
||||
#endif /*ENABLE_RDS_WORK_QUEUE*/
|
||||
#ifdef ENABLE_IF_WORK_QUEUE
|
||||
extern void s610_if_work(struct work_struct *work);
|
||||
#endif /*ENABLE_IF_WORK_QUEUE*/
|
||||
|
||||
extern void s610_sig2_work(struct work_struct *work);
|
||||
extern void s610_tune_work(struct work_struct *work);
|
||||
|
||||
extern void fm_set_blend_mute(struct s610_radio *radio);
|
||||
|
||||
extern u32 fmspeedy_get_reg(u32 addr);
|
||||
extern void fmspeedy_set_reg(u32 addr, u32 data);
|
||||
|
||||
extern void fm_update_rssi(struct s610_radio *radio);
|
||||
extern void fm_update_snr(struct s610_radio *radio);
|
||||
#ifdef VOLUME_CTRL_S610
|
||||
extern void fm_set_audio_gain(struct s610_radio *radio, u16 gain);
|
||||
#endif /*VOLUME_CTRL_S610*/
|
||||
extern void fm_aux_pll_off(void);
|
||||
extern void fmspeedy_wakeup(void);
|
||||
|
||||
#endif /* RADIO_S610_H */
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue