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

#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/async.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#include <linux/of_gpio.h>
#include <linux/miscdevice.h>
#include <asm/setup.h>
#include <linux/regulator/machine.h>
#include <linux/sensor-dev.h>
#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include<linux/fs.h>
#include<linux/string.h>
#include<asm/uaccess.h>
#include <dt-bindings/gpio/gpio.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/termios.h>
#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; ==== %d\n",tStep);
    ch  =  tStep ;
    printk(" ch  =  tStep ; ==== %d\n",ch);
    qn8027_fm_read(client,CH,&tCh,1);  
    printk(" ch  =  tCh ; ==== %d\n",tCh);
    ch = (ch<<8)+tCh;
    printk("(ch<<8)+tCh; ==== %d\n",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 ===================== %x\n",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 ========================= %d\n",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 =================== %d\n",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] = '\0';
    value = simple_strtol(fm_buf,NULL,10);
    printk("qn8027_write =================== fm_buf %s,count = %d,value = %d\n",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 fm\n");
        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 fm\n");
    }
    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, "%d\n",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 directory\n");
        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=%d\n",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);

RK3368 QN8027 FM发射驱动相关推荐

  1. 杰理之FM发射【篇】

    FM发射功能的驱动代码在路径-\apps\common\device\fm_emitter,该文件夹下包含了驱动代码. FM数据编码发射源代码在路径-\cpu\br23\audio_common,au ...

  2. 国产荔枝糖FPGA开发板实现FM发射

    之前在ZEDBOARD上实现了FM发射,移植到荔枝糖FPGA开发板上,运行异常,抓波形看,波形紊乱,由于最高时钟为450M,估计是荔枝糖FPGA开发板跑不了这么高,那就降频吧,降到18M果然可以发射了 ...

  3. 基于mtk平台调试FM发射芯片KT0805

    一个比较简单的i2c设备,原理图如下, 主要是供电,硬件连接好了,软件不需要处理,音频数据是接在耳机模式上AU_HPL,AU_HPR,数据芯片自己接受发射, 软件需要处理的是SW1或者SW2,连接的G ...

  4. GNURadio+HackRF小实验(FM发射与接收)

    引言:初次接触HackRF,做了些小实验,记录一下. 运行环境:Ubuntu 16.04,HackRF One 1 运行环境搭建 百度上说虚拟机不好用,为了方便我直接做了个U盘系统(不是U盘启动盘), ...

  5. FM 发射模块QN8027软件android 5.1实现分析

    FM 发射模块QN8027软件android 5.1实现分析 一,kernel层中的驱动:(主要为厂家提供,主要配置对应的I2C口线) 由三个文件组成: 1,  Makefile   /*驱动的编译文 ...

  6. c++驱动键鼠源码_Android移植FM芯片RDA5807M驱动指导

    文档说明 本文档以SC826为例(MSM8953平台,Android 7),描述如何移植FM芯片RDA5807M驱动. 移植修改 1):rdafm_drv.c rdafm_drv.h 放到kernel ...

  7. FM收音机ic FM发射模块SX6116

    原文地址::http://china.coovee.net/business1/detail/12753421.html 相关文章 1.HS6760 FM调频发射端芯片 SSOP-10封装----ht ...

  8. tl494组成的超声波发射电路_最简单无线发射电路图大全(超声波发射/射频收发电路/调频发射器) - 全文...

    最简单无线发射电路图(一):555构成的超声波发射电路 从555的3脚输出的40kHz的振荡脉冲驱动T-40-16工作,使之发射出40kHz的超声波信号.电路工作电压为9V,工作电流为40-45mA, ...

  9. Android FM模块学习之一 FM启动流程

    转自:http://blog.csdn.net/tfslovexizi/article/details/41283743 最近在学习FM模块,FM是一个值得学习的模块,可以从上层看到底层.上层就是FM ...

最新文章

  1. 【深度学习】CornerNet: 将目标检测问题视作关键点检测与配对
  2. rabbitmq 入门demo
  3. java经典程序_java经典程序编程知识(二)
  4. P3258 [JLOI2014]松鼠的新家
  5. wordpress绿色小清新运营笔记博客主题模板
  6. 校招对项目实战要求分析
  7. 最速下降法极小化rosenbrock函数 代码_典型算法思想与应用9|分支限界法与电路布线问题
  8. 你的灯还亮着吗阅读笔记之二
  9. 虚拟机安装JDK1.8
  10. C# 大华相机图像采集
  11. 网页分享接口代码格式
  12. JS逻辑运算符的与,或,非
  13. 百度竞价推广之关键词的选择策略
  14. 计算机主板 也叫系统板或母版,电脑主板与CPU常见故障维修
  15. 您可以在Windows PC或Android手机上使用iMessage吗?
  16. wo de wen jian
  17. 细胞穿透肽八精氨酸、 H2N-RRRRRRRR-OH、 148796-86-5
  18. 2017百度实习生招聘编程题
  19. EO.Web浏览器 v2023.0.18.0 for .NET -- EO.WebBrowser
  20. float型float f=3.4是否正确?

热门文章

  1. Java数据审计工具:Envers and JaVers比较
  2. 博弈论 ai 大数据开源库_需要进化:博弈论与人工智能
  3. 汽车汽配电商平台系统解决方案
  4. Netflix一位数据科学家剪出了上百部爱情片,想教AI认识“亲吻” | 国际接吻日
  5. 【职坐标】高级特性之内部类简介
  6. 实施架构一个Android项目
  7. 淘宝天猫商家运营推广,宝贝点击率、展现量有什么作用
  8. C++基础-01输入输出
  9. 软银在商业街测试自动驾驶巴士,以5公里时速往返行驶
  10. Makefile 中的subst