i2总线驱动分析

 

static int __init i2c_adap_s3c_init(void)
{
 return platform_driver_register(&s3c24xx_i2c_driver);
}
subsys_initcall(i2c_adap_s3c_init);

static void __exit i2c_adap_s3c_exit(void)
{
 platform_driver_unregister(&s3c24xx_i2c_driver);
}

static struct platform_driver s3c24xx_i2c_driver = {
 .probe  = s3c24xx_i2c_probe,
 .remove  = s3c24xx_i2c_remove,
 .id_table = s3c24xx_driver_ids,
 .driver  = {
  .owner = THIS_MODULE,
  .name = "s3c-i2c",
  .pm = S3C24XX_DEV_PM_OPS,
 },
};
这个就不多说了,学过以平台总线方式注册驱动的都知道这个platform_driver_register()和platform_driver_unregister()。

s3c24xx_i2c_driver 中重要看s3c24xx_i2c_probe,当总线上发生设备驱动name 的匹配是就会调用它。

 

static int s3c24xx_i2c_probe(struct platform_device *pdev)
{

  //传入的参数是在总线中发生匹配的平台设备
 //platform_device *pdev 

 struct s3c24xx_i2c *i2c;
 struct s3c2410_platform_i2c *pdata;
 struct resource *res;
 int ret;

 pdata = pdev->dev.platform_data;
 if (!pdata) {
  dev_err(&pdev->dev, "no platform data\n");
  return -EINVAL;
 }

 i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);//获取上面定义的结构体内存
 if (!i2c) {
  dev_err(&pdev->dev, "no memory for state\n");
  return -ENOMEM;
 }

//下面是给i2c中的一些成员赋值

 strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
 i2c->adap.owner   = THIS_MODULE;
 i2c->adap.algo    = &s3c24xx_i2c_algorithm;//通信方式
 i2c->adap.retries = 2;//通信重复次数
 i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
 i2c->tx_setup     = 50;

 spin_lock_init(&i2c->lock);//初始化i2c->lock锁

init_waitqueue_head(&i2c->wait);//初始化i2c->wait等待队列头

 

 i2c->dev = &pdev->dev;//把平台的设备赋给i2c->dev
 i2c->clk = clk_get(&pdev->dev, "i2c");//获得i2c时钟
 if (IS_ERR(i2c->clk)) {
  dev_err(&pdev->dev, "cannot get clock\n");
  ret = -ENOENT;
  goto err_noclk;
 }

 dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);

 clk_enable(i2c->clk);//使能时钟

 

 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//平台设备资源获取函数
 if (res == NULL) {
  dev_err(&pdev->dev, "cannot find IO resource\n");
  ret = -ENOENT;
  goto err_clk;
 }

 i2c->ioarea = request_mem_region(res->start, resource_size(res),//申请占有此资源
      pdev->name);

 if (i2c->ioarea == NULL) {
  dev_err(&pdev->dev, "cannot request IO\n");
  ret = -ENXIO;
  goto err_clk;
 }

 i2c->regs = ioremap(res->start, resource_size(res));//映射这段内存资源,起始地址在i2c->regs.

 if (i2c->regs == NULL) {
  dev_err(&pdev->dev, "cannot map IO\n");
  ret = -ENXIO;
  goto err_ioarea;
 }

 dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
  i2c->regs, i2c->ioarea, res);

 

 i2c->adap.algo_data = i2c;把i2c中adap.algo_data指针指向i2c结构体。
 i2c->adap.dev.parent = &pdev->dev;

 

 ret = s3c24xx_i2c_init(i2c);//用于初始化i2c控制器
 if (ret != 0)
  goto err_iomap;

 

 i2c->irq = ret = platform_get_irq(pdev, 0);//获取平台设备资源的中断
 if (ret <= 0) {
  dev_err(&pdev->dev, "cannot find IRQ\n");
  goto err_iomap;
 }

 ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
     dev_name(&pdev->dev), i2c);//申请中断

 if (ret != 0) {
  dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
  goto err_iomap;
 }

 ret = s3c24xx_i2c_register_cpufreq(i2c);
 if (ret < 0) {
  dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
  goto err_irq;
 }

 

 i2c->adap.nr = pdata->bus_num;//显示是第几个控制器,在/dev/i2c/ 中显示为0

 ret = i2c_add_numbered_adapter(&i2c->adap);//注册这个控制器
 if (ret < 0) {
  dev_err(&pdev->dev, "failed to add bus to i2c core\n");
  goto err_cpufreq;
 }

 platform_set_drvdata(pdev, i2c);

 dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
 return 0;

 err_cpufreq:
 s3c24xx_i2c_deregister_cpufreq(i2c);

 err_irq:
 free_irq(i2c->irq, i2c);

 err_iomap:
 iounmap(i2c->regs);

 err_ioarea:
 release_resource(i2c->ioarea);
 kfree(i2c->ioarea);

 err_clk:
 clk_disable(i2c->clk);
 clk_put(i2c->clk);

 err_noclk:
 kfree(i2c);
 return ret;
}

这个函数完成i2c控制器的IO资源,中断等等的相关配置。

相对来说比较关键的有
i2c->adap.algo    = &s3c24xx_i2c_algorithm;

 ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
     dev_name(&pdev->dev), i2c);

 第一个定义了i2c总线通信方式,第二个完成了中断函数。

下面看看s3c24xx_i2c_algorithm

 

static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
 .master_xfer  = s3c24xx_i2c_xfer,
 .functionality  = s3c24xx_i2c_func,
};

struct i2c_algorithm {
 
 
 int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
      int num);
 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
      unsigned short flags, char read_write,
      u8 command, int size, union i2c_smbus_data *data);

 
 u32 (*functionality) (struct i2c_adapter *);
};i2c_algorithm 中有三个指针函数,其中只定义了两个。*master_xfer和*functionality.

这两个函数的第一个定义了一次完整的传输,第二个定义了这条总线的功能。


static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
{

//函数传入的是此总线控制器结构,返回其功能
 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}

static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
   struct i2c_msg *msgs, int num)
{ //函数传入控制器结构,传输的信息i2c_msg *msgs结构体指针,还有消息数量num
 struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;//获得结构体struct s3c24xx_i2c *i2c ,为什么能够通过它获得请看s3c24xx_i2c_probe()函数

 int retry;
 int ret;
 struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data;

 

 

通过上面的英文注释不难理解。
 if (pdata->cfg_gpio)
  pdata->cfg_gpio(to_platform_device(i2c->dev));

 

 for (retry = 0; retry < adap->retries; retry++) {

  ret = s3c24xx_i2c_doxfer(i2c, msgs, num);//真正的发送在这个函数里

  if (ret != -EAGAIN)
   return ret;

  dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);

  udelay(100);
 }

 return -EREMOTEIO;
}

下面就打到函数s3c24xx_i2c_doxfer(i2c, msgs, num)

 

static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
         struct i2c_msg *msgs, int num)
{  //这个函数传入了struct s3c24xx_i2c *i2c,发送消息结构体,还有数量
 unsigned long timeout;
 int ret;

 if (i2c->suspended)
  return -EIO;

 ret = s3c24xx_i2c_set_master(i2c);//下面就是这个函数的具体。主要是获得这个总线是否忙

 

static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
{
 unsigned long iicstat;
 int timeout = 400;

 while (timeout-- > 0) {
  iicstat = readl(i2c->regs + S3C2410_IICSTAT);

  if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
   return 0;

  msleep(1);
 }

 return -ETIMEDOUT;
}
**************************************************************************************/
 if (ret != 0) {//如果忙的话就出错,不能获得I2C传输总线
  dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
  ret = -EAGAIN;
  goto out;
 }

 spin_lock_irq(&i2c->lock);//获取锁,不能被打断

 i2c->msg     = msgs;
 i2c->msg_num = num;
 i2c->msg_ptr = 0;
 i2c->msg_idx = 0;
 i2c->state   = STATE_START;

 s3c24xx_i2c_enable_irq(i2c);//打开中断
 s3c24xx_i2c_message_start(i2c, msgs);//起始信号发送如下


 s3c24xx_i2c_enable_ack(i2c);

 iiccon = readl(i2c->regs + S3C2410_IICCON);
 writel(stat, i2c->regs + S3C2410_IICSTAT);

 dev_dbg(i2c->dev, "START: lx to IICSTAT, x to DS\n", stat, addr);
 writeb(addr, i2c->regs + S3C2410_IICDS);

 

 ndelay(i2c->tx_setup);

 dev_dbg(i2c->dev, "iiccon, lx\n", iiccon);
 writel(iiccon, i2c->regs + S3C2410_IICCON);

 stat |= S3C2410_IICSTAT_START;
 writel(stat, i2c->regs + S3C2410_IICSTAT);
}

 

***********************************************************************************************/
 spin_unlock_irq(&i2c->lock);

 timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);//事件过时函数

 ret = i2c->msg_idx;

 

 if (timeout == 0)
  dev_dbg(i2c->dev, "timeout\n");
 else if (ret != num)
  dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);

 

 msleep(1);

 out:
 return ret;
}

//很多人也许还会有疑惑,哪里传输了,怎么好像只发送了一个起始信号,就什么都没干了。具体的传输哪里去了??????

想想中断,在完成s3c24xx_i2c_message_start(i2c, msgs)后会发生中断,在中断中判断具体下一步传输。

 

static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
{ //irqno中断号, *dev_id 传递给中断的参数,在中断注册中确定

struct s3c24xx_i2c *i2c = dev_id;
 unsigned long status;
 unsigned long tmp;

 status = readl(i2c->regs + S3C2410_IICSTAT);

 if (status & S3C2410_IICSTAT_ARBITR) {
  
  dev_err(i2c->dev, "deal with arbitration loss\n");
 }//发生错误

 if (i2c->state == STATE_IDLE) {
  dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");

  tmp = readl(i2c->regs + S3C2410_IICCON);
  tmp &= ~S3C2410_IICCON_IRQPEND;
  writel(tmp, i2c->regs +  S3C2410_IICCON);
  goto out;
 }

 

 i2s_s3c_irq_nextbyte(i2c, status);

 out:
 return IRQ_HANDLED;
}

i2s_s3c_irq_nextbyte()函数很长,也有点复杂。慢慢来吧

 

static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
{

  

 unsigned long tmp;
 unsigned char byte;
 int ret = 0;

 switch (i2c->state) {

 case STATE_IDLE:
  dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
  goto out;
  break;

 case STATE_STOP://发送结束信号
  dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
  s3c24xx_i2c_disable_irq(i2c);
  goto out_ack;

 case STATE_START:
  

  if (iicstat & S3C2410_IICSTAT_LASTBIT &&
      !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
   

   dev_dbg(i2c->dev, "ack was not received\n");
   s3c24xx_i2c_stop(i2c, -ENXIO);
   goto out_ack;
  }//判断是STATE_START状态时,进一步判断有没收到ACK如果没有结束,否者进去下一步判断

  if (i2c->msg->flags & I2C_M_RD)//是读?
   i2c->state = STATE_READ;
  else//否则是写
   i2c->state = STATE_WRITE;

  

  if (is_lastmsg(i2c) && i2c->msg->len == 0) {//如果没有要传输的,结束
   s3c24xx_i2c_stop(i2c, 0);
   goto out_ack;
  }

  if (i2c->state == STATE_READ)
   goto prepare_read;//如果是读则转到prepare_read

  

 case STATE_WRITE:
  

  if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
   if (iicstat & S3C2410_IICSTAT_LASTBIT) {
    dev_dbg(i2c->dev, "WRITE: No Ack\n");

    s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
    goto out_ack;
   }
  }

 retry_write:

 

  if (!is_msgend(i2c)) {
   byte = i2c->msg->buf[i2c->msg_ptr++];
   writeb(byte, i2c->regs + S3C2410_IICDS);发送数据byte

   

   ndelay(i2c->tx_setup);

  } else if (!is_lastmsg(i2c)) {
   

   dev_dbg(i2c->dev, "WRITE: Next Message\n");

   i2c->msg_ptr = 0;
   i2c->msg_idx++;
   i2c->msg++;

   
   if (i2c->msg->flags & I2C_M_NOSTART) {

    if (i2c->msg->flags & I2C_M_RD) {
     

     s3c24xx_i2c_stop(i2c, -EINVAL);
    }

    goto retry_write;
   } else {
    
    s3c24xx_i2c_message_start(i2c, i2c->msg);
    i2c->state = STATE_START;
   }

  } else {
   

   s3c24xx_i2c_stop(i2c, 0);
  }
  break;

 case STATE_READ://判断为读
  

  byte = readb(i2c->regs + S3C2410_IICDS);读取数据到BYTE,
  i2c->msg->buf[i2c->msg_ptr++] = byte;吧byte赋给i2c->msg->buf;

 prepare_read:


 if (is_msglast(i2c)) {
   

   if (is_lastmsg(i2c))
    s3c24xx_i2c_disable_ack(i2c);

  } else if (is_msgend(i2c)) {
   

   if (is_lastmsg(i2c)) {
    
    dev_dbg(i2c->dev, "READ: Send Stop\n");

    s3c24xx_i2c_stop(i2c, 0);
   } else {
    
    dev_dbg(i2c->dev, "READ: Next Transfer\n");

    i2c->msg_ptr = 0;
    i2c->msg_idx++;
    i2c->msg++;
   }
  }

  break;
 }

 

 out_ack:
 tmp = readl(i2c->regs + S3C2410_IICCON);
 tmp &= ~S3C2410_IICCON_IRQPEND;
 writel(tmp, i2c->regs + S3C2410_IICCON);
 out:
 return ret;
}

 

你可能感兴趣的:(Algorithm,c,struct,null,byte,平台)