一. 简介
- 来源:应项目需求,需将3个I2c和6个GPIO封装成一个驱动供上层应用层调用,遂有了此文。
- 开发板:Halley2
- Linux版本:3.10.14
- 开发环境:Manhattan(基于君正官方提供的开发环境,很好用)。
- 经验:说实话,这是我第一个“正经”开发的驱动。
二. 编写驱动前的准备
- 先明确需求,3个I2c的设备地址和片上内存都为一个字节,6个Gpio分别为5输入1输出
- 留给上层接口的选择,刚开始在read/write上琢磨,但是总觉得这样操作好啰嗦,后来受应用层操作I2c的方式的影响,就索性自定义一个结构体用ioctl来传参了,虽操作也是有点啰嗦,但能接受,Bingo。
- 网上搜索相关资料,了解到驱动里使用I2c的一些基操,见本文最后的参考文章。
三. 头文件的编写
- 留给上层使用的结构体,因需求的原因,一切从简,只支持单字节读写,自己可扩展
- 一些关于器件的宏定义,由ioctl函数参数的第二个参数指定
struct sakway_msg_t{
#define SAKWAY_I2C_MSG_WRITE 0
#define SAKWAY_I2C_MSG_READ 1
int rw_flag;
short chip_addr;
unsigned char wmsg;
unsigned char index;
unsigned char * rmsg;
};
#define SAKWAY_CMD_DRV_TEMP 0
#define SAKWAY_CMD_DRV_MCUG 1
#define SAKWAY_CMD_DRV_MCUF 2
#define SAKWAY_CMD_GPIO_GET 3
#define SAKWAY_CMD_GPIO_SET 4
四. 源文件的编写
#define I2C_TEMP_ADDR 0x48
#define I2C_MCUG_ADDR 0x34
#define I2C_MCUF_ADDR 0x38
typedef struct sakway_t SAKWAY;
struct sakway_hw_t{
unsigned int io_in[5];
unsigned int io_out;
unsigned int io[0];
int i2c_id;
#define SAKWAY_I2C_ID_CPLD 0u
#define SAKWAY_I2C_ID_MCUG 1u
#define SAKWAY_I2C_ID_MCUF 2u
struct i2c_client *i2c_clit[3];
struct i2c_adapter *i2c_adper;
struct i2c_driver *i2c_drv;
};
struct sakway_t{
SAKWAY *this;
struct sakway_hw_t *hw;
struct mutex lock;
unsigned int majoy_id;
};
static int __sakway_write_reg(SAKWAY* this, short reg_addr,unsigned char reg_value){
char write_buf[4];
int status;
struct i2c_msg msg =
{
this->hw->i2c_clit[this->hw->i2c_id]->addr, 0, 2, write_buf
};
memset(write_buf, 0, 4);
write_buf[0] = reg_addr&0x00ff;
write_buf[1] = reg_value;
msg.len = 2;
mutex_lock(&(this->lock));
status = i2c_transfer(this->hw->i2c_adper, &msg, 1);
mutex_unlock(&(this->lock));
return (status == 1)? 0 : -1;
}
static int __sakway_read_reg(SAKWAY* this, short reg_addr,unsigned char *reg_value){
char buf[4];
int status;
struct i2c_msg msg[2] = {
{
this->hw->i2c_clit[this->hw->i2c_id]->addr, 0, 2, buf
},
{
this->hw->i2c_clit[this->hw->i2c_id]->addr, I2C_M_RD, 1, reg_value
}
};
memset(buf, 0, 4);
buf[0] = reg_addr&0x00ff;
msg[0].len = 1;