• linux设备驱动(3)I2C驱动


    i2c驱动程序的核心是创建i2c_driver结构体

    /* This is the driver that will be inserted */
    static struct i2c_driver at24cxx_driver = {
        .driver = {
            .name    = "at24cxx",
        },
        .id        = I2C_DRIVERID_AT24Cxx,
        .attach_adapter    = at24cxx_attach_adapter,
        .detach_client    = at24cxx_detach_client,
    };

    再at24cxx_attach_adapter里面

    static int at24cxx_attach_adapter(struct i2c_adapter *adapter)
    {
        return i2c_probe(adapter, &addr_data, at24cxx_detect);
    }

    当probe到设备后, at24cxx_detect会被调用

    这里有两个需要完成的

    (1) 配置addr_data

    (2)at24cxx_detect

    对于addr_data

    /*
     * Generic i2c probe
     * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
     */
    static unsigned short normal_i2c[] = {
        0x50,                         /* 7位地址 */
        I2C_CLIENT_END,
    };
    
    static unsigned short ignore = I2C_CLIENT_END;
    
    static struct i2c_client_address_data addr_data = {
        .normal_i2c        = normal_i2c,
        .probe            = &ignore,
        .ignore            = &ignore,
    };

    而在 at24cxx_detect中主要有

    (1) 设置一个i2c_client 结构体变量

    (2) 设置它

    (3) 注册

    首先创建全局i2c_client变量

    static struct i2c_client *at24cxx_client;
    static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind)
    {
        printk(KERN_INFO "at24cxx_detect 
    ");
        int err = 0;
    
        /* 分配  */ 
        at24cxx_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
    
        /* 设置 */
        at24cxx_client->addr = address;
        at24cxx_client->adapter = adapter;
        at24cxx_client->driver = &at24cxx_driver;
        at24cxx_client->flags = 0;
        
        /* Fill in the remaining client fields */
        strlcpy(at24cxx_client->name, "at24cxx", I2C_NAME_SIZE);
    
        /* Tell the I2C layer a new client has arrived */
        if ((err = i2c_attach_client(at24cxx_client)))
            goto exit_kfree;
    
    
    exit_kfree:
        kfree(at24cxx_client);
        
        return err;
    }

    i2c设置好了, 数据传输使用i2c_transfer

    int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)

    因此, 数据传送是需要构造设置msg

    与用户程序交互的读:

    static int at24cxx_read (struct file *file, char __user *usrbuf, size_t len, loff_t *offset)
    {
        /*
        * buf[0]   addr
        * buf[1]   data
        */
        int ret;
        unsigned char address;
        unsigned char data;
    
        struct i2c_msg msg[2];
    
        if(len != 2)
            return -EFAULT;
    
        if(copy_from_user(&address, usrbuf, 1))
            res = -EFAULT;
    
        /* i2c 传输 */
        /* 先发送地址 */
        msg[0].addr = at24cxx_client->addr;   // dest
        msg[0].buf = &address;                // src
        msg[0].flags = 0;                     // write
        msg[0].len = 1;                       // len
    
        /* 再读 */
        msg[1].addr = at24cxx_client->addr;   // dest
        msg[2].buf = &data;                   // src
        msg[1].flags = I2C_M_RD;                     // read
        msg[1].len = 1;                       // len
        
        ret = i2c_transfer(at24cxx_client->adapter, msg, 2);
        if(ret == 2)
        {
            if(copy_to_user(&usrbuf, &data, 1))
                res = -EFAULT;
            return 1;
        }        
        else
            return -EIO;
        
        
        
        return 0;
    }

    写:

    static int at24cxx_write (struct file *file, const char __user *usrbuf, size_t len, loff_t *offset)
    {
        /*
        * buf[0]   addr
        * buf[1]   data
        */
        int ret;
        unsigned char buf[2];
        struct i2c_msg msg[1];
    
        if(len != 2)
            return -EFAULT;
    
        if(copy_from_user(buf, usrbuf, 2))
            res = -EFAULT;
    
        /* i2c 传输 */
        msg[0].addr = at24cxx_client->addr;   // dest
        msg[0].buf = buf;                     // src
        msg[0].flags = 0;                     // write
        msg[0].len = 2;                       // len
        ret = i2c_transfer(at24cxx_client->adapter, msg, 1);
        if(ret == 1)
            return 2;
        else
            return -EIO;
    }
  • 相关阅读:
    Android服务器——TomCat服务器的搭建
    Ubuntu16.04 Liunx下同时安装Anaconda2与Anaconda3
    android中代码操作外部SD卡出错:W/System.err(1595): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
    查准率与查全率(precision and recall) 的个人理解
    Python游戏-实现键盘控制功能
    UGUI世界坐标转换为UI本地坐标(游戏Hud的实现)
    LoadRunner中遭遇交互数据加密的处理方案
    [Java]链表的打印,反转与删除
    优化程序性能(3)——提高并行性
    基本排序算法的python实现
  • 原文地址:https://www.cnblogs.com/hulig7/p/9901760.html
Copyright © 2020-2023  润新知