ic2-2410.c分析

480阅读 0评论2015-12-11 48576958
分类:LINUX


1、模块初始化,注册一个平台设备,调用platform_driver_register 时系统会使用s3c2440_i2c_driver 中的driver.name 字段去遍历平台设备链表,以找到相应平台设备。
  1. static int __init i2c_adap_s3c_init(void)
  2. {
  3.  int ret;
  4.  ret = platform_driver_register(&s3c2410_i2c_driver);
  5.  if (ret == 0) {
  6.   ret = platform_driver_register(&s3c2440_i2c_driver);
  7.   if (ret)
  8.    platform_driver_unregister(&s3c2410_i2c_driver);
  9.  }
  10.  return ret;
  11. }

2、找到对应的平台设备,则该平台设备结构体指针作为参数,回调probe 字段填入的函数-s3c24xx_i2c_probe.

  1. static struct platform_driver s3c2440_i2c_driver = {
  2.  .probe = s3c24xx_i2c_probe,
  3.  .remove = s3c24xx_i2c_remove,
  4.  .resume = s3c24xx_i2c_resume,
  5.  .driver = {
  6.   .owner = THIS_MODULE,
  7.   .name = "s3c2440-i2c",
  8.  },
  9. };
3、probe函数对平台设备进行初始化等操作,其中会使用内核API platform_get_resource 与platform_get_irq 获得所需的内存和中断号等。


  1. static int s3c24xx_i2c_probe(struct platform_device *pdev)
  2. {
  3.     struct s3c24xx_i2c *i2c;
  4.     struct s3c2410_platform_i2c *pdata;
  5.     struct resource *res;
  6.     int ret;

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

  12.     i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
  13.     if (!i2c) {
  14.         dev_err(&pdev->dev, "no memory for state\n");
  15.         return -ENOMEM;
  16.     }

  17.     strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
  18.     i2c->adap.owner = THIS_MODULE;
  19.     i2c->adap.algo = &s3c24xx_i2c_algorithm;
  20.     i2c->adap.retries = 2;
  21.     i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
  22.     i2c->tx_setup = 50;

  23.     spin_lock_init(&i2c->lock);
  24.     init_waitqueue_head(&i2c->wait);

  25.     /* find the clock and enable it */

  26.     i2c->dev = &pdev->dev;
  27.     i2c->clk = clk_get(&pdev->dev, "i2c");
  28.     if (IS_ERR(i2c->clk)) {
  29.         dev_err(&pdev->dev, "cannot get clock\n");
  30.         ret = -ENOENT;
  31.         goto err_noclk;
  32.     }

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

  34.     clk_enable(i2c->clk);

  35.     /* map the registers */

  36.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  37.     if (res == NULL) {
  38.         dev_err(&pdev->dev, "cannot find IO resource\n");
  39.         ret = -ENOENT;
  40.         goto err_clk;
  41.     }

  42.     i2c->ioarea = request_mem_region(res->start, resource_size(res),
  43.                      pdev->name);

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

  49.     i2c->regs = ioremap(res->start, resource_size(res));

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

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

  57.     /* setup info block for the i2c core */

  58.     i2c->adap.algo_data = i2c;
  59.     i2c->adap.dev.parent = &pdev->dev;

  60.     /* initialise the i2c controller */

  61.     ret = s3c24xx_i2c_init(i2c);
  62.     if (ret != 0)
  63.         goto err_iomap;

  64.     /* find the IRQ for this unit (note, this relies on the init call to
  65.      * ensure no current IRQs pending
  66.      */

  67.     i2c->irq = ret = platform_get_irq(pdev, 0);
  68.     if (ret <= 0) {
  69.         dev_err(&pdev->dev, "cannot find IRQ\n");
  70.         goto err_iomap;
  71.     }

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

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

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

  83.     /* Note, previous versions of the driver used i2c_add_adapter()
  84.      * to add the bus at any number. We now pass the bus number via
  85.      * the platform data, so if unset it will now default to always
  86.      * being bus 0.
  87.      */

  88.     i2c->adap.nr = pdata->bus_num;

  89.     ret = i2c_add_numbered_adapter(&i2c->adap);
  90.     if (ret < 0) {
  91.         dev_err(&pdev->dev, "failed to add bus to i2c core\n");
  92.         goto err_cpufreq;
  93.     }

  94.     platform_set_drvdata(pdev, i2c);

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

  97.  err_cpufreq:
  98.     s3c24xx_i2c_deregister_cpufreq(i2c);

  99.  err_irq:
  100.     free_irq(i2c->irq, i2c);

  101.  err_iomap:
  102.     iounmap(i2c->regs);

  103.  err_ioarea:
  104.     release_resource(i2c->ioarea);
  105.     kfree(i2c->ioarea);

  106.  err_clk:
  107.     clk_disable(i2c->clk);
  108.     clk_put(i2c->clk);

  109.  err_noclk:
  110.     kfree(i2c);
  111.     return ret;
  112. }

  113. /* s3c24xx_i2c_remove
  114.  *
  115.  * called when device is removed from the bus
  116. */

  117. static int s3c24xx_i2c_remove(struct platform_device *pdev)
  118. {
  119.     struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);

  120.     s3c24xx_i2c_deregister_cpufreq(i2c);

  121.     i2c_del_adapter(&i2c->adap);
  122.     free_irq(i2c->irq, i2c);

  123.     clk_disable(i2c->clk);
  124.     clk_put(i2c->clk);

  125.     iounmap(i2c->regs);

  126.     release_resource(i2c->ioarea);
  127.     kfree(i2c->ioarea);
  128.     kfree(i2c);

  129.     return 0;
  130. }


  1. static struct s3c24xx_i2c s3c24xx_i2c = {
  2.  .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock),
  3.  .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
  4.  .tx_setup = 50,
  5.  .adap = {
  6.   .name = "s3c2410-i2c",
  7.   .owner = THIS_MODULE,
  8.   .algo = &s3c24xx_i2c_algorithm, //i2c适配器能力
  9.   .retries = 2,
  10.   .class = I2C_CLASS_HWMON,
  11.  },
  12. };

  1. static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
  2.  .master_xfer = s3c24xx_i2c_xfer,
  3.  .functionality = s3c24xx_i2c_func,
  4. };

 
 
上一篇:I2C协议
下一篇:四种模式的IIC驱动编写介绍