I2C驱动框架(kernel-2.6.22.6)

以用i2c通信的实时时钟为例

框架入口源文件:i2c_m41t11.c

(可根据入口源文件,再按着框架到内核走一遍)

内核版本:linux_2.6.22.6   硬件平台:JZ2440


以下是驱动框架:


以下是驱动代码 i2c_m41t11.c :

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/fs.h>



static unsigned short normal_i2c[] = {0x68,I2C_CLIENT_END}; //只有七位   0xd0 >> 1
static unsigned short probe[] = {I2C_CLIENT_END};
static unsigned short ignore[] = {I2C_CLIENT_END};

//定义一个 client 地址数据
static struct i2c_client_address_data addr_data =
{
    .normal_i2c = normal_i2c,
    .probe      = probe,
    .ignore     = ignore, 
};

//定义 client 
static struct i2c_client *i2c_m41t11_client;

//定义 主设备号
static int major;

//定义一个 i2c 字符驱动
static struct i2c_driver i2c_m41t11_driver;

static ssize_t i2c_m41t11_read(struct file *file, char __user *buf, size_t size, loff_t * offset)
{
  printk(" <========= this is m41t11 RTC chip =========>  
");
  return 0;
}


static ssize_t i2c_m41t11_write(struct file *file, const char __user *buf, size_t size, loff_t * offset)
{
    printk(" <========== this is m41t11 RTC chip =========> 
");
    return 0;
}


//定义字符操作函数
static struct file_operations i2c_m41t11_fops =
{
   .owner = THIS_MODULE,
   .read  = i2c_m41t11_read,
   .write = i2c_m41t11_write,
};



//定义一个字符设备类
static struct class *i2c_m41t11_class;


//匹配处理函数
static int m41t11_match_fun(struct i2c_adapter* adpater,int addr ,int kind)
{
   printk("match m41t11 RTC chip successfully 
"); 
   //初始化 client 结构体
   i2c_m41t11_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
   i2c_m41t11_client->adapter =  adpater;
   i2c_m41t11_client->driver = &i2c_m41t11_driver;
   i2c_m41t11_client->addr   = addr;
   strcpy(i2c_m41t11_client->name, "i2c_m41t11_client");
   i2c_attach_client(i2c_m41t11_client);

   //注册字符设备
    major = register_chrdev(0,"i2c_m41t11", &i2c_m41t11_fops); 
 
    i2c_m41t11_class = class_create(THIS_MODULE,"i2c_m41t11_class");                     //   /sys/class/i2c_m41t11_class
    class_device_create(i2c_m41t11_class, NULL, MKDEV(major, 0), NULL,"i2c_m41t11_dev"); //   /dev/i2c_m41t11_dev
    return 0;
}


static int i2c_m41t11_attach(struct i2c_adapter *adapter)
{

   printk("trying to match  m41t11 RTC chip 
");

  return   i2c_probe( adapter , &addr_data , m41t11_match_fun );
} 

static int i2c_m41t11_detach(struct i2c_client *client)
{
    printk("delect  m41t11 RTC chip 
");
   //字符设备
    unregister_chrdev(major, "i2c_m41t11");
    class_destroy(i2c_m41t11_class);
    class_device_destroy(i2c_m41t11_class,MKDEV(major, 0));
       
    //client
    i2c_detach_client(client);
    kfree(i2c_get_clientdata(client));    
    return 0;
}

//初始化 i2c_m41t11_driver
static struct i2c_driver i2c_m41t11_driver =
{
    .driver = { .name = "i2c_m41t11", },
    .attach_adapter = i2c_m41t11_attach,
    .detach_client  = i2c_m41t11_detach,
};


static int i2c_m41t11_init(void)
{
    i2c_add_driver(&i2c_m41t11_driver);
    return 0;
}


static void i2c_m41t11_exit(void)
{
   i2c_del_driver(&i2c_m41t11_driver);
}
    

module_init(i2c_m41t11_init);
module_exit(i2c_m41t11_exit);

MODULE_LICENSE("GPL");

 注:

        匹配分为三个个步骤
   1. 用驱动的i2c_driver.driver.name与物理设备名字匹配,成功则调用 i2c_driver.attach_adapter。

   2. i2c_driver.attach_adapter中用i2c_probe(adapter,addr,match_func)匹配适配器与物理设备,成功则调用 match_func。

   3. match_func中创建 i2c_client,将 i2c_driver 与 i2c_adapter 联系起来。


以下是编译驱动的Makefile:

KER_DIR=/work/systems/kernel/linux-2/linux-2.6.22.6
all:
make -C $(KER_DIR) M=`pwd` modules
clean:
make -C $(KER_DIR) M=`pwd` modules clean
rm -fr modules.order

obj-m += i2c_m41t11.o

原文地址:https://www.cnblogs.com/zsy12138/p/10392810.html