如何在mtk andorid6.0上添加一个I2C驱动(这里是添加一个FM 芯片驱动)
2017-09-21 11:20
561 查看
平台: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_ID0x18
//#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_3
101ee
2v768K
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");
#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_ID0x18
//#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_3
101ee
2v768K
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");
相关文章推荐
- 如何把一个自己写的外部驱动模块编译添加到内核中 来自网络
- 如何添加一个新的LCD驱动
- 如何用数据驱动实现通用化巡检APP(如何一个界面里添加多个点击拍照按钮并显示在不同的imageview里)
- 如何在mtk kernel中新添加一个摄像头驱动
- 如何在mtk kernel中新添加一个摄像头驱动
- ExtJs中如何动态添加一个textfield的文本框
- 如何实现在一个ScrollView里添加多个ListView,并且让ListView伸张到最长。
- django序列化时如何添加一个customer filed NOT in my model?
- 如何在RCP程序中添加一个banner栏
- linux下如何添加一个用户并且让用户获得root权限
- 【技术支持】如何添加OV9650 camera驱动到FL2440 wince系统中
- 如何实现在TreeView中添加一个删除的按钮
- 如何添加串口2和串口3的驱动
- 如何在niosII中添加i2c外设_winday_新浪博客
- 如何给JavaScript添加一个自定义对象
- ideal中如何添加几个不同的项目在同一个idea页面显示(同一个窗口显示多个工程)
- 如何添加一个cocos2d-x精灵
- Flex中如何利用titleIcon属性给Panel容器标题部添加一个ICON图标的例子
- qt4:如何给按钮添加一个图标
- 如何建立一个基于事件驱动的全自动化交易系统