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


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

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

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