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

 #include <linux/kernel.h>
#include <linux/module.h> #include <linux/i2c.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/regs-gpio.h> #include <asm/irq.h> #include <plat/regs-iic.h>
#include <plat/iic.h> //#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 << ; 
s3c2440_i2c_regs->iicstat = 0xb0; // 主机接收,启动
}
else /* 写 */
{
s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->addr << ;
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(); // 等待一段时间以便P信号已经发出
}
else /* 写 */
{
// 下面两行用来恢复I2C操作,发出P信号
s3c2440_i2c_regs->iicstat = 0xd0;
s3c2440_i2c_regs->iiccon = 0xaf;
ndelay(); // 等待一段时间以便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 = ;
s3c2440_i2c_xfer_data.cur_ptr = ;
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 * ); //等待状态成立或5s
if ( == 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 - );
} 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 - );
} 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();
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(); 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 = ;
s3c2440_i2c_xfer_data.state = STATE_START;
/* 发出START信号和发出设备地址 */
s3c2440_i2c_start();
break;
}
else
{
/* 是最后一个消息的最后一个数据 */
s3c2440_i2c_stop();
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 = ;
s3c2440_i2c_xfer_data.state = STATE_START;
/* 发出START信号和发出设备地址 */
s3c2440_i2c_start();
break;
}
else
{
/* 是最后一个消息的最后一个数据 */
s3c2440_i2c_stop();
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(), S3C2410_GPE14_IICSCL);
s3c_gpio_cfgpin(S3C2410_GPE(), 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 = (<<) | (<<) | (<<) | (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, , "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 ;
} 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "i2c-dev.h" /* i2c_usr_test </dev/i2c-0> <dev_addr> r addr
* i2c_usr_test </dev/i2c-0> <dev_addr> w addr val
*/ void print_usage(char *file)
{
printf("%s </dev/i2c-0> <dev_addr> r addr\n", file);
printf("%s </dev/i2c-0> <dev_addr> w addr val\n", file);
} int main(int argc, char **argv)
{
int fd;
unsigned char addr, data;
int dev_addr; if ((argc != ) && (argc != ))
{
print_usage(argv[]);
return -;
} fd = open(argv[], O_RDWR);
if (fd < )
{
printf("can't open %s\n", argv[]);
return -;
} dev_addr = strtoul(argv[], NULL, );
if (ioctl(fd, I2C_SLAVE, dev_addr) < )
{
/* ERROR HANDLING; you can check errno to see what went wrong */
printf("set addr error!\n");
return -;
} if (strcmp(argv[], "r") == )
{
addr = strtoul(argv[], NULL, ); data = i2c_smbus_read_word_data(fd, addr); printf("data: %c, %d, 0x%2x\n", data, data, data);
}
else if ((strcmp(argv[], "w") == ) && (argc == ))
{
addr = strtoul(argv[], NULL, );
data = strtoul(argv[], NULL, );
i2c_smbus_write_byte_data(fd, addr, data);
}
else
{
print_usage(argv[]);
return -;
} return ;
}

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

Linux I2C总线控制器驱动(S3C2440)的更多相关文章

  1. Linux I2C总线设备驱动模型分析(ov7740)

    1. 框架1.1 硬件协议简介1.2 驱动框架1.3 bus-drv-dev模型及写程序a. 设备的4种构建方法a.1 定义一个i2c_board_info, 里面有:名字, 设备地址 然后i2c_r ...

  2. Linux+I2C总线分析(主要是probe的方式)

    Linux I2C 总线浅析 ㈠ Overview Linux的I2C体系结构分为3个组成部分: ·I2C核心: I2C核心提供了I2C总线驱动和设备驱动的注册.注销方法,I2C通信方法(即“algo ...

  3. Linux的总线设备驱动模型

    裸机编写驱动比较自由,按照手册实现其功能即可,每个人写出来都有很大不同: 而Linux中还需要按照Linux的驱动模型来编写,也就是需要按照"模板"来写,写出来的驱动就比较统一. ...

  4. 芯灵思SinlinxA33开发板 Linux平台总线设备驱动

    1.什么是platform(平台)总线? 相对于USB.PCI.I2C.SPI等物理总线来说,platform总线是一种虚拟.抽象出来的总线,实际中并不存在这样的总线. 那为什么需要platform总 ...

  5. I2C总线和S5PV210的I2C总线控制器

    一.什么是I2C通信协议? 1.物理接口:SCL + SDA (1)SCL(serial clock):时钟线,传输CLK信号,一般是I2C主设备向从设备提供时钟的通道. (2)SDA(serial ...

  6. Linux中总线设备驱动模型及平台设备驱动实例

    本文将简要地介绍Linux总线设备驱动模型及其实现方式,并不会过多地涉及其在内核中的具体实现,最后,本文将会以平台总线为例介绍设备和驱动程序的实现过程. 目录: 一.总线设备驱动模型总体介绍及其实现方 ...

  7. Linux平台总线设备驱动

    1. 平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备(没有挂到真实总线的设备)与驱动进行了管理,这样提高了程序的可移植性. 2. 平台总 ...

  8. Linux I2C核心、总线和设备驱动

    目录 更新记录 一.Linux I2C 体系结构 1.1 Linux I2C 体系结构的组成部分 1.2 内核源码文件 1.3 重要的数据结构 二.Linux I2C 核心 2.1 流程 2.2 主要 ...

  9. Linux设备驱动模型之I2C总线

    一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,提供了与具体硬件无关的I2C读写函数. (2)I2 ...

随机推荐

  1. ms

    meanShift的概念最早是由Fukunage[1]在1975年提出的,其最初的含义正如其名:偏移的均值向量:但随着理论的发展,meanShift的含义已经发生了很多变化.如今,我们说的meanSh ...

  2. spring框架IoC

    IoC反转控制, 举个反例: //数据操作类 public class DataBase { //向数据库中存储数据 public void saveDB() { } } //业务逻辑类 public ...

  3. python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例

    python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...

  4. 如何修改VPN连接的MTU,解决频繁断线和页面打不开的问题

    如何修改VPN连接的MTU,解决频繁断线和页面打不开的问题 MTU 介绍:MTU 即最大传输单元,它是指一种通信协议的某一层上面所能通过的最大数据包大小.为什么需要修改 MTU大多数设备原本支持通过 ...

  5. App创业者必看:如何选择免费数据分析平台

      笔者是一位移动互联网老兵,做过好几个App的开发运营工作,其中一些如今侥幸有了上亿用户.今天和大家聊一下App开发中,不能缺少的一个工具——数据分析系统 首先,App创业者为什么需要一个数据分析系 ...

  6. 新知识:Java 利用itext填写pdf模板并导出(昨天奋战到深夜四点,知道今天两点终于弄懂)

    废话少说,不懂itext干啥用的直接去百度吧. ***************制作模板******************* 1.先用word做出界面 2.再转换成pdf格式 3.用Adobe Acr ...

  7. Unity中通过类名字符串取组件类型的方法(Types.GetType用法)

    正常调用Type.GetType取不到组件,因为会先创建实例在获取,而Unity组件无法通过new来创建. 第二种创建方式是通过程序集,具体如下 Assembly.GetExecutingAssemb ...

  8. HTML 事件属性

    HTML 事件属性一:定义二:窗口事件 (Window Events)三:表单元素事件 (Form Element Events)四:图像事件 (Image Events) 一:定义 HTML 4 的 ...

  9. vs2015手动安装xamarin

    1.安装jdk Download the Java JDK v1.7.0 installer to any directory on your disk, double-click the downl ...

  10. Oracle介绍(初学者必须知道的)

    1.为什么学习数据库?(两个概念) 数据库的概念: 数据库是按照数据结构组织,存储和管理数据的仓库. 数据库,简单来说是本身可视为电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据进行新增. ...