FM收音机调试-RDA5807M
调试平台 平台:Allwinner
安卓版本:android15
内核版本:linux6.6
FM收音机调试-RDA5807M
1 模组数据手册2 调试记录2.1 硬件2.1.1 寄存器功能说明
2.2 软件2.2.1 I2C读写接口2.2.1.1 读函数2.2.1.2 写函数
2.2.2 驱动2.2.2.1 设备树2.2.2.2 驱动源码2.2.2.3 测试应用源码
1 模组数据手册
2 调试记录
2.1 硬件
原理图
第4.5脚为I2C的SCK和SDA。 第6脚为晶振时钟输入脚。需要根据实际的时钟频率输入,配置寄存器02H[6:4]的CLK_MODE。如果没有时钟输入或者时钟配置错误,会出现无法调谐的情况。 第9.10脚为音频输出脚。
2.1.1 寄存器功能说明
REG_03H [15:6]:设置信道值,在执行seek操作成功后才会更新。 REG_02H [8]:【SEEK位】为1开始寻道,当寻道操作完成时,SEEK位被设置为低电平,STC位被设置为高电平。 REG_03H [4]:【调谐TUNE位】当tune置1时调谐操作开始,调谐操作完成后STC位会被拉高,调谐操作完成时,调谐位自动复位为低。 REG_0AH [9:0]: 读取信道值,在成功调谐或查找之后才会更新。 REG_0BH[15:9]:表示当前信号强度0-127。 REG_0BH[14]:STC位,表示信号调谐是否完成。
寄存器位名称功能默认值00H[15:0]Chip IDChip ID0x580402H[15]DHIZ音频高阻态输出:0:静音 1:正常模式0[14]DMUTE静音:0:静音 1:正常0[13]MONO单声道:0:立体声 1:单声道0[12]BASS增强低音:0:禁用 1:启用0[11]RCLK NON-CALIBRATE MODE晶振启用:0:总是启用1:仅FM工作时启用0[10]RCLK DIRECT INPUT MODE晶振直接输入模式0:正常1:直接输入模式0[9]SEEKUP向上搜索0:向下搜索1:向上搜索0[8]SEEK搜索启用0:停止搜索1:启用搜索0[7]SKMODE搜索模式0:到达边界处从另一边界开始搜索1:到达边界处停止搜索0[6:4]CLK_MODE[2:0]晶振频率000:32.768KHz001:12MHz101:24MHz010:12MHz110:26MHz011:19.2MHz111:38.4MHz0[3]RDS_ENRDS/RBDS启用0:不启用1:启用0[2]NEW_METHOD使用新技术提高信号质量可提高约1dB灵敏度0[1]SOFT_RESET软件复位0:正常1:复位0[0]ENABLE上电启用0:不启用1:启用003H[15:6]CHAN[9:0]信道(用于选择频率)BAND = 0:Frequency = Channel Spacing (kHz) x CHAN+ 87.0 MHzBAND = 1 or 2:Frequency = Channel Spacing (kHz) x CHAN + 76.0 MHzBAND = 3:Frequency = Channel Spacing (kHz) x CHAN + 65.0 MH0x00[5]DIRECT MODE直接控制模式,仅在测试模式使用0[4]TUNE调谐0:禁用1:启用0[3:2]BAND[1:0]波段00:87-108MHz(美国/欧洲)01:76-91MHz(日本)10:76-108MHz(全球)11:65-76MHz或50-65MHz(东欧)(根据0x07寄存器的bit9选择 1:65-76MHz 0:50-76MHz)00[1:0]SPACE[1:0]频率的间隔00:100kHz01:200kHz10:50kHz11:25kHz0004H[15]RSVD保留0[14]STCIEN搜索和调谐中断使能0:禁用1:启用(中断是GPIO2的低脉冲)[13]RBDSRBDS/RDS功能0:仅使用RDS1:RBDS启用0[12]RDS_FIFO_EN1=开启RDS先进先出功能0[11]DE去重0:75us1:50us0[10]RDS_FIFO_CLR清除RDS先进先出1:清除1[9]SOFTMUTE_EN软件静音使能0:关闭软件静音1:开启软件静音0[8]AFCDAFC失能0:AFC启用1:AFK禁用0[7]Rsvd被读取时为00[6]I2S_ENABLEI2S使能0:关闭1:打开0[5:4]GPIO3[1:0]GPIO300:高阻01:单声道/立体声指示10:低电平11:高电平00[3:2]GPIO2[1:0]GPIO200:高阻01:中断10:低电平11:高电平00[1:0]GPIO1[1:0]GPIO100:高阻01:保留10:低电平11:高电平0005H[15]INT_MODE中断模式0:每5ms产生中断1:中断持续到读取了0x0C寄存器1[14:13]Seek_mode搜索模式00:默认10:添加RSSI模式00[12]RSVD保留0[11:8]SEEKTH[3:0]SNK阈值1000[7:6]LNA_PORT_SEL[1:0]低噪声放大器输入端口选择00:无输入01:LNAN10:LNAP11:双输入10[5:4]LNA_ICSEL_BIT[1:0]低噪声放大器工作电流00:1.8mA01:2.1mA10:2.5mA11:3.0mA00[3:0]VOLUME[3:0]音量0-15等级0000=min 1111=max当0000时,输出静音,输出阻抗很大101106H[15]RSVD保留0[14:13]OPEN_MODE[1:0]保留寄存器模式11:打开寄存器后写入其他:仅打开寄存器后读取功能00[12]slave_masterI2S主从0:主机1:从机0[11]ws_lrWs与l/r通道的关系0:ws=0 ->r, ws=1 ->l1:ws=0 ->l, ws=1 ->r0[10]sclk_i_edgeSCLK边沿0:正常1:反相0[9]data_signedI2S数据符号0:无符号16bit1:有符号16bit0[8]WS_I_EDGE0:正常1:反相0[7:4]I2S_SW_CNT[4:0]Only validin master mode波特率只有主机模式有用1000: WS_STEP_48 0111: WS_STEP:44.1kbps;0110: WS_STEP:32kbps;0101: WS_STEP:24kbps;0100: WS_STEP:22.05kbps;0011: WS_STEP:16kbps;0010: WS_STEP:12kbps;0001: WS_STEP:11.025kbps;0000: WS_STEP:8kbps;0000[3]SW_O_EDGEWs输出0:禁用1:启用0[2]SCLK_O_EDGESCLK输出0:禁用1:启用0[1]L_DELY左声道延迟0:不延迟1:延迟1T0[0]R_DELY右声道延迟0:不延迟1:延迟1T007H[15]RSVD保留0[14:10]TH_SOFRBLEND[5:0]噪声软混合设置阈值,单位2dB10000[9]65M_50M MODE选择频率段在0x3[3:2]=11时有效0 :50~76 MHz.1: 65~76 MHz1[8]RSVD保留0[7:2]SEEK_TH_OLD旧搜索模式的搜索阈值, 0x05[14:13]=10时有效0[1]SOFTBLEND_ENSoftblend启用0:禁用1:启用1[0]FREQ_MODE频率模式0:传统模式1:直接写出频率(0x08)008H[15:0]freq_direct[15:0]频率07H[0]=1时有效00000AH[15]RDSRRDS就绪0:没有RDS/RBDS组没有准备就绪1:新的RDS/RBDS组准备就绪0[14]STC调谐搜索完成0:未完成1:完成调谐搜索完成的标志位,在调谐或搜索完成时被置10[13]SF搜索失败0:成功1:失败当寻道操作找不到RSSSI值大于SEEKTH[3:0]的信道时,设置寻道失败标志0[12]RDSSRDS同步0:RDS解码器未同步(默认)1:RDS解码器已同步仅在RDS详细模式下可用0[11]BLK_E当RDS启用时0:没有找到Block E1:找到Block E0[10]ST立体声指示0:单声道1:立体声1[9:0]READCHAN[9:0]信道值00BH[15:9]RSSI[6:0]信号强度0-127RSSI是对数0[8]FM TRUE电台指示0:不是电台1:是电台0[7]FM_READY软件搜索0:没有就绪1:就绪[6:5]reserved保留[4]ABCD_E0x0c,0x0d,0x0e,0x0f功能0:ABCD1:E决定0CH、0DH、0EH、0FH的块id是ABCD还是E0[3:2]BLERA[1:0]纠错级别00:0需要更正的错误01:需要纠正的1~2个错误10:需要纠正的3-5个错误11:6+错误或校验字错误,无法纠正。仅在RDS模式下使用[1:0]BLERB[1:0]纠错级别00:0需要更正的错误01:需要纠正的1~2个错误10:需要纠正的3-5个错误11:6+错误或校验字错误,无法纠正。仅在RDS模式下使用0CH[15:0]RDSA[15:0]BLOCK A ( 在RDS模式) 或BLOCK E (0x0B[4]=1)0x58030DH[15:0]RDSC[15:0]BLOCK B ( 在RDS模式) 或BLOCK E (0x0B[4]=1)0x58040EH[15:0]RDSC[15:0]BLOCK C ( 在RDS模式) 或BLOCK E (0x0B[4]=1)|0x58080FH[15:0]RDSC[15:0]BLOCK D ( 在RDS模式) 或BLOCK E (0x0B[4]=1)0x5804
2.2 软件
2.2.1 I2C读写接口
I2C 7位地址Addr:0x10 (0b0010000) RDA5807M的寄存器地址是8bit而其内容是16bit数据。所以I2C的读写接口需要特别注意。
2.2.1.1 读函数
static uint16_t rda5807m_i2c_read(struct i2c_client* client,uint8_t address) 参数: uint8_t address:想要读取的目的寄存器地址(8bit) 返回值: uint16_t:目的寄存器中的值(16bit)
rda5807m_i2c_read中先发送8位的寄存器地址,然后用char databuf[2]接收16bit的数据,databuf[0]接收到寄存器的高8位数据,databuf[1]接收到寄存器的低8位数据。
/**
* @brief i2c读函数
* @param address:uint8_t address
* @return fail:ret < 0
* @author chenmango
*/
static uint16_t rda5807m_i2c_read(struct i2c_client* client,uint8_t address)
{
int ret = -1;
unsigned char databuf[2] = {0};
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &address,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = 2,
.buf = databuf,
},
};
ret = i2c_transfer(client->adapter, msgs, 2);
if(ret < 0)
LOG_ERR("rda5807m_i2c_read err!\n");
return (databuf[0]<<8 | databuf[1]);
}
2.2.1.2 写函数
static int rda5807m_i2c_write(struct i2c_client* client,uint8_t address,uint16_t data) 参数: uint8_t address:想要写入的目的寄存器地址(8bit) uint16_t data:想要写入的数据(16bit) 返回值: ret: <0->fail
rda5807m_i2c_write中发送3个databuf,databuf[0]为想要写入的寄存器地址,databuf[1]为写入数据的高8位,databuf[2]为写入数据的低8位
/**
* @brief i2c写函数
* @param databuf:databuf[0]=REG_ADDR databuf[1]=H_DATA databuf[2]=L_DATA
* @return fail:ret < 0
* @author chenmango
*/
static int rda5807m_i2c_write(struct i2c_client* client,uint8_t address,uint16_t data)
{
int ret = -1;
uint8_t databuf[3] = {0};
databuf[0] = address;
databuf[1] = data >> 8;
databuf[2] = data & 0x00FF;
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = 3,
.buf = databuf,
},
};
ret = i2c_transfer(client->adapter, msgs, 1);
if(ret < 0)
LOG_ERR("rda5807m_i2c_write err!\n");
return ret;
}
2.2.2 驱动
2.2.2.1 设备树
设备树配置如下:
RDA5807M@11{
compatible = "rda,rda5807m";
clocks = <&rtc_ccu CLK_RTC_32K_FANOUT>;//时钟源
clock-names = "32k_fanout";
clk_flag = <1>;//使用外部时钟源则配置1 时钟源常供则配置0
rda_clk_rate = <32768>;//时钟频率
reg = <0x11>;//I2C地址
status = "okay";
};
如果晶振时钟常供无需软件配置,则不需要配置clk_flag/clocks/clock-names/rda_clk_rate 属性
2.2.2.2 驱动源码
在probe中根据clk_flag判断是否需要初始化时钟调用rda5807m_of_get_source解析设备树资源rda5807m_hwinit中初始化设备
读取chip_id 兵判断是否等于0x5804调用rda5807m_reset复位芯片调用rda5807m_enable使能芯片调用rda5807m_setmute解除静音调用rda5807m_set_output_idle退出空闲模式调用rda5807m_set_freqspace设置信道间隔100KHz调用rda5807m_set_freqrange设置波段87-108MHz调用rda5807m_set_freq设置频率9740(97.4MHz) init中已经调用misc_deregister注册了rda5807m_dev设备rda5807m_fm_fops注册了rda5807m_ioctl的接口
在rda5807m_ioctl中实现ioctl接口,方便应用层调用调试
#include
#include
#include
#include
#include
#include
#include
#include
/* insmod rda5807m.ko dbg_level=1/2/3 */
static int dbg_level = 0;
module_param_named(dbg_level, dbg_level, int, 0644);
#define LOG_ERR(fmt,...) \
do { \
if (dbg_level > 0) { \
printk(KERN_ERR fmt,##__VA_ARGS__); \
} \
} while (0)
#define LOG_INFO(fmt,...) \
do { \
if (dbg_level > 1) { \
printk(KERN_INFO fmt,##__VA_ARGS__); \
} \
} while (0)
#define LOG_DBG(fmt,...) \
do { \
if (dbg_level > 2) { \
printk(KERN_DEBUG fmt,##__VA_ARGS__); \
} \
} while (0)
/* @brief ic内部寄存器 */
#define REG_00 0x00
#define REG_01 0x01
#define REG_02 0x02
#define REG_03 0x03
#define REG_04 0x04
#define REG_05 0x05
#define REG_06 0x06
#define REG_07 0x07
#define REG_08 0x08
#define REG_09 0x09
#define REG_0A 0x0A
#define REG_0B 0x0B
#define REG_0C 0x0C
#define REG_0D 0x0D
#define REG_0E 0x0E
/* @brief 步长频率 */
#define FREQ_SPACE_100KHz 0
#define FREQ_SPACE_200KHz 1
#define FREQ_SPACE_50KHz 2
#define FREQ_SPACE_25KHz 3
/* @brief 频率段 */
#define FREQ_RANGE_87_108 0
#define FREQ_RANGE_76_91 1
#define FREQ_RANGE_76_108 2
#define FREQ_RANGE_65_76 3
#define FREQ_RANGE_50_76 4
/* @brief 存放频段数组的大小 */
#define RDA5807M_N_STATION 20
/* @brief ioctl */
#define FMRX_IOCTL_SET_FREQ _IOWR('s', 1, int)
#define FMRX_IOCTL_READ_FREQ _IOWR('r', 2, int)
#define FMRX_IOCTL_SEARCH_FREQ_TURNUP _IOWR('c', 3, int)
#define FMRX_IOCTL_SEARCH_ALL_FREQ _IOWR('c', 4, int)
#define FMRX_IOCTL_SET_VOLUME _IOWR('s', 5, int)
#define FMRX_IOCTL_READ_VOLUME _IOWR('r', 6, int)
#define FMRX_IOCTL_SET_MUTE _IOWR('c', 7, int)
#define FMRX_IOCTL_SET_OUTPUT_IDLE _IOWR('c', 8, int)
#define FMRX_IOCTL_READ_SIGNAL_INTENSITY _IOWR('r', 9, int)
#define FMRX_IOCTL_SET_FREQ_RANGE _IOWR('s', 10, int)
#define FMRX_IOCTL_READ_FREQ_RANGE _IOWR('r', 11, int)
#define FMRX_IOCTL_SET_FREQ_SAPCE _IOWR('s', 12, int)
#define FMRX_IOCTL_READ_FREQ_SAPCE _IOWR('r', 13, int)
#define FMRX_IOCTL_READ_ID _IOWR('r', 14, int)
#define FMRX_IOCTL_PRINT_REG _IOWR('c', 15, int)
#define FMRX_IOCTL_ENABLE _IOWR('c', 16, int)
#define FMRX_IOCTL_DISABLE _IOWR('c', 17, int)
#define FMRX_IOCTL_WRITE_REG _IOWR('s', 18, int)
#define DEF_CLK_FREQ 32768
struct rda5807m_data_s {
struct i2c_client *client;
uint32_t clk_flag;
struct clk *rda_clk;
uint32_t rda_clk_rate;
}rda5807m_data_t;
uint16_t RDA5807M_RadioStation_Freq[RDA5807M_N_STATION] = {0}; //查找到的电台
/**
* @brief i2c写函数
* @param databuf:databuf[0]=REG_ADDR databuf[1]=H_DATA databuf[2]=L_DATA
* @return fail:ret < 0
* @author chenmango
*/
static int rda5807m_i2c_write(struct i2c_client* client,uint8_t address,uint16_t data)
{
int ret = -1;
uint8_t databuf[3] = {0};
databuf[0] = address;
databuf[1] = data >> 8;
databuf[2] = data & 0x00FF;
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = 3,
.buf = databuf,
},
};
ret = i2c_transfer(client->adapter, msgs, 1);
if(ret < 0)
LOG_ERR("rda5807m_i2c_write err!\n");
return ret;
}
/**
* @brief i2c读函数
* @param address:uint8_t address
* @return fail:ret < 0
* @author chenmango
*/
static uint16_t rda5807m_i2c_read(struct i2c_client* client,uint8_t address)
{
int ret = -1;
unsigned char databuf[2] = {0};
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &address,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = 2,
.buf = databuf,
},
};
ret = i2c_transfer(client->adapter, msgs, 2);
if(ret < 0)
LOG_ERR("rda5807m_i2c_read err!\n");
return (databuf[0]<<8 | databuf[1]);
}
static void __maybe_unused rda5807m_reg_dump(struct rda5807m_data_s *data)
{
uint16_t print_buf[16] = {0};
print_buf[0] = rda5807m_i2c_read(data->client,REG_00);
print_buf[1] = rda5807m_i2c_read(data->client,REG_01);
print_buf[2] = rda5807m_i2c_read(data->client,REG_02);
print_buf[3] = rda5807m_i2c_read(data->client,REG_03);
print_buf[4] = rda5807m_i2c_read(data->client,REG_04);
print_buf[5] = rda5807m_i2c_read(data->client,REG_05);
print_buf[6] = rda5807m_i2c_read(data->client,REG_06);
print_buf[7] = rda5807m_i2c_read(data->client,REG_07);
print_buf[8] = rda5807m_i2c_read(data->client,REG_08);
print_buf[9] = rda5807m_i2c_read(data->client,REG_09);
print_buf[10] = rda5807m_i2c_read(data->client,REG_0A);
print_buf[11] = rda5807m_i2c_read(data->client,REG_0B);
print_buf[12] = rda5807m_i2c_read(data->client,REG_0C);
print_buf[13] = rda5807m_i2c_read(data->client,REG_0D);
print_buf[14] = rda5807m_i2c_read(data->client,REG_0E);
for(int i = 0;i < 15;i++){
LOG_INFO("[REG_%x]:0x%x\n",i,print_buf[i]);
}
}
/**
* @brief 使能 REG_02[1:0]->0b01
*
*/
static void rda5807m_enable(struct rda5807m_data_s *data)
{
uint16_t result = rda5807m_i2c_read(data->client,REG_02);
result &= ~(0x3);
result |= 0x01;
rda5807m_i2c_write(data->client,REG_02,result);
mdelay(50);
}
/**
* @brief 失能 REG_02[0]->0
*
*/
static void rda5807m_disable(struct rda5807m_data_s *data)
{
uint16_t result = rda5807m_i2c_read(data->client,REG_02);
result &= ~(0x1);
rda5807m_i2c_write(data->client,REG_02,result);
mdelay(50);
}
/**
* @brief 设置步长频率 REG_03[1:0]
* @param FREQ_SPACE_100KHz 0
* FREQ_SPACE_200KHz 1
* FREQ_SPACE_50KHz 2
* FREQ_SPACE_25KHz 3
*/
static void rda5807m_set_freqspace(struct rda5807m_data_s *data,uint8_t space)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_03);
if (space == FREQ_SPACE_100KHz)
{ //0x03[1:0]=00
result &= ~(1 << 1);
result &= ~(1 << 0);
}
else if (space == FREQ_SPACE_200KHz)
{ //0x03[1:0]=01
result &= ~(1 << 1);
result |= 1 << 0;
}
else if (space == FREQ_SPACE_50KHz)
{ //0x03[1:0]=10
result |= 1 << 1;
result &= ~(1 << 0);
}
else if (space == FREQ_SPACE_25KHz)
{ //0x03[1:0]=11
result |= 1 << 1;
result |= 1 << 0;
}
rda5807m_i2c_write(data->client,REG_03,result);
}
/**
* @brief 读取步长频率 REG_03[1:0]
* @param FREQ_SPACE_100KHz 0
* FREQ_SPACE_200KHz 1
* FREQ_SPACE_50KHz 2
* FREQ_SPACE_25KHz 3
*
*/
uint8_t rda5807m_read_freqspace(struct rda5807m_data_s *data)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_03);
result &= 0x3;
switch (result) {
case 0x0:
LOG_DBG("[%s]:read freqrange FREQ_SPACE_100KHz\n",__func__);
return (uint8_t)result;
case 0x1:
LOG_DBG("[%s]:read freqrange FREQ_SPACE_200KHz\n",__func__);
return (uint8_t)result;
case 0x2:
LOG_DBG("[%s]:read freqrange FREQ_SPACE_50KHz\n",__func__);
return (uint8_t)result;
case 0x3:
LOG_DBG("[%s]:read freqrange FREQ_SPACE_25KHz\n",__func__);
return (uint8_t)result;
default:
LOG_ERR("[%s]:read freqrange fail\n",__func__);
return 0;
}
}
/**
* @brief 设置频率段 band REG_03[3:2]
* #define FREQ_RANGE_87_108 0
* #define FREQ_RANGE_76_91 1
* #define FREQ_RANGE_76_108 2
* #define FREQ_RANGE_65_76 3
* #define FREQ_RANGE_50_76 4
*/
static void rda5807m_set_freqrange(struct rda5807m_data_s *data,uint8_t range)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_03);
if (range == FREQ_RANGE_87_108)
{ //0x03[3:2]=00 0x07[9]=x
result &= ~(1 << 3);
result &= ~(1 << 2);
rda5807m_i2c_write(data->client,REG_03,result);
}
else if (range == FREQ_RANGE_76_91)
{ //0x03[3:2]=01 0x07[9]=x
result &= ~(1 << 3);
result |= 1 << 2;
rda5807m_i2c_write(data->client,REG_03,result);
}
else if (range == FREQ_RANGE_76_108)
{ //0x03[3:2]=10 0x07[9]=x
result |= 1 << 3;
result &= ~(1 << 2);
rda5807m_i2c_write(data->client,REG_03,result);
}
else if (range == FREQ_RANGE_65_76)
{ //0x03[3:2]=11 0x07[9]=1
result |= 1 << 2;
result |= 1 << 3;
rda5807m_i2c_write(data->client,REG_03,result);
result = rda5807m_i2c_read(data->client,REG_07);
result |= 1 << 9;
rda5807m_i2c_write(data->client,REG_07,result);
}
else if (range == FREQ_RANGE_50_76)
{ //0x03[3:2]=11 0x07[9]=0
result |= 1 << 2;
result |= 1 << 3;
rda5807m_i2c_write(data->client,REG_03,result);
result = rda5807m_i2c_read(data->client,REG_07);
result &= ~(1 << 9);
rda5807m_i2c_write(data->client,REG_07,result);
}
}
/**
* @brief 读取频率段 band REG_03[3:2]
* #define FREQ_RANGE_87_108 0
* #define FREQ_RANGE_76_91 1
* #define FREQ_RANGE_76_108 2
* #define FREQ_RANGE_65_76 3
* #define FREQ_RANGE_50_76 4
* @return 0x0 -> FREQ_RANGE_87_108
* 0x1 -> FREQ_RANGE_76_91
* 0x2 -> FREQ_RANGE_76_108
* 0x3 -> FREQ_RANGE_65_76
* 0x4 -> FREQ_RANGE_50_76
*/
uint8_t rda5807m_read_freqrange(struct rda5807m_data_s *data)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_03);
result = (result & 0xC) >> 2;
printk("result:0x%x\n",result);
switch (result) {
case 0x0:
LOG_DBG("[%s]:read freqrange FREQ_RANGE_87_108\n",__func__);
return (uint8_t)result;
case 0x1:
LOG_DBG("[%s]:read freqrange FREQ_RANGE_76_91\n",__func__);
return (uint8_t)result;
case 0x2:
LOG_DBG("[%s]:read freqrange FREQ_RANGE_76_108\n",__func__);
return (uint8_t)result;
case 0x3:
result = rda5807m_i2c_read(data->client,REG_07);
result = (result & 0x200) >> 9;
if (result){
result = 0x3;
LOG_DBG("[%s]:read freqrange FREQ_RANGE_65_76\n",__func__);
return (uint8_t)result;
} else {
result = 0x4;
LOG_DBG("[%s]:read freqrange FREQ_RANGE_50_76\n",__func__);
return (uint8_t)result;
}
default:
LOG_ERR("[%s]:read freqrange fail\n",__func__);
return 0;
}
}
/**
* @brief 将频率转为信道值
* @param freq:频率(以MHz为单位*100)(如设置108MHz=>传入freq:10800)
* @return 信道值
* @author chenmango
*/
static uint16_t rda5807m_freqtochan(struct rda5807m_data_s *data,uint16_t freq)
{
uint16_t start = 0; //频率开始
uint16_t end = 0; //频率结束
uint16_t space = 0; //频率间隔
uint16_t band_value;
uint16_t space_value;
band_value = (rda5807m_i2c_read(data->client,REG_03) & 0x000C) >> 2; // 0x03的3,2位(波段)
if (band_value == 0 /*0b00*/)
{
start = 8700;
end = 10800;
}
else if (band_value == 1 /*0b01*/)
{
start = 7600;
end = 9100;
}
else if (band_value == 2 /*0b10*/)
{
start = 7600;
end = 10800;
}
else if (band_value == 3 /*0b11*/)
{
if ((rda5807m_i2c_read(data->client,REG_07) >> 9) & 0x01)
{
start = 6500;
end = 7600;
} else {
start = 5000;
end = 7600;
}
} else {
return 0;
}
space_value = rda5807m_i2c_read(data->client,REG_03) & 0x0003;
if (space_value == 0 /*0b00*/)
space = 10;
else if (space_value == 1 /*0b01*/)
space = 20;
else if (space_value == 2 /*0b10*/)
space = 5;
else if (space_value == 3 /*0b11*/)
space = 3;
else
return 0;
if (freq < start)
return 0;
if (freq > end)
return 0;
LOG_INFO("[%s]chan_value:0x%x\n",__func__,(freq - start) / space);
return ((freq - start) / space);
}
/**
* @brief 将信道值转为频率
* @param chan:信道值
* @return 频率(以MHz为单位*100)(如108MHz=>10800)
* @author chenmango
*/
static uint16_t rda5807m_chantofreq(struct rda5807m_data_s *data,uint16_t chan)
{
uint16_t start = 0; //频率开始
uint16_t end = 0; //频率结束
uint16_t space = 0; //频率间隔
uint16_t band_value;
uint16_t space_value;
band_value = (rda5807m_i2c_read(data->client,REG_03) & 0x000C) >> 2; // 0x03的3,2位(波段)
if (band_value == 0 /*0b00*/)
{
start = 8700;
end = 10800;
}
else if (band_value == 1 /*0b01*/)
{
start = 7600;
end = 9100;
}
else if (band_value == 2 /*0b10*/)
{
start = 7600;
end = 10800;
}
else if (band_value == 3 /*0b11*/)
{
if ((rda5807m_i2c_read(data->client,REG_07) >> 9) & 0x01)
{
start = 6500;
end = 7600;
} else {
start = 5000;
end = 7600;
}
} else {
return 0;
}
space_value = rda5807m_i2c_read(data->client,REG_03) & 0x0003;
if (space_value == 0 /*0b00*/)
space = 10;
else if (space_value == 1 /*0b01*/)
space = 20;
else if (space_value == 2 /*0b10*/)
space = 5;
else if (space_value == 3 /*0b11*/)
space = 3;
else
return 0;
space_value = start + chan * space;
if (space_value > end)
return 0;
if (space_value < start)
return 0;
return space_value;
}
/**
* @brief 设置频率值 REG_03[15:6]
* @param freq:频率(以MHz为单位*100)(如108MHz=>10800)
* @return 无
* @author chenmango
*/
static void rda5807m_set_freq(struct rda5807m_data_s *data,uint16_t freq)
{
uint16_t chan;
uint16_t temp_value;
chan = rda5807m_freqtochan(data,freq); //先转化为信道值
temp_value = rda5807m_i2c_read(data->client,REG_03);
temp_value &= 0x003F; //清空信道值
temp_value |= (chan & 0x03FF) << 6; //写入信道值
temp_value |= (1) << 4; //调频启用
rda5807m_i2c_write(data->client, REG_03, temp_value);
rda5807m_i2c_write(data->client, REG_03, temp_value);
int try_count = 0;
uint16_t stc_value = 0;
do{
stc_value = rda5807m_i2c_read(data->client, REG_0A);
stc_value &= (1 << 14);//bit14:STC
if (stc_value == 0x4000){
LOG_INFO("set freq success!\n");
return;
}
LOG_INFO("count:%d set freq wait!\n",try_count);
try_count++;
mdelay(50);
}while(try_count < 20);
LOG_ERR("set freq fail!\n");
}
/**
* @brief 读取当前频率 REG_0A[9:0]
* @param 无
* @return 频率(以MHz为单位*100)(如108MHz=>10800)
* @author chenmango
*/
uint16_t rda5807m_read_freq(struct rda5807m_data_s *data)
{
uint16_t chan = 0;
chan = rda5807m_i2c_read(data->client,REG_0A) & 0x03FF;
return rda5807m_chantofreq(data,chan);
}
/**
* @brief 设置音量 REG_05[3:0]
* @param Val:音量值(0-15)
* @return 无
* @author chenmango
*/
void rda5807m_set_volume(struct rda5807m_data_s *data,uint8_t val)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_05);
result &= 0xFFF0;
result |= (val & 0x0F);
rda5807m_i2c_write(data->client,REG_05,result);
}
/**
* @brief 读取音量 REG_05[3:0]
* @param Val:音量值(0-15)
* @return 无
* @author chenmango
*/
uint8_t rda5807m_read_volume(struct rda5807m_data_s *data)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_05);
result &= 0xF;
return (uint8_t)result;
}
/**
* @brief 设置静音 REG_02[15:14]
* @param bool:1是静音,0是解除静音
* @return 无
* @author chenmango
*/
static void rda5807m_setmute(struct rda5807m_data_s *data,uint8_t bool)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_02);
if (bool)
{
result &= ~(0x1 << 14);
}
else
{
result |= 0x1 << 14;
}
rda5807m_i2c_write(data->client,REG_02,result);
}
/**
* @brief 将输出设为空闲状态(喇叭高阻)
* @param bool:1是空闲,0是解除空闲
* @return 无
* @author chenmango
* @date 2024-07-21 23:39:07
*/
static void rda5807m_set_output_idle(struct rda5807m_data_s *data,uint8_t bool)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_02);
if (bool)
{
result &= ~(1 << 15);
}
else
{
result |= 1 << 15;
}
rda5807m_i2c_write(data->client,REG_02,result);
}
/**
* @brief 获取当前频率的信号强度
* @param 无
* @return 信号强度(0-127)
* @author chenmango
*/
uint8_t rda5807m_read_signal_intensity(struct rda5807m_data_s *data)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_0B);
result >>= 9;
return (uint8_t)result;
}
/**
* @brief 判断当前频率是否为电台
* @param 无
* @return 返回1则是电台,0则不是电台
* @author HZ12138
* @date 2022-07-21 22:22:30
*/
uint8_t rda5807m_radio_instructions(struct rda5807m_data_s *data)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_0B);
result >>= 8;
result &= 1;
return result;
}
/**
* @brief 向上搜索下一个电台(搜索完成后会设置当前频率为搜到的频率)
* @param 无
* @return 无
* @author chenmango
*/
static void rda5807m_search_freq_turnup(struct rda5807m_data_s *data)
{
uint16_t result;
result = rda5807m_i2c_read(data->client,REG_03);
result &= ~(1 << 4); //禁用调谐
rda5807m_i2c_write(data->client,REG_03,result);
result = rda5807m_i2c_read(data->client,REG_02);
result |= 1 << 9; //向上搜索
result |= 1 << 8; //开启搜索
result |= 1 << 7; //到达最高频率停止
rda5807m_i2c_write(data->client,REG_02,result);
LOG_INFO("search wait!\n");
while ((rda5807m_i2c_read(data->client,REG_0A) & 0x4000) == 0) //等待搜索完成
{
mdelay(1);
}
rda5807m_set_freq(data,rda5807m_read_freq(data)); //将搜索到频率设置为播放频率
LOG_INFO("search success!\n");
}
/**
* @brief 搜索所有电台
* @param 无
* @return 搜到的电台数量
* @author chenmango
*/
uint16_t rda5807m_search_all_freq(struct rda5807m_data_s *data)
{
uint16_t i = 0;
uint16_t band_value = 0;
uint16_t start, end;
band_value = (rda5807m_i2c_read(data->client,REG_03) & 0x000C) >> 2; // 0x03的3,2位(波段)
if (band_value == 0 /*0b00*/)
{
start = 8700;
end = 10800;
}
else if (band_value == 1 /*0b01*/)
{
start = 7600;
end = 9100;
}
else if (band_value == 2 /*0b10*/)
{
start = 7600;
end = 10800;
}
else if (band_value == 3 /*0b11*/)
{
if ((rda5807m_i2c_read(data->client,REG_07) >> 9) & 0x01)
{
start = 6500;
end = 7600;
} else {
start = 5000;
end = 7600;
}
} else {
return 0;
}
rda5807m_set_freq(data,start);
mdelay(100);
while (rda5807m_read_freq(data) != end)
{
rda5807m_search_freq_turnup(data);
mdelay(10);
RDA5807M_RadioStation_Freq[i] = rda5807m_read_freq(data);
i++;
}
mdelay(100);
if (!rda5807m_radio_instructions(data))
RDA5807M_RadioStation_Freq[--i] = 0;
LOG_INFO("rda5807m_search total stations:[%d]\n",i);
return i;
}
static uint16_t __maybe_unused rda5807m_get_chipid(struct rda5807m_data_s *data)
{
/* ic chip id 0x5804*/
return rda5807m_i2c_read(data->client,REG_00);
}
static void __maybe_unused rda5807m_reset(struct rda5807m_data_s *data)
{
rda5807m_i2c_write(data->client,REG_02,0x0002);
LOG_INFO("ic reset\n");
mdelay(100);
}
/**
* @reutrn: success: ret = 0 fail: ret < 0
*/
static int rda5807m_hwinit(struct rda5807m_data_s *data)
{
int ret = 0;
uint16_t chip_id;
chip_id = rda5807m_get_chipid(data);
LOG_INFO("chipid:[0x%x]\n",chip_id);
if(chip_id != 0x5804){
ret = -1;
return ret;
}
/* reset ic */
rda5807m_reset(data);
/* enable ic */
rda5807m_enable(data); //REG_02[1:0]->0b01
/* unmute */
rda5807m_setmute(data,0); //REG_02[14]->0b1
/* not idle */
rda5807m_set_output_idle(data, 0); //REG_02[15]->0b1
mdelay(600);
/* set freqspace */
rda5807m_set_freqspace(data,FREQ_SPACE_100KHz);//100KHz
/* set freqrange */
rda5807m_set_freqrange(data,FREQ_RANGE_87_108);//band 87-108MHz
/* set freq */
rda5807m_set_freq(data,9740); //REG_03[15:6]->freq 97.4Mhz
/* reg all dump */
rda5807m_reg_dump(data);
return ret;
}
static long rda5807m_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
uint16_t val = 0;
struct write_s {
uint8_t addr;
uint16_t val;
}write_t;
struct rda5807m_data_s *data = &rda5807m_data_t;
switch (cmd) {
case FMRX_IOCTL_SET_FREQ:
LOG_DBG("%s FMRX_IOCTL_SET_FREQ\n", __func__);
if (copy_from_user(&val, (const void __user *)arg, sizeof(val))) {
return -EFAULT;
}
rda5807m_set_freq(data,val);
break;
case FMRX_IOCTL_READ_FREQ:
LOG_DBG("%s FMRX_IOCTL_READ_FREQ\n", __func__);
val = rda5807m_read_freq(data);
if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
return -EFAULT;
}
break;
case FMRX_IOCTL_SEARCH_FREQ_TURNUP:
LOG_DBG("%s FMRX_IOCTL_SEARCH_FREQ_TURNUP\n", __func__);
rda5807m_search_freq_turnup(data);
break;
case FMRX_IOCTL_SEARCH_ALL_FREQ:
LOG_DBG("%s FMRX_IOCTL_SEARCH_ALL_FREQ\n", __func__);
val = rda5807m_search_all_freq(data);
if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
return -EFAULT;
}
break;
case FMRX_IOCTL_SET_VOLUME:
LOG_DBG("%s FMRX_IOCTL_SET_VOLUME\n", __func__);
if (copy_from_user(&val, (const void __user *)arg, sizeof(val))) {
return -EFAULT;
}
if(val > 15 || val < 0)
break;
else{
rda5807m_set_volume(data,val);
break;
}
case FMRX_IOCTL_READ_VOLUME:
LOG_DBG("%s FMRX_IOCTL_READ_VOLUME\n", __func__);
val = rda5807m_read_volume(data);
if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
return -EFAULT;
}
break;
case FMRX_IOCTL_SET_MUTE:
LOG_DBG("%s FMRX_IOCTL_SET_MUTE\n", __func__);
if (copy_from_user(&val, (const void __user *)arg, sizeof(val))) {
return -EFAULT;
}
rda5807m_setmute(data, val);
break;
case FMRX_IOCTL_SET_OUTPUT_IDLE:
LOG_DBG("%s FMRX_IOCTL_SET_OUTPUT_IDLE\n", __func__);
if (copy_from_user(&val, (const void __user *)arg, sizeof(val))) {
return -EFAULT;
}
rda5807m_set_output_idle(data, val);
break;
case FMRX_IOCTL_READ_SIGNAL_INTENSITY:
LOG_DBG("%s FMRX_IOCTL_READ_SIGNAL_INTENSITY\n", __func__);
val = rda5807m_read_signal_intensity(data);
if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
return -EFAULT;
}
break;
case FMRX_IOCTL_SET_FREQ_RANGE:
LOG_DBG("%s FMRX_IOCTL_SET_FREQ_RANGE\n", __func__);
if (copy_from_user(&val, (const void __user *)arg, sizeof(val))) {
return -EFAULT;
}
rda5807m_set_freqrange(data,val);
break;
case FMRX_IOCTL_READ_FREQ_RANGE:
LOG_DBG("%s FMRX_IOCTL_READ_FREQ_RANGE\n", __func__);
val = rda5807m_read_freqrange(data);
if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
return -EFAULT;
}
break;
case FMRX_IOCTL_SET_FREQ_SAPCE:
LOG_DBG("%s FMRX_IOCTL_SET_FREQ_SAPCE\n", __func__);
if (copy_from_user(&val, (const void __user *)arg, sizeof(val))) {
return -EFAULT;
}
rda5807m_set_freqspace(data,val);
break;
case FMRX_IOCTL_READ_FREQ_SAPCE:
val = rda5807m_read_freqspace(data);
LOG_DBG("%s FMRX_IOCTL_READ_FREQ_SAPCE\n", __func__);
if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
return -EFAULT;
}
break;
case FMRX_IOCTL_READ_ID:
LOG_DBG("%s FMRX_IOCTL_READ_ID\n", __func__);
val = rda5807m_get_chipid(data);
if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
return -EFAULT;
}
break;
case FMRX_IOCTL_PRINT_REG:
LOG_DBG("%s FMRX_IOCTL_PRINT_REG\n", __func__);
rda5807m_reg_dump(data);
break;
case FMRX_IOCTL_ENABLE:
LOG_DBG("%s FMRX_IOCTL_PRINT_REG\n", __func__);
rda5807m_enable(data);
break;
case FMRX_IOCTL_DISABLE:
LOG_DBG("%s FMRX_IOCTL_PRINT_REG\n", __func__);
rda5807m_disable(data);
break;
case FMRX_IOCTL_WRITE_REG:
LOG_DBG("%s FMRX_IOCTL_WRITE_REG\n", __func__);
if (copy_from_user(&write_t, (const void __user *)arg, sizeof(write_t))) {
return -EFAULT;
}
LOG_DBG("[%s][ioctl_write]addr:0x%x val:0x%x\n",__func__,write_t.addr,write_t.val);
rda5807m_i2c_write(data->client,write_t.addr,write_t.val);
break;
default:
rda5807m_reg_dump(data);
break;
}
return 0;
}
static int rda5807m_clk_init(struct rda5807m_data_s *data)
{
int ret = 0;
/*get clock*/
data->rda_clk = devm_clk_get(&data->client->dev,"32k_fanout");
if(data->rda_clk == NULL){
LOG_ERR("get_clk err!\n");
return -1;
}
ret = clk_prepare(data->rda_clk);
if(ret < 0){
LOG_ERR("clk prepare fail!\n");
return -2;
}
ret = clk_set_rate(data->rda_clk, data->rda_clk_rate);
if (ret) {
LOG_ERR("clk set rate fail!\n");
return -3;
}
ret = clk_enable(data->rda_clk);
if(ret < 0){
LOG_ERR("clk enable fail!\n");
return -4;
}
LOG_INFO("clk init success!\n");
return ret;
}
/**
* @brief: 获取dts资源
* @author: chenmango
*/
static void rda5807m_of_get_source(struct rda5807m_data_s *data){
/* 获取时钟标志位 是否需要单独配置时钟 1->需要 0->不需要 */
struct device_node *np = data->client->dev.of_node;
int ret = -1;
ret = of_property_read_u32(np, "clk_flag",&data->clk_flag);
if (ret) {
LOG_INFO("Failed get clk_flag from dts,set default\n");
data->clk_flag = 0;
} else {
LOG_INFO("clk_flag:%d\n",data->clk_flag);
}
if(data->clk_flag) {
/* 获取时钟频率*/
ret = of_property_read_u32(np, "rda_clk_rate",&data->rda_clk_rate);
if(ret){
LOG_INFO("Failed get rda_clk_rate from dts,set default\n");
data->rda_clk_rate = DEF_CLK_FREQ;
} else {
LOG_INFO("rda_clk_rate:%d\n",data->rda_clk_rate);
}
}
}
static const struct file_operations rda5807m_fm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = rda5807m_ioctl,
//.compat_ioctl = rda5807m_ioctl,
};
static struct miscdevice rda5807m_fm_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "rda5807m_dev",
.fops = &rda5807m_fm_fops,
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0))
static int rda5807m_probe(struct i2c_client *client)
#else
static int rda5807m_probe(struct i2c_client *client,
const struct i2c_device_id *id)
#endif
{
int ret = -1;
struct rda5807m_data_s *data = &rda5807m_data_t;
LOG_INFO("rda5807m probe\n");
data->client = client;
i2c_set_clientdata(client, data);
rda5807m_of_get_source(data);
if(data->clk_flag){
ret = rda5807m_clk_init(data);
if (ret < 0){
LOG_ERR("rda5807m clk init fail\n");
}
}
/* rda5807m init */
ret = rda5807m_hwinit(data);
if(ret < 0){
LOG_ERR("ic init fail\n");
goto OUT;
}
return ret;
OUT:
return ret;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0))
static void rda5807m_remove(struct i2c_client *client)
#else
static int rda5807m_remove(struct i2c_client *client)
#endif
{
//int result;
clk_disable_unprepare(rda5807m_data_t.rda_clk);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0))
return;
#else
return result;
#endif
}
static const struct of_device_id rda5807m_of_match[] = {
{.compatible = "rda,rda5807m"},
{},
};
static struct i2c_driver rda5807m_driver = {
.driver = {
.of_match_table = rda5807m_of_match,
.name = "rda5807m",
.owner = THIS_MODULE,
},
.probe = rda5807m_probe,
.remove = rda5807m_remove,
};
static int __init rda5807m_init(void)
{
int ret = -1;
ret = i2c_add_driver(&rda5807m_driver);
if (ret < 0) {
LOG_DBG("add rda5807m i2c driver failed\n");
return -ENODEV;
}
ret = misc_register(&rda5807m_fm_misc);
if (ret < 0) {
LOG_DBG("rda5807m misc driver register failed\n");
return -ENODEV;
}
return 0;
}
static void __exit rda5807m_exit(void)
{
LOG_DBG("remove rda5807m i2c driver.\n");
i2c_del_driver(&rda5807m_driver);
misc_deregister(&rda5807m_fm_misc);
}
MODULE_AUTHOR("de-07");
MODULE_DESCRIPTION("rda5807m Sensor driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.1.0");
module_init(rda5807m_init);
module_exit(rda5807m_exit);
2.2.2.3 测试应用源码
#include
#include
#include
#include
#include
#include
#include
/**
* @brief test fm-rx
* driver ic:rda5807m
* @author chenmango
* @version v1.1.0
* @date 2025.01.06
*/
#define FMRX_IOCTL_SET_FREQ _IOWR('s', 1, int)
#define FMRX_IOCTL_READ_FREQ _IOWR('r', 2, int)
#define FMRX_IOCTL_SEARCH_FREQ_TURNUP _IOWR('c', 3, int)
#define FMRX_IOCTL_SEARCH_ALL_FREQ _IOWR('c', 4, int)
#define FMRX_IOCTL_SET_VOLUME _IOWR('s', 5, int)
#define FMRX_IOCTL_READ_VOLUME _IOWR('r', 6, int)
#define FMRX_IOCTL_SET_MUTE _IOWR('c', 7, int)
#define FMRX_IOCTL_SET_OUTPUT_IDLE _IOWR('c', 8, int)
#define FMRX_IOCTL_READ_SIGNAL_INTENSITY _IOWR('r', 9, int)
#define FMRX_IOCTL_SET_FREQ_RANGE _IOWR('s', 10, int)
#define FMRX_IOCTL_READ_FREQ_RANGE _IOWR('r', 11, int)
#define FMRX_IOCTL_SET_FREQ_SAPCE _IOWR('s', 12, int)
#define FMRX_IOCTL_READ_FREQ_SAPCE _IOWR('r', 13, int)
#define FMRX_IOCTL_READ_ID _IOWR('r', 14, int)
#define FMRX_IOCTL_PRINT_REG _IOWR('c', 15, int)
#define FMRX_IOCTL_ENABLE _IOWR('c', 16, int)
#define FMRX_IOCTL_DISABLE _IOWR('c', 17, int)
#define FMRX_IOCTL_WRITE_REG _IOWR('s', 18, int)
struct write_s {
uint8_t addr;
uint16_t val;
}write_t;
void print_list(void)
{
// 展示可执行的ioctl操作列表给用户
printf("Available ioctl commands:\n");
printf("1. FMRX_IOCTL_SET_FREQ\n");
printf("2. FMRX_IOCTL_READ_FREQ\n");
printf("3. FMRX_IOCTL_SEARCH_FREQ_TURNUP\n");
printf("4. FMRX_IOCTL_SEARCH_ALL_FREQ\n");
printf("5. FMRX_IOCTL_SET_VOLUME\n");
printf("6. FMRX_IOCTL_SET_MUTE\n");
printf("7. FMRX_IOCTL_SET_OUTPUT_IDLE\n");
printf("8. FMRX_IOCTL_READ_SIGNAL_INTENSITY\n");
printf("9. FMRX_IOCTL_SET_FREQ_RANGE\n");
printf("10. FMRX_IOCTL_SET_FREQ_SAPCE\n");
printf("11. FMRX_IOCTL_READ_ID\n");
printf("12. FMRX_IOCTL_PRINT_REG\n");
printf("13. FMRX_IOCTL_ENABLE\n");
printf("14. FMRX_IOCTL_DISABLE\n");
printf("15. FMRX_IOCTL_WRITE_REG\n");
printf("16. FMRX_IOCTL_READ_VOLUME\n");
printf("17. FMRX_IOCTL_READ_FREQ_RANGE\n");
printf("18. FMRX_IOCTL_READ_FREQ_SAPCE\n");
printf("98. help\n");
printf("99. quit\n");
}
int main()
{
int fd;
uint16_t val = 0;
char *device_file = "/dev/rda5807m_dev";
char input[100];
int choice;
char ch;
// 打开设备文件
fd = open(device_file, O_RDWR);
if (fd < 0) {
perror("Failed to open device file");
return -1;
}
print_list();
while(1){
printf("Please enter the number corresponding to the ioctl command you want to execute: ");
fgets(input, sizeof(input), stdin);
choice = atoi(input);
val = 0;
switch (choice) {
case 1:
// 测试 FMRX_IOCTL_SET_FREQ
printf("Please enter a value for FMRX_IOCTL_SET_FREQ: \n");
fgets(input, sizeof(input), stdin);
val = (uint16_t)atoi(input);
if (ioctl(fd, FMRX_IOCTL_SET_FREQ, &val) < 0) {
perror("ioctl FMRX_IOCTL_SET_FREQ failed");
}
break;
case 2:
// 测试 FMRX_IOCTL_READ_FREQ
if (ioctl(fd, FMRX_IOCTL_READ_FREQ, &val) < 0) {
perror("ioctl FMRX_IOCTL_READ_FREQ failed");
} else {
printf("Read frequency value: 0x%x\n", val);
}
break;
case 3:
// 测试 FMRX_IOCTL_SEARCH_FREQ_TURNUP
if (ioctl(fd, FMRX_IOCTL_SEARCH_FREQ_TURNUP, NULL) < 0) {
perror("ioctl FMRX_IOCTL_SEARCH_FREQ_TURNUP failed");
}
break;
case 4:
// 测试 FMRX_IOCTL_SEARCH_ALL_FREQ
if (ioctl(fd, FMRX_IOCTL_SEARCH_ALL_FREQ, &val) < 0) {
perror("ioctl FMRX_IOCTL_SEARCH_ALL_FREQ failed");
} else {
printf("Result of FMRX_IOCTL_SEARCH_ALL_FREQ: 0x%x\n", val);
}
break;
case 5:
// 测试 FMRX_IOCTL_SET_VOLUME
printf("Please enter a value for FMRX_IOCTL_SET_VOLUME: \n");
printf("VOLUME:[0-15] enter:");
fgets(input, sizeof(input), stdin);
val = (uint16_t)atoi(input);
if (ioctl(fd, FMRX_IOCTL_SET_VOLUME, &val) < 0) {
perror("ioctl FMRX_IOCTL_SET_VOLUME failed");
}
break;
case 6:
// 测试 FMRX_IOCTL_SET_MUTE
printf("Please enter a value for FMRX_IOCTL_SET_MUTE: \n");
printf("[mute] enter 1\n");
printf("[cancel mute] enter 0\n");
fgets(input, sizeof(input), stdin);
val = (uint16_t)atoi(input);
if (ioctl(fd, FMRX_IOCTL_SET_MUTE, &val) < 0) {
perror("ioctl FMRX_IOCTL_SET_MUTE failed");
}
break;
case 7:
// 测试 FMRX_IOCTL_SET_OUTPUT_IDLE
printf("Please enter a value for FMRX_IOCTL_SET_OUTPUT_IDLE: \n");
fgets(input, sizeof(input), stdin);
val = (uint16_t)atoi(input);
if (ioctl(fd, FMRX_IOCTL_SET_OUTPUT_IDLE, &val) < 0) {
perror("ioctl FMRX_IOCTL_SET_OUTPUT_IDLE failed");
}
break;
case 8:
// 测试 FMRX_IOCTL_READ_SIGNAL_INTENSITY
if (ioctl(fd, FMRX_IOCTL_READ_SIGNAL_INTENSITY, &val) < 0) {
perror("ioctl FMRX_IOCTL_READ_SIGNAL_INTENSITY failed");
} else {
printf("Signal intensity value: 0x%x\n", val);
}
break;
case 9:
// 测试 FMRX_IOCTL_SET_FREQ_RANGE
printf("Please enter a value for FMRX_IOCTL_SET_FREQ_RANGE: \n");
printf("[FREQ_RANGE_87_108] enter 0\n");
printf("[FREQ_RANGE_76_91 ] enter 1\n");
printf("[FREQ_RANGE_76_108] enter 2\n");
printf("[FREQ_RANGE_65_76 ] enter 3\n");
printf("[FREQ_RANGE_50_76 ] enter 4\n");
fgets(input, sizeof(input), stdin);
val = (uint16_t)atoi(input);
if (ioctl(fd, FMRX_IOCTL_SET_FREQ_RANGE, &val) < 0) {
perror("ioctl FMRX_IOCTL_SET_FREQ_RANGE failed");
}
break;
case 10:
// 测试 FMRX_IOCTL_SET_FREQ_SAPCE
printf("Please enter a value for FMRX_IOCTL_SET_FREQ_SAPCE: \n");
printf("[FREQ_SPACE_100KHz] enter 0\n");
printf("[FREQ_SPACE_200KHz] enter 1\n");
printf("[FREQ_SPACE_50KHz ] enter 2\n");
printf("[FREQ_SPACE_25KHz ] enter 3\n");
fgets(input, sizeof(input), stdin);
val = (uint16_t)atoi(input);
if (ioctl(fd, FMRX_IOCTL_SET_FREQ_SAPCE, &val) < 0) {
perror("ioctl FMRX_IOCTL_SET_FREQ_SAPCE failed");
}
break;
case 11:
// 测试 FMRX_IOCTL_READ_ID
if (ioctl(fd, FMRX_IOCTL_READ_ID, &val) < 0) {
perror("ioctl FMRX_IOCTL_READ_ID failed");
} else {
printf("Chip ID value: 0x%x\n", val);
}
break;
case 12:
// 测试 FMRX_IOCTL_PRINT_REG
if (ioctl(fd, FMRX_IOCTL_PRINT_REG, NULL) < 0) {
perror("ioctl FMRX_IOCTL_PRINT_REG failed");
}
break;
case 13:
// 测试 FMRX_IOCTL_ENABLE
if (ioctl(fd, FMRX_IOCTL_ENABLE, NULL) < 0) {
perror("ioctl FMRX_IOCTL_ENABLE failed");
}
break;
case 14:
// 测试 FMRX_IOCTL_DISABLE
if (ioctl(fd, FMRX_IOCTL_DISABLE, NULL) < 0) {
perror("ioctl FMRX_IOCTL_DISABLE failed");
}
break;
case 15:
// 测试 FMRX_IOCTL_WRITE_REG
printf("Please enter [addr]: \n");
scanf("%x",&write_t.addr);
while ((ch = getchar())!= '\n');
printf("Please enter [val]: \n");
scanf("%x",&write_t.val);
while ((ch = getchar())!= '\n');
if (ioctl(fd, FMRX_IOCTL_WRITE_REG, &write_t) < 0) {
perror("ioctl FMRX_IOCTL_WRITE_REG failed");
}
break;
case 16:
// 测试 FMRX_IOCTL_READ_VOLUME
if (ioctl(fd, FMRX_IOCTL_READ_VOLUME, &val) < 0) {
perror("ioctl FMRX_IOCTL_READ_VOLUME failed");
} else {
printf("Read volume value: 0x%x\n", val);
}
break;
case 17:
// 测试 FMRX_IOCTL_READ_FREQ_RANGE
if (ioctl(fd, FMRX_IOCTL_READ_FREQ_RANGE, &val) < 0) {
perror("ioctl FMRX_IOCTL_READ_FREQ_RANGE failed");
} else {
printf("Read freq range value: 0x%x\n", val);
}
break;
case 18:
// 测试 FMRX_IOCTL_READ_FREQ_SAPCE
if (ioctl(fd, FMRX_IOCTL_READ_FREQ_SAPCE, &val) < 0) {
perror("ioctl FMRX_IOCTL_READ_FREQ_SAPCE failed");
} else {
printf("Read freq sapce value: 0x%x\n", val);
}
break;
case 98:
// help
print_list();
break;
case 99:
break;
default:
printf("Invalid choice. Please enter a valid number from the list.\n");
break;
}
}
// 关闭设备文件
close(fd);
return 0;
}