Msm7227-I2C设备驱动实现要点

1.               摘要

.主要介绍Msm7227平台上I2C驱动结构。

2.               介绍

Linux内核中I2C驱动包含三个层面,按调用顺序排列为:

设备驱动->I2C框架层->I2C适配器驱动

适配器驱动实现的是处理器的I2C控制器部分的驱动,包括I2C的时钟频率,各种寄存器控制和状态信息,读写实现,并提供了I2C框架层读写算法的基本接口。本文主要介绍基于I2C框架层实现一个I2C设备驱动的基本过程,并不关心具体的实现细节。

3.              I2C设备驱动实现

3.1            I2C驱动的注册与卸载

按照常规驱动注册方法实现:

static int __devinit mxt224_module_init(void)

{

int ret = 0;

printk("%s:%d\n", __FUNCTION__,__LINE__);

ret = i2c_add_driver(&mxt224_i2c_driver);/*剩下的就是实现自己的i2c_driver结构了。

return ret;

}

 

static void __exit mxt224_module_exit(void)

{     

i2c_del_driver(&mxt224_i2c_driver);     

}

module_init(mxt224_module_init);

module_exit(mxt224_module_exit);

 

3.2            struct i2c_driver

struct i2c_driver {

int id;

unsigned int class;

/*旧的驱动探测方案,新内核以不建议使用*/

int (*attach_adapter)(struct i2c_adapter *);

int (*detach_adapter)(struct i2c_adapter *);

/*旧的卸载驱动函数,已被声明为不赞成使用,使用时有警告*/

int (*detach_client)(struct i2c_client *) __deprecated;

 

/*新的设备探测接口*/

int (*probe)(struct i2c_client *, const struct i2c_device_id *);

int (*remove)(struct i2c_client *);

/*电源管理相关接口*/

void (*shutdown)(struct i2c_client *);

int (*suspend)(struct i2c_client *, pm_message_t mesg);

int (*resume)(struct i2c_client *);

 

/*一个类似于ioctl的接口*/     

int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

 

struct device_driver driver;

/*bus_type中的match回调中匹配驱动*/

const struct i2c_device_id *id_table;

 

/*设备自动探测的回调*/

int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);

const struct i2c_client_address_data *address_data;

struct list_head clients;

};

 

示例:

static struct i2c_device_id mxt224_idtable[] = {

{MT_DEVICE_NAME, 0 },

{ }

};

static struct i2c_driver mxt224_i2c_driver = {

.driver = {

       .owner    = THIS_MODULE,

       .name    =MT_DEVICE_NAME

},

.id_table = mxt224_idtable,

.probe           = mxt224_i2c_probe,

.remove         = mxt224_i2c_remove,

};

 

1.1            I2C的设备注册

设备注册即填充一个i2c_board_info结构,用于在主板初始话时构建I2C的设备链表,供I2C总线初始化时加载指定i2c的设备的驱动程序。

msm7227平台的板级初始过程在arch\arm\mach-msm\board-msm7x27.c中,

将设备信息加在static struct i2c_board_info i2c_devices[] = {}中即可。

struct i2c_board_info {

      char       type[I2C_NAME_SIZE]; /*i2c_client.name,与驱动程序的设备名保持一致*/

      unsigned short       flags;/*i2c_client.flags*/

      unsigned short       addr; /*i2c_client.addrI2C设备地址*/

      void        *platform_data;/*保存在i2c_client.dev.platform_data*/

      struct dev_archdata     *archdata;

      int          irq; /*i2c_client.irq */

};

              主要填充红色部分即可,蓝色部分可根据自己的需填充。

              Typeaddr的填充可由下面的宏完成:

#define I2C_BOARD_INFO(dev_type, dev_addr) \

.type = (dev_type), .addr = (dev_addr)

              示例:

static struct i2c_board_info i2c_devices[] = {

#ifdef CONFIG_MT9D112

   {

          I2C_BOARD_INFO("mt9d112",0x78 >> 1),/* 0x787位地址,设备地址是0x3C*/

   },

#endif

#if defined(CONFIG_M_TOUCHSCREEN_MXT224)

   {

          I2C_BOARD_INFO("mxt224", 0x4a),

   },

#endif

};

保证MT_DEVICE_NAME和“mxt224”名字是一致的,否则将无法探测设备

1.2            probe操作

I2Cprobe中要进行设备的探测,如果发现无法进入proble函数,需要检查,

1、是否注册i2c_board_info

2driver name是否和i2c_board_info中的type一致

进入probe后参数包含struct i2c_client *clientconst struct i2c_device_id *id

Client中的i2c_adapter指定了当前使用的适配器,而id则是为了区分多个设备共用一个驱动时,当前的设备id,和注册时的i2c_device_id有关。

进入probe后的第一歩操作就是检查当前适配器功能:

   if (!i2c_check_functionality(adapter,I2C_FUNC_I2C)) {

          printk("%s:%d\n", __FUNCTION__,__LINE__);

          return -ENODEV;

   }

之后要读器件信息,如:

   err = i2c_mxt224_read(client, 0, &family_id, 7);

   if ( err < 0 ) {

          printk("%s:%d,errno=%d\n", __FUNCTION__,__LINE__,err);

          goto exit;

   }

如果失败。那么该设备的探测结束,要与硬件配合检查。

之后就开始自己驱动的主要工作了,包括申请私有数据空间,初始化,中断注册等操作,或者注册一个新的其他类型的设备驱动,任君发挥了。

1.3             与设备的通信(读写寄存器)

通过系统的内建命令:

s32 i2c_smbus_read_byte(struct i2c_client *client)1byte

s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)1byte

s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)交互式读1byte

s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)交互式写1byte

s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)2byte

s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)2byte

s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,

                     u8 *values)读一个数据块,最大32byte

s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,

                      u8 length, const u8 *values)写数据块,最大32byte

 

自己封装读写函数,例:

static int i2c_mxt224_read(struct i2c_client *client, uint16_t address, uint8_t *data, uint8_t length)

{

  int retry;

  uint8_t addr[2];   

  struct i2c_msg msg[] = {

        {

               .addr = client->addr,

               .flags = 0,

               .len = 2,

               .buf = addr,

        },

        {

               .addr = client->addr,

               .flags = I2C_M_RD,

               .len = length,

               .buf = data,

        }

  };

  addr[0] = address & 0xFF;

  addr[1] = (address >> 8) & 0xFF; /*寄存器地址*/

  for (retry = 0; retry < MXT224_RETRY_COUNT; retry++) {

        if (i2c_transfer(client->adapter, msg, 2) == 2)

               break;

        mdelay(10);

  }

  if (retry == MXT224_RETRY_COUNT) {

        printk("i2c_read_block retry over %d\n",

               MXT224_RETRY_COUNT);

        return -EIO;

  }

  return 0;

}

 

static int i2c_mxt224_write(struct i2c_client *client, uint16_t address, uint8_t *data, uint8_t length)

{

  int retry, loop_i;

  uint8_t buf[length + 2];

 

  struct i2c_msg msg[] = {

        {

               .addr = client->addr,

               .flags = 0,

               .len = length + 2,

               .buf = buf,

        }

  };

  buf[0] = address & 0xFF;

  buf[1] = (address >> 8) & 0xFF;

  for (loop_i = 0; loop_i < length; loop_i++)

        buf[loop_i + 2] = data[loop_i];

  for (retry = 0; retry < MXT224_RETRY_COUNT; retry++) {

        if (i2c_transfer(client->adapter, msg, 1) == 1)

               break;

        mdelay(10);

  }

  if (retry == MXT224_RETRY_COUNT) {

        printk("i2c_write_block retry over %d\n",

               MXT224_RETRY_COUNT);

        return -EIO;

  }

  return 0;

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值