自学内容网 自学内容网

(RK3566驱动开发 - 2).IIC驱动

一.设备树

(1).流程图

(2).设备树代码

二.驱动代码部分

(1).流程图

(2).驱动代码

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "oledfont.h"


#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>


#define OLED_CNT    1
#define OLED_NAME   "oled"


#define OLED_CMD    0X00    //OLED 写命令
#define OLED_DATA   0X40    //OLED 写数据

#define Max_Column  128     //OLED 的 x方向的像素个数


//IIC从用户控件接收的数据格式
struct display_stru 
{
    int  x;             //x坐标
    int  y;             //y坐标
    char *buf;          //接收数据缓冲区
};



/* 设备结构体 */
struct oled_dev
{
    dev_t devid;            /* 设备号 */
    struct cdev cdev;       /* cdev */
    struct class *class;    /* 类 */
    struct device *device;  /* 设备 */
    struct device_node *nd; /* 设备结点 */
    int major;              /* 主设备号 */

    void *private_data;     /* 私有数据 */
};

/* OLED 设备 */
struct oled_dev oleddev;


/**
 * @description:            向 OLED 写入若干个字节的数据
 * @param - dev     :       OLED 设备
 * @param - reg     :       寄存器首地址
 * @param - buf     :       要写入的数据缓冲区
 * @param - len     :       要写入的字节数
 * @return          :       成功则返回(发送的 msg 数量),失败则返回(负值) 
 */
static s32 oled_write_regs(struct oled_dev *dev,u8 reg,u8 *buf,int len)
{
    u8 b[256] = {};
    struct i2c_msg msg;
    struct i2c_client *client = (struct i2c_client *)dev->private_data;

    b[0] = reg;                 //填充寄存器的首地址
    memcpy(&b[1],buf,len);      //填充要写入的数据

    msg.addr = client->addr;    //OLED 设备
    msg.buf = b;
    msg.flags = 0;              //表示为写数据
    msg.len = len + 1;          //数据长度 = 1个字节的寄存器首地址 + 要写入的数据长度

    return i2c_transfer(client->adapter,&msg,1);
}


/**
 * @description:            向 OLED 写入单个字节的数据
 * @param - dev     :       OLED 设备
 * @param - reg     :       寄存器首地址
 * @param - data    :       要写入的单个字节的数据
 * @return          :       成功则返回(发送的 msg 数量),失败则返回(负值)
 */
static s32 oled_write_reg(struct oled_dev *dev,u8 reg,u8 data)
{
    u8 buf = data;

    return oled_write_regs(dev,reg,&buf,1);
}


/**
 * @description:            oled 初始化
 * @param           :       无
 * @return          :       无
 */
void oled_init(void)
{
    int ret;
    u8 i = 0;
    u8 data[] ={ 0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6,
 
                 0xA8, 0x3F, 0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05,
 
                 0xD9, 0xF1, 0xDA, 0x12, 0xDB, 0x30, 0x8D, 0x14, 0xAF };
 
    for(i = 0 ; i < sizeof(data) ; i++)
    {
        ret = oled_write_reg(&oleddev,OLED_CMD,data[i]);
    }
}
 
 
 
/**
 * @description:            oled 清屏
 * @param           :       无
 * @return          :       无 
 */
void oled_clear(void)
{
    u8 i,n;
 
    for(i = 0 ; i < 8 ; i++)
    {
        oled_write_reg(&oleddev,OLED_CMD,0XB0+i);               //设置页地址
        oled_write_reg(&oleddev,OLED_CMD,0x00);                 //设置显示位置-列低地址
        oled_write_reg(&oleddev,OLED_CMD,0x10);                 //设置显示位置-列高地址
    }
 
    for(n = 0 ; n < 128 ; n++)
    {
        oled_write_reg(&oleddev,OLED_DATA,0x00);
    }
}
 
 
/**
 * @description:            设置 OLED 某个点
 * @param - x       :       x坐标
 * @param - y       :       y坐标
 * @return          :       无
 */
void oled_set_pos(u8 x, u8 y)
 
{  
 
    oled_write_reg(&oleddev,OLED_CMD, 0xb0 + y);
 
    oled_write_reg(&oleddev,OLED_CMD, ((x & 0xf0) >> 4) | 0x10);
 
    oled_write_reg(&oleddev,OLED_CMD, x & 0x0f);
 
}
 
 
 
/**
 * @description:            oled 显示单个字符
 * @param - x           :   x坐标
 * @param - y           :   y坐标
 * @param - chr         :   要显示的字符
 * @return              :   无
 */
void oled_showchar(u8 x, u8 y, u8 chr)
 
{     
    u8 c=0, i=0;
 
    c = chr - ' ';                    
 
    if(x > Max_Column-1)
 
    {
       x = 0;
       y = y + 2;
    }
 
    oled_set_pos(x, y);
 
    for(i=0; i<8; i++)
 
    {
       oled_write_reg(&oleddev,OLED_DATA, F8X16[c*16+i]);
    }
 
    oled_set_pos(x,y+1);
 
    for(i=0; i<8; i++)
 
    {
       oled_write_reg(&oleddev,OLED_DATA, F8X16[c*16+i+8]);  
    }
 
}
 
 
 
/**
 * @description:            oled显示字符串
 * @param - x       :       x坐标
 * @param - y       :       y坐标
 * @param - chr     :       字符串首地址
 * @return          :       无
 */
void oled_showstring(u8 x, u8 y, u8 *chr)
 
{
    unsigned char j=0;
 
    while(chr[j] != '\0')
    {     
       oled_showchar(x, y, chr[j]);
       x += 8;
 
       if(x > 120)
 
       {
           x = 0;
           y += 2;
       }
       j++;
    }
}




/**
 * @description:            open 函数
 */
static int oled_open(struct inode *inode,struct file *filp)
{
    filp->private_data = &oleddev;

    /* 初始化 OLED */
    oled_init();
    oled_clear();

    return 0;
}



/**
 * @description:            write 函数
 */
static ssize_t oled_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt)
{
    /* 可根据用户空间传进来的 buf , 自行编写对应的逻辑实现 */
    oled_showstring(0,0,"hello");

    return 0;
}


/**
 * @description:            release 函数
 */
static int oled_release(struct inode *inode,struct file *filp)
{
    return 0;
}



/* 绑定设备操作函数 */
static const struct file_operations fops = 
{
    .open = oled_open,
    .write = oled_write,
    .release = oled_release,
};



/**
 * @description:            probe 函数
 */
static int oled_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
    dev_err(oleddev.device,"enter oled_probe\r\n");

    /* 1.创建设备号 */
    if(oleddev.major)
    {
        oleddev.devid = MKDEV(oleddev.major,0);
        register_chrdev_region(oleddev.devid,OLED_CNT,OLED_NAME);
    }
    else
    {
        alloc_chrdev_region(&oleddev.devid,0,OLED_CNT,OLED_NAME);
        oleddev.major = MAJOR(oleddev.devid);
    }

    /* 2.注册cdev */
    cdev_init(&oleddev.cdev,&fops);
    cdev_add(&oleddev.cdev,oleddev.devid,OLED_CNT);

    /* 3.创建类 */
    oleddev.class = class_create(THIS_MODULE,OLED_NAME);
    if(IS_ERR(oleddev.class))
    {
        return PTR_ERR(oleddev.class);
    }

    /* 4.创建设备 */
    oleddev.device = device_create(oleddev.class,NULL,oleddev.devid,NULL,OLED_NAME);
    if(IS_ERR(oleddev.device))
    {
        return PTR_ERR(oleddev.device);
    }

    oleddev.private_data = client;


    return 0;
}


/**
 * @description:            remove 函数
 */
static int oled_remove(struct i2c_client *client)
{   
    dev_err(oleddev.device,"enter oled_remove\r\n");

    /* 1.注销字符设备驱动 */
    cdev_del(&oleddev.cdev);
    unregister_chrdev_region(oleddev.devid,OLED_CNT);

    /* 2.注销类和设备 */
    device_destroy(oleddev.class,oleddev.devid);
    class_destroy(oleddev.class);
    

    return 0;
}


/* 无设备树时的匹配方式 - ID列表 */
static const struct i2c_device_id oled_id[] = 
{
    {"oled_test",0},
    {},
};


/* 设备树下的匹配方式 - 匹配列表 */
static const struct of_device_id oled_of_match[] = 
{
    {.compatible = "oled_test"},
    {},
};


/* i2c 驱动结构体 */
static struct i2c_driver oled_driver = 
{
    .probe  = oled_probe,
    .remove = oled_remove,
    .driver = 
    {
        .owner = THIS_MODULE,
        .name = "oled",
        .of_match_table = oled_of_match,
    },
    .id_table = oled_id,
};



/**
 * @description:            驱动入口函数
 */
static int __init oled_module_init(void)
{
    return i2c_add_driver(&oled_driver);
}



/**
 * @description:            驱动出口函数
 */
static void __exit oled_module_exit(void)
{
    i2c_del_driver(&oled_driver);
}


module_init(oled_module_init);
module_exit(oled_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kaneki");



原文地址:https://blog.csdn.net/kaneki_lh/article/details/143832683

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!