一般相应的硬件都会连接到相应的硬件i2c上,但有时会用到模拟i2c(sda和scl引脚弄反,通
信异常,非标准i2c等),这里给出了相应的例子。
这里假设i2c的频率是100k(周期为10us),SCL对应的引脚号是pin11,SDA对应的引脚号是pin22,
#define UDELAY {udelay(5);}
#define MDELAY {mdelay(5);}
#define SCL pin11
#define SDA pin22
#define ONE 1
#define ZERO 0
#define USESOFTIIC
typedef u8 u8;
static struct i2c_client *i2c_client;
static void i2c_start(void) { //起始信号 SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据
gpio_set_value(SDA, 1);
gpio_set_value(SCL, 1);
UDELAY;
gpio_set_value(SDA, 0);
UDELAY;
gpio_set_value(SCL, 0);
}
static void i2c_stop (void){//停止信号 SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据
gpio_set_value(SDA, 0);
gpio_set_value(SCL, 1);
UDELAY;
gpio_set_value(SDA, 1);
UDELAY;
}
static void i2c_sendack(u8 ack){ //发送应答信号 入口参数:ack (0x0:ACK 0x01:NAK)
if(ack)
gpio_set_value(SDA, 1);
else
gpio_set_value(SDA, 0);
gpio_set_value(SCL, 1);
UDELAY;
gpio_set_value(SCL, 0);
UDELAY;
}
static u8 i2c_recvack(void){//接收应答信号
u8 cy;
gpio_set_value(SDA, 1);
UDELAY;
gpio_direction_input(SDA);
gpio_set_value(SCL, 1);
UDELAY;
cy=gpio_get_value(SDA);
gpio_set_value(SCL, 0);
UDELAY;
gpio_direction_output(SDA,1);
UDELAY;
return cy;
}
static int i2c_sendbyte(u8 data){//向IIC总线发送一个字节数据
u8 i;
u8 ack;
u8 cy[8];
u8 bit;
for (i=0; i<8; i){
bit=data&0x80;
if(bit)
cy[i]=ONE;
else
cy[i]=ZERO;
data<<=1;
}
for (i=0; i<8; i){
gpio_set_value(SDA,cy[i]);
gpio_set_value(SCL, 1);
UDELAY;
gpio_set_value(SCL, 0);
UDELAY;
}
ack=i2c_recvack();
return ack;
}
static u8 i2c_recvbyte(void){//从IIC总线接收一个字节数据
u8 i;
u8 dat = 0;
gpio_set_value(SDA,1);
gpio_direction_input(SDA);
UDELAY;
for (i=0; i<8; i){
dat <<= 1;
gpio_set_value(SCL, 1);
UDELAY;
dat |= gpio_get_value(SDA);
gpio_set_value(SCL, 0);
UDELAY;
}
gpio_direction_output(SDA,1);
return dat;
}
static void i2c_init(void){
int ret;
ret = gpio_request(SDA, "I2C_SDA");
ret = gpio_request(SCL, "I2C_SCL");
gpio_direction_output(SCL, 1);
gpio_direction_output(SDA, 1);
}
相应的读写寄存器接口
static int i2c_write_reg(u8 reg,u8 value){
int ret1,ret2,ret3;
i2c_start();
ret1=i2c_sendbyte(i2c_client->addr<<1);
ret2=i2c_sendbyte(reg);
ret3=i2c_sendbyte(value);
i2c_stop();
if(ret1||ret2||ret3){
pr_err("i2c_write error ret1=%d,ret2=%d,ret3=%d",ret1,ret2,ret3);
return -ENXIO;
}
return 0;
}
static u8 i2c_read_reg(u8 reg){
int ret1,ret2,ret3,ret4;
i2c_start();
ret1=i2c_sendbyte(i2c_client->addr<<1);
ret2=i2c_sendbyte(reg);
i2c_stop();
i2c_start();
ret3=i2c_sendbyte((i2c_client->addr<<1)+1);
ret4=i2c_recvbyte();
i2c_sendack(0x1);
i2c_stop();
if(ret1||ret2||ret3){
pr_err("i2c_write error ret1=%d,ret2=%d,ret3=%d,ret4=%d",ret1,ret2,ret3,ret4);
return -ENXIO;
}
return ret4;
}
一般我们都有硬件的i2c驱动,我们在probe函数里将i2c设备的信息保存下(i2c_client=client,
主要是获取从机地址),然后调用下i2c_init拉高i2c信号的电平,然后替换相应的读写接口,
就可以实现驱动了模拟和硬件i2c驱动兼容了。
static int xxxx_probe(struct i2c_client *client,const struct i2c_device_id *id){
i2c_client=client;
i2c_init();
}