1. 程式人生 > >linux設備驅動(3)I2C驅動

linux設備驅動(3)I2C驅動

eric without this flags res 創建 sig pri 數據傳輸

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 \n");
    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;
}

linux設備驅動(3)I2C驅動