I2C linux设备驱动程序,在Petalinux上运行并在Zedboard上运行

时间:2016-10-28 20:28:53

标签: linux driver i2c bus

我已经阅读了有关编写I2C客户端(写入客户端)的Linux文档,并使用了此博客链接http://renjucnair.blogspot.in/2012/01/writing-i2c-driver.html以及我能找到的其他资源。我正在尝试使用SM-Bus接口访问设备并使用用于标准字符驱动程序的文件操作访问设备文件,如此I2C device linux driver问题的答案中的第三种类型所示。我正在尝试与磁力计HMC5883l进行通信。我最后写了下面的代码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>


#define REG_CONF_A 0x00 
#define REG_CONF_B 0x01
#define REG_MODE 0x02
#define REG_FIELD_X_LSB 0x03
#define REG_FIELD_X_MSB 0x04
#define REG_FIELD_Y_LSB 0x05
#define REG_FIELD_Y_MSB 0x06
#define REG_FIELD_Z_LSB 0x07
#define REG_FIELD_Z_MSB 0x08
#define REG_STATUS 0x09
#define REG_ID_A 0x0A
#define REG_ID_B 0x0B
#define REG_ID_C 0x0C

static char c = 's';

static dev_t first;
static struct cdev c_dev; 
static struct class *cl;
static struct i2c_client *client;

static const struct i2c_device_id hmc5883l_id[] = {
    { "hmc5883l", 0 },
    { }
};

MODULE_DEVICE_TABLE(i2c, hmc5883l_id);

static const struct of_device_id hmc5883l_of_match[] = {
    { .compatible = "honeywell,hmc5883l", .data = 0 },
    {}
};
MODULE_DEVICE_TABLE(of, hmc5883l_of_match);

static struct i2c_driver hmc5883l_driver = {
    .driver = {
    .owner      = THIS_MODULE,
    .name       = "hmc5883l",
    .of_match_table = hmc5883l_of_match,
    },
    .id_table   = hmc5883l_id
};

static int hmc5883l_open(struct inode *i, struct file *f)
{
    printk(KERN_INFO "Driver: open()\n");
    return 0;
}
static int hmc5883l_release(struct inode *i, struct file *f)
{
    printk(KERN_INFO "Driver: close()\n");
    return 0;
}

static ssize_t hmc5883l_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{

    struct i2c_adapter *my_adap = i2c_get_adapter(0); 
    client = i2c_new_dummy(my_adap, 0x1e);

    printk(KERN_INFO "Driver: read()\n");
    if (*off == 0) 
    {
    i2c_smbus_write_byte_data(client, 0x0a, 0);
    c = i2c_smbus_read_byte(client);
    copy_to_user(buf,&c,1); 
    (*off)++;
    return 1;   
    }
    else  
    return 0;
}

static const struct file_operations hmc5883l_fops = {
    .owner      = THIS_MODULE,
    .read       = hmc5883l_read,
    .open       = hmc5883l_open,
    .release    = hmc5883l_release,
};


static int __init hmc5883l_init(void)
{
    int ret;
    struct device *dev_ret;

    printk(KERN_INFO "Namaskar: mmeter driver registered");
    if ((ret = alloc_chrdev_region(&first, 0, 1, "Shweta")) < 0)
    {
        return ret;
    }
    if (IS_ERR(cl = class_create(THIS_MODULE, "chardrv")))
    {
        unregister_chrdev_region(first, 1);
        return PTR_ERR(cl);
    }
    if (IS_ERR(dev_ret = device_create(cl, NULL, first, NULL, "mynull")))
    {
        class_destroy(cl);
        unregister_chrdev_region(first, 1);
        return PTR_ERR(dev_ret);
    }

    cdev_init(&c_dev, &hmc5883l_fops); //this is the step of initializing the character driver.

    if ((ret = cdev_add(&c_dev, first, 1)) < 0)
    {
        device_destroy(cl, first);
        class_destroy(cl);
        unregister_chrdev_region(first, 1);
        return ret;
    }

    return i2c_add_driver(&hmc5883l_driver);
}

static void __exit hmc5883l_exit(void)
{
    i2c_del_driver(&hmc5883l_driver);
    cdev_del(&c_dev);
    device_destroy(cl, first);
    class_destroy(cl);
    unregister_chrdev_region(first, 1);
    printk(KERN_INFO "Alvida: mmeter driver unregistered");

}


module_init(hmc5883l_init);
module_exit(hmc5883l_exit);

MODULE_AUTHOR("Shubham Sharma");
MODULE_DESCRIPTION("Mmeter Driver");
MODULE_LICENSE("GPL");

我还在设备树中进行了必要的添加,如下所示:

/dts-v1/;
/include/ "system-conf.dtsi"
/ {
    amba: amba {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <1>;
        interrupt-parent = <&intc>;
        ranges;
i2c0: i2c@e0004000 {
            compatible = "cdns,i2c-r1p10";
            status = "okay";
            clocks = <&clkc 38>;
            interrupt-parent = <&intc>;
            interrupts = <0 25 4>;
            reg = <0xe0004000 0x1000>;
            #address-cells = <1>;
            #size-cells = <0>;

hmc5883l@1e {
        compatible = "honeywell,hmc5883l";
        reg = <0x1e>;
};
};
};

};

此代码在我的笔记本电脑上编译,以下是在Zedboard上的petalinux上安装驱动程序时运行以下命令时得到的输出。

root@I2C:~# i2cdetect -r -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1e -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --



root@I2C:/dev# cat mynull
Driver: open()
i2c i2c-0: Failed to register i2c client dummy at 0x1e (-16)
Driver: read()
Unable to handle kernel NULL pointer dereference at virtual address 00000002
pgd = 5d898000
[00000002] *pgd=1e4aa831, *pte=00000000, *ppte=00000000
Internal error: Oops - BUG: 17 [#1] PREEMPT SMP ARM
Modules linked in: ipv6 mmeter_driver(O)
CPU: 1 PID: 982 Comm: cat Tainted: G           O   3.19.0-xilinx #19
Hardware name: Xilinx Zynq Platform
task: 5e46f180 ti: 5e4f2000 task.ti: 5e4f2000
PC is at i2c_smbus_write_byte_data+0x8/0x3c
LR is at hmc5883l_read+0x48/0xb4 [mmeter_driver]
pc : [<40332068>]    lr : [<3f000078>]    psr: 600d0013
sp : 5e4f3f10  ip : 00000000  fp : 00000001
r10: 00000000  r9 : 5e4f2000  r8 : 4000dee4
r7 : 3ec43c60  r6 : 3f000628  r5 : 3ec43c60  r4 : 5e4f3f88
r3 : 00000000  r2 : 00000000  r1 : 0000000a  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 18c5387d  Table: 1d89804a  DAC: 00000015
Process cat (pid: 982, stack limit = 0x5e4f2238)
Stack: (0x5e4f3f10 to 0x5e4f4000)
3f00:                                     5e4f2000 00000000 00000001 4004f0cc
3f20: 3f0003c9 5e4f3f44 00000000 4046fa08 3f0003c9 5e4f3f44 5e4f3f88 3f00005c
3f40: 3f0003c9 5ebef000 0000000a 3f000078 3ec43c60 5e65be80 5e4f3f88 400b9fe4
3f60: 5e65be80 3ec43c60 00001000 5e65be80 5e65be80 00001000 3ec43c60 4000dee4
3f80: 5e4f2000 400ba08c 00000000 00000000 00001000 000aba18 00001000 3ec43c60
3fa0: 00000003 4000dd60 000aba18 00001000 00000003 3ec43c60 00001000 01000000
3fc0: 000aba18 00001000 3ec43c60 00000003 00000003 00000001 00000000 00000001
3fe0: 00000000 3ec43c44 00011a68 36e8125c 600d0010 00000003 00000000 00000000
[<40332068>] (i2c_smbus_write_byte_data) from [<3f000078>] (hmc5883l_read+0x48/0xb4 [mmeter_driver])
[<3f000078>] (hmc5883l_read [mmeter_driver]) from [<400b9fe4>] (vfs_read+0x84/0xec)
[<400b9fe4>] (vfs_read) from [<400ba08c>] (SyS_read+0x40/0x80)
[<400ba08c>] (SyS_read) from [<4000dd60>] (ret_fast_syscall+0x0/0x34)
Code: e28dd03c e49df004 e52de004 e24dd03c (e1d0c0b2) 
---[ end trace 7a4ba311ad6063f0 ]---
Driver: close()
Segmentation fault

我无法理解我所犯的错误。任何帮助将受到高度赞赏。感谢。

P.S。 :这是我的第一个问题,所以如果我发布的方式问题不对,我很抱歉,我会再提供详细信息。

0 个答案:

没有答案