linux i2c dev.h freq,Linux I2C总线控制器驱动(S3C2440)

s3c2440的i2c控制器驱动(精简DIY),直接上代码,注释很详细:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//#define PRINTK printk

#define PRINTK(...)

enum s3c24xx_i2c_state {

STATE_IDLE,

STATE_START,

STATE_READ,

STATE_WRITE,

STATE_STOP

};

//i2c控制器寄存器

struct s3c2440_i2c_regs {

unsigned int iiccon;

unsigned int iicstat;

unsigned int iicadd;

unsigned int iicds;

unsigned int iiclc;

};

//i2c数据传输载体

struct s3c2440_i2c_xfer_data {

struct i2c_msg *msgs;

int msn_num;

int cur_msg;

int cur_ptr;

int state;

int err;

wait_queue_head_t wait;

};

static struct s3c2440_i2c_xfer_data s3c2440_i2c_xfer_data;

static struct s3c2440_i2c_regs *s3c2440_i2c_regs;

static void s3c2440_i2c_start(void)

{

s3c2440_i2c_xfer_data.state = STATE_START;

if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */

{

s3c2440_i2c_regs->iicds        = s3c2440_i2c_xfer_data.msgs->addr << 1;

s3c2440_i2c_regs->iicstat      = 0xb0;    // 主机接收,启动

}

else /* 写 */

{

s3c2440_i2c_regs->iicds        = s3c2440_i2c_xfer_data.msgs->addr << 1;

s3c2440_i2c_regs->iicstat    = 0xf0;        // 主机发送,启动

}

}

static void s3c2440_i2c_stop(int err)

{

s3c2440_i2c_xfer_data.state = STATE_STOP;

s3c2440_i2c_xfer_data.err  = err;

PRINTK("STATE_STOP, err = %d\n", err);

if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */

{

// 下面两行恢复I2C操作,发出P信号

s3c2440_i2c_regs->iicstat = 0x90;

s3c2440_i2c_regs->iiccon  = 0xaf;

ndelay(50);  // 等待一段时间以便P信号已经发出

}

else /* 写 */

{

// 下面两行用来恢复I2C操作,发出P信号

s3c2440_i2c_regs->iicstat = 0xd0;

s3c2440_i2c_regs->iiccon  = 0xaf;

ndelay(50);  // 等待一段时间以便P信号已经发出

}

/* 唤醒 */

wake_up(&s3c2440_i2c_xfer_data.wait);

}

//i2c总线数据传输处理函数

static int s3c2440_i2c_xfer(struct i2c_adapter *adap,

struct i2c_msg *msgs, int num)

{

unsigned long timeout;

/* 把num个msg的I2C数据发送出去/读进来 */

s3c2440_i2c_xfer_data.msgs    = msgs;

s3c2440_i2c_xfer_data.msn_num = num;

s3c2440_i2c_xfer_data.cur_msg = 0;

s3c2440_i2c_xfer_data.cur_ptr = 0;

s3c2440_i2c_xfer_data.err    = -ENODEV; //确认是否有ack应答

s3c2440_i2c_start(); //发出start信号,判断read or write

/* 休眠-等待i2c读写状态改变 */

timeout = wait_event_timeout(s3c2440_i2c_xfer_data.wait, (s3c2440_i2c_xfer_data.state == STATE_STOP), HZ * 5); //等待状态成立或5s

if (0 == timeout)

{

printk("s3c2440_i2c_xfer time out\n");

return -ETIMEDOUT;

}

else

{

return s3c2440_i2c_xfer_data.err;

}

}

static u32 s3c2440_i2c_func(struct i2c_adapter *adap)

{

return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;

}

static const struct i2c_algorithm s3c2440_i2c_algo = {

//    .smbus_xfer    = ,  //smbus是i2c传输的一个子集,支持的话可以在这里指定处理函数

.master_xfer    = s3c2440_i2c_xfer, //传输函数

.functionality    = s3c2440_i2c_func,

};

/* 1. 分配/设置i2c_adapter

*/

static struct i2c_adapter s3c2440_i2c_adapter = {

.name            = "s3c2440_sheldon",

.algo            = &s3c2440_i2c_algo, //算法函数

.owner          = THIS_MODULE,

};

static int isLastMsg(void)

{

return (s3c2440_i2c_xfer_data.cur_msg == s3c2440_i2c_xfer_data.msn_num - 1);

}

static int isEndData(void)

{

return (s3c2440_i2c_xfer_data.cur_ptr >= s3c2440_i2c_xfer_data.msgs->len);

}

static int isLastData(void)

{

return (s3c2440_i2c_xfer_data.cur_ptr == s3c2440_i2c_xfer_data.msgs->len - 1);

}

static irqreturn_t s3c2440_i2c_xfer_irq(int irq, void *dev_id)

{

unsigned int iicSt;

iicSt  = s3c2440_i2c_regs->iicstat;  //读取i2c控制器的状态寄存器,判断是否读写成功

if(iicSt & 0x8){ printk("Bus arbitration failed\n\r"); }

switch (s3c2440_i2c_xfer_data.state)

{

case STATE_START : /* 发出S和设备地址后,产生中断 */

{

PRINTK("Start\n");

/* 如果没有ACK, 返回错误 */

if (iicSt & S3C2410_IICSTAT_LASTBIT)

{

s3c2440_i2c_stop(-ENODEV);

break;

}

if (isLastMsg() && isEndData())

{

s3c2440_i2c_stop(0);

break;

}

/* 进入下一个状态 */

if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */

{

s3c2440_i2c_xfer_data.state = STATE_READ;

goto next_read;

}

else

{

s3c2440_i2c_xfer_data.state = STATE_WRITE;

}

}

case STATE_WRITE:

{

PRINTK("STATE_WRITE\n");

/* 如果没有ACK, 返回错误 */

if (iicSt & S3C2410_IICSTAT_LASTBIT)

{

s3c2440_i2c_stop(-ENODEV);

break;

}

if (!isEndData())  /* 如果当前msg还有数据要发送 */

{

s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr];

s3c2440_i2c_xfer_data.cur_ptr++;

// 将数据写入IICDS后,需要一段时间才能出现在SDA线上

ndelay(50);

s3c2440_i2c_regs->iiccon = 0xaf;        // 恢复I2C传输

break;

}

else if (!isLastMsg())

{

/* 开始处理下一个消息 */

s3c2440_i2c_xfer_data.msgs++;

s3c2440_i2c_xfer_data.cur_msg++;

s3c2440_i2c_xfer_data.cur_ptr = 0;

s3c2440_i2c_xfer_data.state = STATE_START;

/* 发出START信号和发出设备地址 */

s3c2440_i2c_start();

break;

}

else

{

/* 是最后一个消息的最后一个数据 */

s3c2440_i2c_stop(0);

break;

}

break;

}

case STATE_READ:

{

PRINTK("STATE_READ\n");

/* 读出数据 */

s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr] = s3c2440_i2c_regs->iicds;

s3c2440_i2c_xfer_data.cur_ptr++;

next_read:

if (!isEndData()) /* 如果数据没读写, 继续发起读操作 */

{

if (isLastData())  /* 如果即将读的数据是最后一个, 不发ack */

{

s3c2440_i2c_regs->iiccon = 0x2f;  // 恢复I2C传输,接收到下一数据时无ACK

}

else

{

s3c2440_i2c_regs->iiccon = 0xaf;  // 恢复I2C传输,接收到下一数据时发出ACK

}

break;

}

else if (!isLastMsg())

{

/* 开始处理下一个消息 */

s3c2440_i2c_xfer_data.msgs++;

s3c2440_i2c_xfer_data.cur_msg++;

s3c2440_i2c_xfer_data.cur_ptr = 0;

s3c2440_i2c_xfer_data.state = STATE_START;

/* 发出START信号和发出设备地址 */

s3c2440_i2c_start();

break;

}

else

{

/* 是最后一个消息的最后一个数据 */

s3c2440_i2c_stop(0);

break;

}

break;

}

default: break;

}

/* 清中断 */

s3c2440_i2c_regs->iiccon &= ~(S3C2410_IICCON_IRQPEND);

return IRQ_HANDLED;

}

/*

* I2C初始化

*/

static void s3c2440_i2c_init(void)

{

struct clk *clk;

clk = clk_get(NULL, "i2c");

clk_enable(clk);

// 选择引脚功能:GPE15:IICSDA, GPE14:IICSCL

s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);

s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);

/* bit[7] = 1, 使能ACK

* bit[6] = 0, IICCLK = PCLK/16

* bit[5] = 1, 使能中断

* bit[3:0] = 0xf, Tx clock = IICCLK/16

* PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz

*/

s3c2440_i2c_regs->iiccon = (1<<7) | (0<<6) | (1<<5) | (0xf);  // 0xaf

s3c2440_i2c_regs->iicadd  = 0x10;    // S3C24xx slave address = [7:1]

s3c2440_i2c_regs->iicstat = 0x10;    // I2C串行输出使能(Rx/Tx)

}

static int i2c_bus_s3c2440_init(void)

{

/* 2. 硬件相关的设置 */

s3c2440_i2c_regs = ioremap(0x54000000, sizeof(struct s3c2440_i2c_regs));//映射功能寄存器

s3c2440_i2c_init(); //初始化i2c控制器

request_irq(IRQ_IIC, s3c2440_i2c_xfer_irq, 0, "s3c2440-i2c", NULL); //申请中断源,加载中断处理函数-s3c2440_i2c_xfer_irq

init_waitqueue_head(&s3c2440_i2c_xfer_data.wait); //初始化一个等待队列头

/* 3. 注册i2c_adapter */

i2c_add_adapter(&s3c2440_i2c_adapter);

return 0;

}

static void i2c_bus_s3c2440_exit(void)

{

i2c_del_adapter(&s3c2440_i2c_adapter);

free_irq(IRQ_IIC, NULL);

iounmap(s3c2440_i2c_regs);

}

module_init(i2c_bus_s3c2440_init);

module_exit(i2c_bus_s3c2440_exit);

MODULE_LICENSE("GPL");

附一份测试程序:

#include

#include

#include

#include

#include

#include

#include "i2c-dev.h"

/* i2c_usr_test r addr

* i2c_usr_test w addr val

*/

void print_usage(char *file)

{

printf("%s r addr\n", file);

printf("%s w addr val\n", file);

}

int main(int argc, char **argv)

{

int fd;

unsigned char addr, data;

int dev_addr;

if ((argc != 5) && (argc != 6))

{

print_usage(argv[0]);

return -1;

}

fd = open(argv[1], O_RDWR);

if (fd < 0)

{

printf("can't open %s\n", argv[1]);

return -1;

}

dev_addr = strtoul(argv[2], NULL, 0);

if (ioctl(fd, I2C_SLAVE, dev_addr) < 0)

{

/* ERROR HANDLING; you can check errno to see what went wrong */

printf("set addr error!\n");

return -1;

}

if (strcmp(argv[3], "r") == 0)

{

addr = strtoul(argv[4], NULL, 0);

data = i2c_smbus_read_word_data(fd, addr);

printf("data: %c, %d, 0x%2x\n", data, data, data);

}

else if ((strcmp(argv[3], "w") == 0) && (argc == 6))

{

addr = strtoul(argv[4], NULL, 0);

data = strtoul(argv[5], NULL, 0);

i2c_smbus_write_byte_data(fd, addr, data);

}

else

{

print_usage(argv[0]);

return -1;

}

return 0;

}

Make File:

KERN_DIR = /work/system/linux-3.4.2

all:

make -C $(KERN_DIR) M=`pwd` modules

clean:

make -C $(KERN_DIR) M=`pwd` modules clean

rm -rf modules.order

obj-m    += i2c_bus_s3c2440.o

0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值