1.TEA5767FM模块
1.1简介
TEA5767是飞利浦公司出的一款集成化的收音机芯片,这是一款低功耗立体声收音IC,广泛应用于手机、MP3、MP4等便携设备,接收频率76MHz~108MHz
1.2 数据格式
1.2.1 写数据格式
位7 | 位6 | 位5 | 位4 | 位3 | 位2 | 位1 | 位0 | |
---|---|---|---|---|---|---|---|---|
数据字节1 | MUTE | SM | PLL13 | PLL12 | PLL11 | PLL10 | PLL9 | PLL8 |
数据字节2 | PLL7 | PLL6 | PLL5 | PLL4 | PLL3 | PLL2 | PLL1 | PLL0 |
数据字节3 | SUD | SSL1 | SSL0 | HISI | MS | ML | MR | SWP1 |
数据字节4 | SWP2 | STBY | BL | XTAL | SMUTE | HCC | SNC | SI |
数据字节5 | PLLREF | DTC | — | — | — | — | — | — |
1.2.2 写数据格式各符号含义
符号 | 含义 |
---|---|
MUTE | 静音控制:MUTE = 1,左右声道静音;MUTE = 0,左右声道正常 |
SM | 搜索模式:SM = 1,处于搜索模式;SM = 0,不处于搜索模式 |
PLL13-PLL0 | 设定用于搜索和预设的可编程帧率合成器 |
SUD | 搜索方向:SUD = 1,向上搜索;SUD = 0,向下搜索 |
SSL1-0 | 设定搜索标准 |
HISI | 高低边带接收:HISI = 1,设定为高边带接收;HISI = 0,设定为低边带接收 |
MS | MS = 1,设定为单声道接收;MS = 0,设定为立体声接收 |
ML | ML = 1,左声道静音并设置为立体声;ML = 0,左声道正常 |
MR | MR = 1,右声道静音并设置为立体声;MR = 0,右声道正常 |
SWP1 | 软件可编程端口:SWP1 = 1,端口1为高电平;SWP1 = 0,端口1为低电平 |
SWP2 | 软件可编程端口:SWP2 = 1,端口2为高电平;SWP2 = 0,端口2为低电平 |
STBY | 待机模式选择:STBY = 1,处于待机模式;STBY = 0,不处于待机模式 |
BL | 波段制式:BL =1,日本制式;BL = 0,中国/美国/欧洲调频制式 |
XTAL | 振荡器选择:XTAL = 1,使用13MHz晶体振荡器;XTAL = 0,使用32.768KHz晶体振荡器 |
SMUTE | 软件静音:SMUTE = 1,软件静音打开;SMUTE = 0,软件静音关闭 |
HCC | 高电平切割:HCC =1,高电平切割打开;HCC = 0,高电平切割关闭 |
SNC | 立体声噪音去除:SNC = 1,立体声噪音去除打开;SNC = 0,立体声噪音去除关闭 |
SI | 搜索标志位:SI = 1,端口1输出准备好信号;SI = 0,端口1做可编程端口用 |
PLLREF | PLLREF = 1,6.5MHz锁相环参考频率使用;PLLREF = 0,6.5MHz锁相环参考频率关闭 |
DTC | 去加重时间:DTC = 1,去加重时间为75us;DTC = 0,去加重时间为50us |
1.3 读数据格式
位7 | 位6 | 位5 | 位4 | 位3 | 位2 | 位1 | 位0 | |
---|---|---|---|---|---|---|---|---|
数据字节1 | RF | BLF | PLL13 | PLL12 | PLL11 | PLL10 | PLL9 | PLL8 |
数据字节2 | PLL7 | PLL6 | PLL5 | PLL4 | PLL3 | PLL2 | PLL1 | PLL0 |
数据字节3 | STEREO | IF6 | IF5 | IF4 | IF3 | IF2 | IF1 | IF0 |
数据字节4 | LEV3 | LEV2 | LEV1 | LEV0 | C13 | C12 | C11 | C10 |
数据字节5 | — | — | — | — | — | — | — | — |
1.3.1 读数据格式各符号含义
符号 | 含义 |
---|---|
RF | 准备好标志:RF = 1,有一个频段被搜到或已到达波段极限;RF = 0,没有频段被搜到 |
BLF | 波段极限标志:BLF = 1,已经到达搜索波段的极限 |
PLL13-0 | 当前频率的PLL值 |
STEREO | 立体声标志:STEREO = 1,接收到立体声;STEREO = 0,接收到单声道 |
IF6-0 | 中频计数器结果,正确调谐时值在31H-3EH之间 |
LEV3-0 | RF信号强度ADC输出 |
C13-0 | 芯片 |
2.TEA5767设备驱动
根据TEA5767的传输数据格式,编写对应的设备驱动
2.1 所需头文件及宏定义
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#define READY_WAIT_TIME 15000 //等待时间
#define HCC_DEFAULT 1 //高电平切割,默认打开
#define SNC_DEFAULT 1 //立体声噪音去除,默认打开
#define SEARCH_MODE_DEFAULT 2 //搜索模式
#define FORCED_MONO 0 //默认为立体声接收
#define MAX_STATION 50 //存放频率数最大为50个
#define TEA5767_DEBUG 1
2.2 TEA5767设备结构体
/* tea5767设备结构体 */
struct tea5767_dev {
struct i2c_client *client;
char name[8]; // tea5767XX
int frequency;
int mute;
int station_list[MAX_STATION];
int station_count;
u32 minstation; //最小频率,默认值为87500
u32 maxstation; //最大频率,默认值为10800
struct task_struct *scan_task; /* 进程控制 */
u8 scan_task_flag;
spinlock_t station_list_lock; /*自旋锁*/
};
2.3 主要函数
/*设置频率*/
static int tea5767_set_freq(struct i2c_client *client, int freq, int hcc,
int snc, unsigned char forcd_mono, int mute,
int standby)
{
#ifdef TEA5767_DEBUG
dev_info(&client->dev, "tea5767_set_freq is entered \n");
#endif
/* 计算寄存器内容*/
unsigned char radio[5]; // 寄存器 5个字节
unsigned char frequencyH; // 频率高字节
unsigned char frequencyL; // 频率低字节
unsigned int frequencyB;
frequencyH = 0;
frequencyL = 0;
frequencyB = 0;
frequencyB = 4 * (freq * 1000 + 225000) / 32768; //计算PLL
frequencyH = frequencyB >> 8;
frequencyL = frequencyB & 0xFF;
radio[0] = frequencyH;
if (mute)
radio[0] |= 0x80;
radio[1] = frequencyL;
radio[2] = 0xB0; //搜索设置
if (forcd_mono)
radio[2] |= 0x08;
radio[3] = 0x10; // 振荡器32.768 kHz
if (freq < 87500)
radio[3] |= 0x20;
if (hcc)
radio[3] |= 0x04;
if (snc)
radio[3] |= 0x02;
if (standby)
radio[3] |= 0x40;
radio[4] = 0x40; // 去加重时间为75us
/* i2c写入 */
if (-1 == i2c_master_send(client, radio, 5)) {
return -1;
}
#ifdef TEA5767_DEBUG
dev_info(&client->dev, "tea5767_set_freq is exited.\n");
#endif
return 0;
}
2.4 辅助函数(仅声明)
static int tea5767_get_wrapped_frequency(struct i2c_client *client, int freq);
static int tea5767_get_device_frequency(struct i2c_client *client);
static int tea5767_search(struct i2c_client *client, int dir, int mode,
int forced_mono);
static int tea5767_wait_ready(struct i2c_client *client);
static int tea5767_get_status(struct i2c_client *client, int *freq,
unsigned char *mode, unsigned char *level_adc);
static int tea5767_scan_frequencies(struct i2c_client *client, int mode,
int forced_mono);
2.5 读写sysfs设备节点方法
在/sys中生成节点,可用于应用层从驱动中获取数据,也可以直接将数据写入到驱动中
2.5.1 DEVICE_ATTR()宏定义
DEVICE_ATTR的功能就是定义一个device_attribute结构体对象
该定义为位于include/linux/device.h
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
_name : 节点名字,在sys路径下可以搜索的到
_mode : 节点权限
权限 | 含义 |
---|---|
400 | 拥有者可读,其他任何人不能进行任何操作 |
644 | 拥有者可读,但只有拥有者可以编辑 |
660 | 拥有者和组用户都可读写,其他人不能进行任何操作 |
664 | 所有人都可读,但只有拥有者和组用户可编辑 |
700 | 拥有者能够读、写和执行,其他用户不能进行任何操作 |
744 | 所有人都能读,但只有拥有者才能进行编辑和执行 |
755 | 所有人都能读和执行,但只有拥有者才能编辑 |
777 | 所有人都能读、写和执行 |
_show : 当cat命令作用于该文件时调用该函数
_store : 当echo数据到该文件时调用该函数
2.5.2驱动中的具体实现
static DEVICE_ATTR(
station, S_IWUSR | S_IRUGO, sysfs_show_station_callback,
sysfs_store_station_callback); // Create sysfs attribute "station"
static DEVICE_ATTR(mute, S_IWUSR | S_IRUGO, sysfs_show_mute_callback,
sysfs_store_mute_callback); // Create sysfs attribute "mute"
static DEVICE_ATTR(stationlist, S_IRUGO, sysfs_show_stationlist_callback,
NULL); // Create sysfs attribute "stationlist"
static DEVICE_ATTR(autoscan, S_IWUSR | S_IRUGO, NULL,
sysfs_store_autoscan_callback);
static struct attribute *tea5767_sysfs_attrs[] = {
&dev_attr_station.attr,
&dev_attr_mute.attr,
&dev_attr_stationlist.attr,
&dev_attr_autoscan.attr,
NULL,
};
/* Following creates sysfs group that will be registered and deregistered in module enter and exit. */
static struct attribute_group tea5767_sysfs_group = {
.name = "tea5767",
.attrs = tea5767_sysfs_attrs,
};