1. 云栖社区>
  2. >
  3. 正文

如何在mtk andorid6.0上添加一个I2C驱动(这里是添加一个FM 芯片驱动)

作者:用户 来源:互联网 时间:2018-09-07 15:54:29

如何在mtk andorid6.0上添加一个I2C驱动(这里是添加一个FM 芯片驱动) - 摘要: 本文讲的是如何在mtk andorid6.0上添加一个I2C驱动(这里是添加一个FM 芯片驱动), 平台:mt6737 android 6.0 #include <linux/init.h> #include <linux/module.h> //#include <stdl

平台:mt6737 android 6.0
#include <linux/init.h>
#include <linux/module.h>
//#include <stdlib.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>










static void fm_set_gpio_output(unsigned int GPIO, unsigned int output);
static unsigned int GPIO_FM_PWR_EN;
static unsigned int GPIO_SPK_PWR_EN;
#define HS6760_I2C_ID 0x18
//#define Clock_12M // Clock_7v6M//Clock_12M//Clock_24M//Clock_32v768K//选择时钟频率 

static struct i2c_client *HS6760_client = NULL;
static struct class *cls = NULL;
static unsigned int major;
static char *name = "fm_hs6760";

typedef enum 
{
hs6760_normal = 0,
hs6760_mute = 1,
hs6760_sleep = 2,
MODE_NULL
}MODE;


typedef enum
{
_75K = 0,
_50K = 1,
_22v5K = 2,
DEV_NULL
}DEV;

typedef enum
{
disable = 0,
enable = 1,
STATE_NULL
}STATE;

void HS6760_Initial(void);
void HS6760_SetFreq(uint16_t curFreq);
void HS6760_SetPow(uint8_t power);
void HS6760_Reset(void);
void HS6760_Fre_dev(DEV deviation);
void HS6760_Sel_mode(MODE mode);
void HS6760_Stereo(STATE flag);


static int Delayms(u32 data)
{
printk("delay %dms\n", data);
mdelay(data);//msleep(data);
return 0;
}


void ext_spkamp_enable(void)
{
printk(" fm  --- ext_spkamp_enable!\n");
fm_set_gpio_output(GPIO_SPK_PWR_EN , 1);
}


void ext_spkamp_disable(void)
{
printk(" fm  --- ext_spkamp_disable!\n");
fm_set_gpio_output(GPIO_SPK_PWR_EN , 0);
}


void HS6760_FM3V3_enable(void) //打开HS6760
{
printk(" fm  --- HS6760_FM3V3_enable!\n");
fm_set_gpio_output(GPIO_FM_PWR_EN, 1);
}


void HS6760_FM3V3_disable(void) //关闭HS6760
{
printk(" fm  --- HS6760_FM3V3_disable!\n");
fm_set_gpio_output(GPIO_FM_PWR_EN, 0);
}


static int HS6760_i2c_read(u8 reg)
{
unsigned char val[1] = {0};
int ret = 0;
val[0] = reg;
ret = i2c_master_send(HS6760_client, val, 1);
if (ret < 0) 
{
printk(" fm  --- HS6760_i2c_read I2C i/o error ret = %d\n", ret);
return ret;
}
mdelay(10);
ret = i2c_master_recv(HS6760_client, val, 1);
if (ret < 0) 
{
printk(" fm  --- HS6760_i2c_read I2C read error ret = %d\n", ret);
return ret;
}
return val[0];
}


static int HS6760_i2c_write(u8 reg, u8 writedata)
{
u8 databuf[2] = {0};
int ret = 0;
databuf[0] = reg;
databuf[1] = writedata;
ret = i2c_master_send(HS6760_client, databuf, 2);
printk(" fm  --- HS6760_i2c_write ret=%d, databuf[0]=%d, databuf[1]=%d\n", ret, databuf[0], databuf[1]);
if(ret < 0)
{
printk(" fm  --- HS6760_i2c_write send data failed !\n");
return -1;
}
return ret;
}


void HS6760_Initial(void)
{
uint8_t RegData;

#ifdef Clock_24M
RegData = 0x36; //PGA12dB,24M晶振
printk(" fm  ---HS6760 : HS6760_Initial Clock_24M !!\n");
#else

#ifdef Clock_12M
RegData = 0x34; //PGA12dB,12M晶振
printk(" fm  ---HS6760 : HS6760_Initial Clock_12M !!\n");
#else


#ifdef Clock_7v6M
RegData = 0x32; //PGA为12dB,7.6M晶振
printk(" fm  ---HS6760 : HS6760_Initial Clock_7v6M !!\n");
#else


#ifdef Clock_32v768K
RegData = 0x30; //PGA为12dB,32.768K晶振
printk(" fm  ---HS6760 : HS6760_Initial Clock_32v768K !!\n");
#endif
#endif
#endif
#endif


printk(" fm  ---HS6760 : HS6760_Initial !!\n");
HS6760_i2c_write(0x02,RegData);
Delayms(10);

RegData = 0x06;
HS6760_i2c_write(0x01,RegData); // normal模式
Delayms(10);

HS6760_Stereo(enable); //开启立体声
HS6760_SetPow(31); //设置功率最大
}


void HS6760_Reset(void)
{
uint8_t Data8;


printk(" fm  ---HS6760 : HS6760_Reset !!\n");

/*使PA发射功率生效*/
Data8 = HS6760_i2c_read(0x07);
Data8 &= 0x7f;
HS6760_i2c_write(0x07,Data8); 
Delayms(10);
Data8 |= 0x80;
HS6760_i2c_write(0x07,Data8); 
}


/**************************************************         
Function: HS6760_SetFreq()
Parameter: 
curFreq: FM frequency *10 ,such as  1017,933,1077..                                      


Description:
set FM to a frequency 80-1080M Hz
**************************************************/ 
char buffer [33]; //用于存放转换好的十六进制字符串,可根据需要定义长度
 
char * inttohex(int aa)
{
    static int i = 0;
    if (aa < 16)            //递归结束条件 
    {
        if (aa < 10)        //当前数转换成字符放入字符串 
            buffer[i] = aa + '0';
        else
            buffer[i] = aa - 10 + 'A';
        buffer[i+1] = '\0'; //字符串结束标志 
    }
    else
    {
        inttohex(aa / 16);  //递归调用 
        i++;                //字符串索引+1 
        aa %= 16;           //计算当前值
        if (aa < 10)        //当前数转换成字符放入字符串 
            buffer[i] = aa + '0';
        else
            buffer[i] = aa - 10 + 'A';
    }
    return (buffer);
}






void HS6760_SetFreq(uint16_t curFreq)
{
uint8_t cy1;
uint8_t cy0;
uint16_t curChan;


uint8_t Data8;
uint8_t TmpData8[2];
 printk("curFreq is %d add to HS6760_SetFreq\n",curFreq);
curChan = curFreq*2;

printk("curChan is %x add to HS6760_SetFreq\n",curChan);

TmpData8[0] = curChan>>8; //取高8位
TmpData8[1] = curChan&0xff; //取低8位

//TmpData8[0] = 0x06; //取高8位   6D8
//TmpData8[1] = 0xd8; //取低8位
printk("TmpData8[0] is %x add to HS6760_SetFreq\n",TmpData8[0]);
printk("TmpData8[1] is %x add to HS6760_SetFreq\n",TmpData8[1]);


HS6760_i2c_write(0x00,TmpData8[1]);
Delayms(10);

Data8 = HS6760_i2c_read(0x01);
// printk("0x01 is %x add to HS6760_SetFreq\n",Data8);
TmpData8[0] = TmpData8[0]|(Data8&0xc0);
HS6760_i2c_write(0x01,TmpData8[0]);
Delayms(10);


  cy0 = HS6760_i2c_read(0x00);
  cy1 = HS6760_i2c_read(0x01);
  
  printk("cy0 is %x add to HS6760_SetFreq\n",cy0);
  printk("cy1 is %x add to HS6760_SetFreq\n",cy1);

/*使写入的频点生效 */
Data8 =  HS6760_i2c_read(0x02);
printk("0x02 is %x add to HS6760_SetFreq\n",Data8);
Data8 &= 0xfe; //最低位置0
HS6760_i2c_write(0x02,Data8);
Delayms(10);

Data8 |= 0x01; //最高位置1
HS6760_i2c_write(0x02,Data8);
Delayms(10);
}


/**************************************************         
Function: HS6760_SetPower(uint8_t power)
Parameter: power=1~31 (Decimalism)
curFreq: FM power  dBm ,such as  1、2、…… 31                               


Description:
set FM to a Power
**************************************************/ 
void HS6760_SetPow(uint8_t power)
{
uint8_t Data8;


printk(" fm  ---HS6760 : HS6760_SetPow !!\n");
Data8 = HS6760_i2c_read(0x07);  
printk(" fm  --- HS6760 : HS6760_SetPow read(0x07)=%d !!\n", Data8);

Data8 &= 0xe0; //把低5位清零
Data8 += power;
HS6760_i2c_write(0x07,Data8); 
HS6760_Reset(); //复位HS6760芯片
}


void HS6760_start(void)
{  
   printk(" fm  ---HS6760 : HS6760_start !!\n");
HS6760_Initial(); //初始化HS6760
//HS6760_SetFreq(905); //设置频点为90.5M Hz
HS6760_SetPow(31); //设置功率最大
HS6760_Fre_dev(_22v5K); //设置频偏为22.5K Hz
HS6760_Stereo(enable); //开启立体声
}


/**************************************************         
Function: HS6760_Sel_mode(MODE mode)
Parameter: mode=normal/mute/sleep;                          
Description:
set FM to a work mode 
**************************************************/ 
void HS6760_Sel_mode(MODE mode)
{
uint8_t Data8;

switch (mode)
{
case hs6760_normal: //最高两位设为 00'b
Data8 = HS6760_i2c_read(0x01); 
Data8 &= 0x3f;
break;

case hs6760_mute: //最高两位设为 01'b
Data8 = HS6760_i2c_read(0x01); 
Data8 &= 0x3f;
Data8 |= 0x40;
break;

case hs6760_sleep: //最高两位设为 10'b
Data8 = HS6760_i2c_read(0x01); 
Data8 &= 0x3f;
Data8 |= 0x80;
break;

default:
break;
}
HS6760_i2c_write(0x01,Data8);

if(mode == hs6760_normal) //(注:A3版不需要此操作)
{
HS6760_Reset(); //复位HS6760芯片
}
}

/**************************************************         
Function: HS6760_Fre_dev(DEV deviation)
Parameter: deviation=_75K/_50K/_22v5K;                          
Description:
set HS6760  frequency deviation 
**************************************************/ 
void HS6760_Fre_dev(DEV deviation)
{
uint8_t Data8;

Data8 = HS6760_i2c_read(0x03);
Data8 &= 0xfc; //最低两位设为 00'b

printk(" fm  ---HS6760 : HS6760_Fre_dev HS6760_Fre_dev= !!\n");
switch (deviation)
{
case _75K:
break;
case _50K:
Data8 += 0x01;
break; //最低两位设为 01'b
case _22v5K:
Data8 += 0x02;
break; //最低两位设为 10'b
default:
break;
}
HS6760_i2c_write(0x03,Data8); 
}


/**************************************************         
Function: HS6760_Stereo(STATE flag)
Parameter: flag=enable/disable;                          
Description:
set HS6760  Stereo mode or mono mode. 
**************************************************/ 
void HS6760_Stereo(STATE flag)
{
uint8_t Data8;

Data8 = HS6760_i2c_read(0x03);
printk(" fm  ---HS6760 : HS6760_Stereo enable read(0x0c)=%d !!\n", Data8);
if(flag)
{
Data8 |= 0x80;
printk(" fm  ---HS6760 : HS6760_Stereo enable !!\n");
}
else
{
Data8 &= 0x7f;
printk(" fm  ---HS6760 : HS6760_Stereo disable !!\n");
}
HS6760_i2c_write(0x03,Data8); 
}

/************************************************************/
static int HS6760_open(struct inode *inode, struct file *file)
{
printk(" fm  ---HS6760 open:: %s\n", __func__);

//HS6760_Initial();
return 0;
}


static int HS6760_release(struct inode *inode, struct file *file)
{
printk(" fm  --- HS6760 release:: %s\n", __func__);
return 0;
}






static long HS6760_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    void __user *dat;
    int cydat1[2] = {0,0};
    // int cydat1 = 0;
    switch(cmd)
        {
          case 1:
          {
          
dat = (void __user *) arg;
//strcpy(pinf.model,"S19");
    cydat1[0] = HS6760_i2c_read(0x00);
 
    cydat1[1] = HS6760_i2c_read(0x02);

//pinf.id=19;
copy_to_user(dat, cydat1, sizeof(cydat1));
            break; 
          }
         
          default:break;
         }
   

//printk(" fm  --- qn8027_ioctl : cmd = %d\n", cmd);
return 0;
}


ssize_t HS6760_read(struct file *fp, char __user *buf, size_t count, loff_t * off)
{
printk("  fm  --- HS6760 read:: %s\n", __func__);
return 0;
}


ssize_t HS6760_write(struct file *fp, const char __user *buf, size_t count, loff_t *off)
{
int data[2] = {0,0}; /* cmd, data*/
int freq;

/*这里是从用户空间传递过来的频率*/
copy_from_user(data, buf, sizeof(data));

printk("  fm  --- HS6760 write:: %s, data[0] = %d, data[1] = %d \n\r", __func__, data[0], data[1]);


switch(data[0])
{
case 0: //hs6760_open:
printk("  fm  --- hs6760_open:: %s\n", __func__);

//HS6760_Reset();
HS6760_FM3V3_enable(); //打开HS6760
ext_spkamp_disable(); //关闭机器功放输出
HS6760_start();
HS6760_Sel_mode(hs6760_normal);
break;


case 1: //hs6760_silent_mode:
printk("  fm  --- hs6760_silent_mode:: %s\n", __func__);

HS6760_FM3V3_enable(); //打开HS6760
ext_spkamp_disable(); //关闭机器功放输出
HS6760_Sel_mode(hs6760_mute);
break;

case 2: //hs6760_close:
printk("  fm  --- hs6760_close:: %s\n", __func__);

HS6760_Sel_mode(hs6760_sleep);
HS6760_FM3V3_disable(); //关闭HS6760
ext_spkamp_enable(); //打开机器功放输出
break;

case 9: //设置频率
freq = data[1];


printk("  fm  --- hs6760_set freq:: freq = %d, %s\n", freq, __func__);


/*这里调用设置频率的函数*/
HS6760_SetFreq(freq);

break;
}

return 0;
}


static struct file_operations HS6760_fops = {
.owner = THIS_MODULE,
.open = HS6760_open,
.read = HS6760_read,
.write = HS6760_write,
.release = HS6760_release,
.unlocked_ioctl = HS6760_ioctl,
};


static int HS6760_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret;
printk(" fm  --- HS6760 probe:: %s\n", __func__);


HS6760_client = client;
HS6760_client->addr = HS6760_I2C_ID;


// 1. register character device
major = register_chrdev(0, name, &HS6760_fops);    //向内核注册一个设备,返回值为注册的主设备号
if(major < 0)
{
printk("<xxxx> register_chrdev(probe) failed\n");
goto out1;
}

// 2. class create
cls = class_create(THIS_MODULE, name);      //注册一个类,使mdev可以在"/dev/"目录下 面建立设备节点
if(IS_ERR(cls))
{
printk("<xxxx> class create failed\n");
goto out2;
}


// 3. device create
device_create(cls, NULL, MKDEV(major, 0), NULL, name);  //创建一个设备节点,节点名为name




HS6760_FM3V3_enable(); //打开HS6760

HS6760_start(); //初始化


return 0;


out2:
unregister_chrdev(major, name);


out1:
return -1;
}


static int HS6760_remove(struct i2c_client *client)
{
printk(" fm  ---HS6760 remove:: %s\n", __func__);



device_destroy(cls, MKDEV(major, 0));
class_destroy(cls);
unregister_chrdev(major, name);


return 0;
}


static const struct i2c_device_id HS6760_ids[] = {
{ "fm_hs6760", 0 },
{  }
};


#ifdef CONFIG_OF
static const struct of_device_id FM_HW_i2c_of_ids[] = {
    { .compatible = "mediatek,ext_speaker_amp", },
{}
};
#endif
static struct i2c_driver HS6760_driver = {
.driver = {
.name = "fm_hs6760",
.owner = THIS_MODULE,


#ifdef CONFIG_OF
.of_match_table = FM_HW_i2c_of_ids,
#endif
},
.probe = HS6760_probe,
.remove = HS6760_remove,
.id_table = HS6760_ids,
};






void fm_get_gpio_infor(void)
{
static struct device_node *node;


node = of_find_compatible_node(NULL, NULL, "mediatek,c66_fm");
if (!node) {

printk("Failed to find device-tree node: rm_hs6760\n");
return -ENODEV;
}
GPIO_FM_PWR_EN = of_get_named_gpio(node, "fm_power_gpio", 0);
GPIO_SPK_PWR_EN = of_get_named_gpio(node, "spk_power_gpio", 0);



}


static void fm_set_gpio_output(unsigned int GPIO, unsigned int output)
{

gpio_direction_output(GPIO, output);
gpio_set_value(GPIO, output);
}


static int fm_probe(struct device *dev)
{


printk(" fm  ---HS6760 fm_probe\n");
fm_get_gpio_infor();



return i2c_add_driver(&HS6760_driver);
}


static const struct of_device_id fm_of_ids[] = {
{.compatible = "mediatek,c66_fm",},
{}
};
static struct platform_driver fm_driver = {
.driver = {
   .name = "c66_fm",
   .owner = THIS_MODULE,
   .probe = fm_probe,
#ifdef CONFIG_OF
   .of_match_table = fm_of_ids,
#endif
   },
};
static int __init HS6760_init(void)
{
printk(" fm  ---HS6760 module_init()\n");
if (platform_driver_register(&fm_driver)) {
pr_err("LCM: failed to register disp driver\n");
return -ENODEV;
}


return 0;
}


/*----------------------------------------------------------------------------*/
static void __exit HS6760_exit(void)
{
}


/*----------------------------------------------------------------------------*/
MODULE_DESCRIPTION("Fm Register Driver");
MODULE_LICENSE("GPL");


module_init(HS6760_init);
module_exit(HS6760_exit);




MODULE_AUTHOR("mediatek");



以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索,以便于您获取更多的相关知识。