一个比较简单的i2c设备,原理图如下,
主要是供电,硬件连接好了,软件不需要处理,音频数据是接在耳机模式上AU_HPL,AU_HPR,数据芯片自己接受发射,
软件需要处理的是SW1或者SW2,连接的GPIO,选择不同的频率,简单就是拉高就ok了,硬件已经选择了。然后通过i2c设置FM发射频率。
1、需要给上层提供几个接口,开启和关闭功能,即耳机插入和拨出一样,还有一个就是设置频率功能。
这三个接口都可以通过sys文件系统或者proc文件系统来操作。在使用sys/class文件系统进行echo操作时,居然不能够输入数据,没有搞明白mtk平台为啥不行,我在高通,展讯平台都是可以的,奇怪了,后来只有使用proc文件系统进行echo输入数据。
再到平台相应的关机耳机部分的驱动,在probe中
#ifdef FM_ACCDET_TX//
device_create_file(accdet_nor_device, &dev_attr_fmtransmitter);
//device_create_file(accdet_nor_device, &dev_attr_fmtransmitterfrq);
_create_procfs();
#endif
#ifdef FM_ACCDET_TX
static void accdet_fmtx_enable()
{
//set PWM IDLE on
pmic_pwrap_write(ACCDET_STATE_SWCTRL, (pmic_pwrap_read(ACCDET_STATE_SWCTRL)|ACCDET_SWCTRL_IDLE_EN));
//enable ACCDET unit
enable_accdet(ACCDET_SWCTRL_EN);
}
//static ssize_t store_fmtx_disable(struct device_driver *ddri, char *buf, size_t count)
static ssize_t show_fmtx_enable(struct device_driver *ddri, char *buf)
{
//set PWM IDLE on
pmic_pwrap_write(ACCDET_STATE_SWCTRL, (pmic_pwrap_read(ACCDET_STATE_SWCTRL)|ACCDET_SWCTRL_IDLE_EN));
//enable ACCDET unit
enable_accdet(ACCDET_SWCTRL_EN);
}
static ssize_t store_fmtx_disable(struct device_driver *ddri, char *buf, size_t count)
//static ssize_t show_fmtx_enable(struct device_driver *ddri, char *buf)
//static ssize_t store_fmtx_disable(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)
//static void store_fmtx_disable()
{
accdet_auxadc_switch(0);
disable_accdet();
headset_plug_out();
}
int KTTX_FRQ;
extern int KT_Bus_Read(kal_uint8 addr, kal_uint8 *returnData);
extern int KT_Bus_Write(kal_uint8 addr, kal_uint8 writeData);
void KT_TXTune (int Frequency) // Exemple :91.55MHz---> *Freqency = 9155;
{
char reg1,reg2;
char aa;
Frequency = Frequency / 5;
KT_Bus_Write( 0x00, (Frequency & 0x01FE) >>1);
//reg1 = KT_Bus_Read( 0x01);
KT_Bus_Read( 0x01,®1);
printk("======KT_TXTune===reg1=%x\n",reg1);
aa=(reg1 & 0xF8 ) | ((Frequency & 0x0E00) >> 9);
printk("======KT_TXTune===aa=%x\n",aa);
KT_Bus_Write( 0x01, (reg1 & 0xF8 ) | ((Frequency & 0x0E00) >> 9) );
//reg2 = KT_Bus_Read( 0x02);
KT_Bus_Read( 0x01,®2);
printk("======KT_TXTune===reg2=%x,Frequency=%x\n",reg2,Frequency);
if ( Frequency & 0x0001) // if frequency = XX.X5 MHz
{
KT_Bus_Write( 0x02, reg2 | 0x80);
}
else
{
KT_Bus_Write( 0x02, reg2 & 0x7F);
}
}
int strtoint(const char *str,int len)
{
int result = 0;
int i = 0;
char c;
while(i <= len-1)
{
c = str[i++];
if(c<'0' || c>'9')
break;
result = 10*result + c - '0';
}
return result;
}
static char *_copy_from_user_for_proc(const char __user *buffer, size_t count)
{
char *buf = (char *)__get_free_page(GFP_USER);
if (!buf)
return NULL;
if (count >= PAGE_SIZE)
goto out;
if (copy_from_user(buf, buffer, count))
goto out;
buf[count] = '\0';
return buf;
out:
free_page((unsigned long)buf);
return NULL;
}
static DEVICE_ATTR(fmtransmitter,0777, show_fmtx_enable, store_fmtx_disable);
//static DEVICE_ATTR(fmtransmitterfrq,0777, show_fmtxfrq, store_fmtxfrq);
static int accdet_fmtx_proc_show(struct seq_file *m, void *v)
{
printk("accdet_fmtx_proc_show=====cpufreq debug (log level) KTTX_FRQ= %d\n", KTTX_FRQ);
return 0;;
}
static ssize_t accdet_fmtx_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
{
unsigned int dbg_lv;
char *buf = _copy_from_user_for_proc(buffer, count);
if (!buf)
return -EINVAL;
sscanf(buf, "%d", &dbg_lv);
printk("========accdet_fmtx_proc_write======dbg_lv=%d\n",dbg_lv);
KTTX_FRQ=dbg_lv;
KT_TXTune(dbg_lv);
free_page((unsigned int)buf);
return count;
}
#define PROC_FOPS_RW(name) \
static int name ## _proc_open(struct inode *inode, struct file *file) \
{ \
return single_open(file, name ## _proc_show, NULL); \
} \
static const struct file_operations name ## _proc_fops = { \
.owner = THIS_MODULE, \
.open = name ## _proc_open, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release, \
.write = name ## _proc_write, \
}
#define PROC_ENTRY(name) {__stringify(name), &name ## _proc_fops}
PROC_FOPS_RW(accdet_fmtx);
static int _create_procfs(void)
{
struct proc_dir_entry *dir = NULL;
//struct proc_dir_entry *cpu_dir = NULL;
//struct mt_cpu_dvfs *p = id_to_cpu_dvfs(0);
int i; //, j;
struct pentry {
const char *name;
const struct file_operations *fops;
};
const struct pentry entries[] = {
PROC_ENTRY(accdet_fmtx),
};
dir = proc_mkdir("accdetfmtx", NULL);
if (!dir) {
printk("fail to_create_procfs------------create /proc/accdetfmtx @ %s()\n", __func__);
return -ENOMEM;
}
for (i = 0; i < ARRAY_SIZE(entries); i++) {
proc_create(entries[i].name, S_IRUGO | S_IWUSR | S_IWGRP, dir, entries[i].fops);
printk("%s(), create --------------/proc/accdetfmtx/%s failed\n", __func__, entries[i].name);
}
return 0;
}