瑞芯微Rockchip开发者社区
直播中

莫联雪

7年用户 1075经验值
私信 关注
[问答]

RK3368 QN8027 FM发射驱动代码该怎样去实现呢

RK3368 QN8027 FM发射驱动代码该怎样去实现呢?

回帖(1)

姜钰

2022-2-10 14:35:43
之前在做车机相关项目,有FM发射需求,8027这颗芯片,之前大部分都是在单片机使用,很少在linux系统使用,我把他移植成了linux驱动,以下为参考:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "QN8027.h"
#define QN8027_I2C_NAME     "QN8027"
#define QN8027_I2C_ADDR     0x58
#define QN8027_DEV_NAME        "QN8027"
static int qn8027_fm_write(struct i2c_client *client, u8 addr, u8 *pdata, int datalen);
static int qn8027_fm_read(struct i2c_client *client, u8 addr, u8 *pdata, unsigned int datalen);
void  QNF_SetRegBit(struct i2c_client *client,u8 reg, u8 bitMask, u8 data_val) ;
u16  QNF_GetCh(struct i2c_client *client) ;
void QN_ChipInitialization(struct i2c_client *client);
UINT8 QNF_SetCh(struct i2c_client *client,u16 freq) ;
void QN_ChipInitialization(struct i2c_client *client);
static struct i2c_client *Gol_client;
struct proc_dir_entry *qn8027_extend_dir;
extern void es8316_spk_ctrl(int level);
static int qn8027_fm_write(struct i2c_client *client, u8 addr, u8 *pdata, int datalen)
{
    int ret = 0;
    u8 tmp_buf[128];
    unsigned int bytelen = 0;
    if (datalen > 125)
    {
        printk("%s too big datalen = %d!n", __func__, datalen);
        return -1;
    }
   
    tmp_buf[0] = addr;
    bytelen++;
   
    if (datalen != 0 && pdata != NULL)
    {
        memcpy(&tmp_buf[bytelen], pdata, datalen);
        bytelen += datalen;
    }
   
    ret = i2c_master_send(client, tmp_buf, bytelen);
    return ret;
}
static int qn8027_fm_read(struct i2c_client *client, u8 addr, u8 *pdata, unsigned int datalen)
{
    int ret = 0;
    if (datalen > 126)
    {
        printk("%s too big datalen = %d!n", __func__, datalen);
        return -1;
    }
    ret = qn8027_fm_write(client, addr, NULL, 0);
    if (ret < 0)
    {
        printk("%s set data address fail!n", __func__);
        return ret;
    }
    return i2c_master_recv(client, pdata, datalen);
}
void QNF_SetRegBit(struct i2c_client *client,u8 reg, u8 bitMask, u8 data_val)
{
    u8 temp;
    int ret;
    ret= qn8027_fm_read(client,reg,&temp,sizeof(temp));
    temp &= (u8)(~bitMask);
    temp |= data_val & bitMask;
       qn8027_fm_write(client, reg, &temp, 1);
}
UINT8 QNF_SetCh(struct i2c_client *client,u16 freq)
{
    // calculate ch parameter used for register setting
    UINT8 tStep;
    UINT8 tCh;
    UINT16 f;
        f = FREQ2CHREG(freq);
        // set to reg: CH
        tCh = (UINT8) f;
        qn8027_fm_write(client,CH, &tCh,1);
        // set to reg: CH_STEP
        qn8027_fm_read(client,CH_STEP,&tStep,1);
        tStep &= ~CH_CH;
        tStep |= ((UINT8) (f >> 8) & CH_CH);
        qn8027_fm_write(client,CH_STEP, &tStep,1);
    return 1;
}
u16 QNF_GetCh(struct i2c_client *client)
{
    u8 tCh;
    u8  tStep;
    u16 ch = 0;
    // set to reg: CH_STEP
     qn8027_fm_read(client,CH_STEP,&tStep,1);
    tStep &= CH_CH;
    printk("Step &= CH_CH; ==== %dn",tStep);
    ch  =  tStep ;
    printk(" ch  =  tStep ; ==== %dn",ch);
    qn8027_fm_read(client,CH,&tCh,1);  
    printk(" ch  =  tCh ; ==== %dn",tCh);
    ch = (ch<<8)+tCh;
    printk("(ch<<8)+tCh; ==== %dn",ch);
    return CHREG2FREQ(ch);
}
void QN_ChipInitialization(struct i2c_client *client)
{
   
    u8 write_buf;
    u8 read_buf;
    int ret = 0;
    //write_buf = 0x81;
    //ret = qn8027_fm_write(client, 0x00, &write_buf, 1);
    //msleep(200);
    write_buf = 0x20;
    ret = qn8027_fm_write(client, 0x03, &write_buf, 1);
     msleep(200);   
    write_buf = 0x21;
    ret = qn8027_fm_write(client, 0x04, &write_buf, 1);
      msleep(200);   
    QNF_SetRegBit(client,0x00,0x40,0x40);
    msleep(200);               //delay 20 ms
       write_buf = 0xe4;
    ret = qn8027_fm_write(client, 0x18, &write_buf, 1);
    msleep(200);      
    write_buf = 0xf0;
    qn8027_fm_write(client, 0x1b, &write_buf, 1);
    msleep(200);  
    write_buf = 0xB9;
    ret = qn8027_fm_write(client, 0x02, &write_buf, 1);
     msleep(200);      
    write_buf = 0x20;
    ret = qn8027_fm_write(client, 0x00, &write_buf, 1);
   
    ret= qn8027_fm_read(client,0x00,&read_buf,sizeof(read_buf));
    printk("intqn8027_fm_read ===================== %xn",read_buf);
}
static int  qn8027_fm_probe(struct i2c_client *client,
            const struct i2c_device_id *id)
{
    int ch;
    int ret = 0;
    u8 write_buf;
    QN_ChipInitialization(client);
    ch = QNF_GetCh(client);
    Gol_client = client;
    printk("qn8027  ch ========================= %dn",ch);
    return 0;
   
}
static int qn8027_fm_remove(struct i2c_client *client)
{
    printk("qn8027_fm_remove ========================= n");
    return 0;
}
static int qn8027_open(struct inode *inode, struct file *file)
{
    return nonseekable_open(inode, file);
}
static int qn8027_release(struct inode *inode, struct file *file)
{
    return 0;
}

static ssize_t qn8027_read(struct file *file,  char __user * usr_buf, size_t len, loff_t * f_pos)
{
    int ch = 0;
    ch = QNF_GetCh(Gol_client);
    copy_to_user(usr_buf,&ch,1);
    printk("qn8027_read =================== %dn",ch);
    return 0;
}
static ssize_t qn8027_write(struct file *file, const char __user * usr_buf, size_t len, loff_t * f_pos){
   
    char fm_buf[40];
    copy_from_user(&fm_buf,usr_buf,len);
    QNF_SetCh(Gol_client,10000);
    printk("qn8027_write ===================n");
    return len;
}
static ssize_t qn8027_proc_write(struct file *file, const char __user *usr_buf,
                    size_t count, loff_t *pos){
                        
    char fm_buf[40];
    int value;
    char write_buf;
    copy_from_user(&fm_buf,usr_buf,count);
    fm_buf[count] = '';
    value = simple_strtol(fm_buf,NULL,10);
    printk("qn8027_write =================== fm_buf %s,count = %d,value = %dn",fm_buf,count,value);
   
    if(value > 0)// set fm rate
    {
        es8316_spk_ctrl(0);// trun off spk
        write_buf = 0x10;
        qn8027_fm_write(Gol_client, 0x03, &write_buf, 1);
        msleep(200);   
        write_buf = 0x11;
         qn8027_fm_write(Gol_client, 0x04, &write_buf, 1);
        msleep(200);   
        printk("hxl ===============turn off fmn");
        QNF_SetCh(Gol_client,value);
    }
    else // turn off fm
    {
        es8316_spk_ctrl(1);// trun on spk
        write_buf = 0x00;
        qn8027_fm_write(Gol_client, 0x03, &write_buf, 1);
        msleep(200);   
        write_buf = 0x00;
        qn8027_fm_write(Gol_client, 0x04, &write_buf, 1);
        msleep(200);   
        printk("hxl ===============turn off fmn");
    }
    return count;               
}
static int qn8027_proc_read(struct file *file, char *usr_buf,
                        size_t count, loff_t *pos){                        
   
    printk("qn8027_read =================== n");
    return 0;                        
}
static int qn8027_proc_show(struct seq_file *m, void *v)
{
    int val = 0;
    val = QNF_GetCh(Gol_client);
    seq_printf(m, "%dn",val);
    printk("qn8027_proc_show ......n");
    return 0;
}

static int qn8027_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, qn8027_proc_show, NULL);
}
static struct file_operations qn8027_fops = {
    .owner        = THIS_MODULE,
    .open        = qn8027_open,
    .release    = qn8027_release,
    //.unlocked_ioctl        = qn8027_ioctl,
    .write = qn8027_write,
    .read = seq_read,
};
static const struct i2c_device_id qn8027_id[] = {
    {QN8027_I2C_NAME, 0},
    {}
};
MODULE_DEVICE_TABLE(i2c, qn8027_id);
static struct i2c_driver qn8027_fm_driver = {
    .driver = {
        .name = QN8027_I2C_NAME,
        .owner = THIS_MODULE,
    },
    .probe        = qn8027_fm_probe,
    .remove        = qn8027_fm_remove,
    .id_table    = qn8027_id,
};
static const struct file_operations qn8027_extend_fops = {
    .owner        = THIS_MODULE,
    .open        = qn8027_proc_open,
    .read        = seq_read,
    .llseek        = seq_lseek,
    .release    = single_release,
    .write        = qn8027_proc_write,
};

static int __init qn8027_fm_init(void)
{
    int ret;
    int ent;
    printk("==qn8027_fm_init==n");
    qn8027_extend_dir = proc_mkdir("QN8027", NULL);
    if(qn8027_extend_dir == NULL)
    {
        printk("unable to creat /proc/QN8027 directoryn");
        return -ENOMEM;
    }
   
    ent = proc_create("rw_data", 0666, qn8027_extend_dir, &qn8027_extend_fops);
    if(ent == NULL)
    {
        printk("unable to create /proc/QN8027/rw_data entry");
        //goto fail;
    }
    ret = i2c_add_driver(&qn8027_fm_driver);
    printk("ret=%dn",ret);
    return ret;
}
static void __exit qn8027_fm_exit(void)
{
    printk("==qn8027_fm_exit==n");
    i2c_del_driver(&qn8027_fm_driver);
    return;
}
module_init(qn8027_fm_init);
module_exit(qn8027_fm_exit);
举报

更多回帖

发帖
×
20
完善资料,
赚取积分