Linux I2C总线控制器驱动(S3C2440)

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 << 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;
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/50d322c3f56eb4d1846acdcb8741af1b.html