<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 3.4.2內(nèi)核下的I2C驅(qū)動(dòng)框架解析

          3.4.2內(nèi)核下的I2C驅(qū)動(dòng)框架解析

          作者: 時(shí)間:2016-11-21 來源:網(wǎng)絡(luò) 收藏
          第一種方法:
          at24cxx_drv.c源碼:
          #include "linux/kernel.h"
          #include "linux/module.h"
          #include "linux/platform_device.h"
          #include "linux/i2c.h"
          #include "linux/err.h"
          #include "linux/regmap.h"
          #include "linux/slab.h"
          static int __devinit at24cxx_probe(struct i2c_client *client,
          const struct i2c_device_id *id)
          {
          printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__);
          return 0;
          }
          static int __devexit at24cxx_remove(struct i2c_client *client)
          {
          printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__);
          return 0;
          }
          static const struct i2c_device_id at24cxx_id_table[] = {
          { "at24c08", 0 },
          {}
          };
          // 1. 分配/設(shè)置i2c_driver //
          static struct i2c_driver at24cxx_driver = {
          .driver = {
          .name = "100ask",
          .owner = THIS_MODULE,
          },
          .probe = at24cxx_probe,
          .remove = __devexit_p(at24cxx_remove),
          .id_table = at24cxx_id_table,
          };
          static int at24cxx_drv_init(void)
          {
          // 2. 注冊(cè)i2c_driver //
          i2c_add_driver(&at24cxx_driver);
          return 0;
          }
          static void at24cxx_drv_exit(void)
          {
          i2c_del_driver(&at24cxx_driver);
          }
          module_init(at24cxx_drv_init);
          module_exit(at24cxx_drv_exit);
          MODULE_LICENSE("GPL");
          at24cxx_dev.c源碼:
          #include "linux/kernel.h"
          #include "linux/module.h"
          #include "linux/platform_device.h"
          #include "linux/i2c.h"
          #include "linux/err.h"
          #include "linux/regmap.h"
          #include "linux/slab.h"
          static struct i2c_board_info at24cxx_info = {
          I2C_BOARD_INFO("at24c08", 0x50),
          };
          static struct i2c_client *at24cxx_client;
          static int at24cxx_dev_init(void)
          {
          struct i2c_adapter *i2c_adap;
          i2c_adap = i2c_get_adapter(0);
          at24cxx_client = i2c_new_device(i2c_adap, &at24cxx_info);
          i2c_put_adapter(i2c_adap);
          return 0;
          }
          static void at24cxx_dev_exit(void)
          {
          i2c_unregister_device(at24cxx_client);
          }
          module_init(at24cxx_dev_init);
          module_exit(at24cxx_dev_exit);
          MODULE_LICENSE("GPL");
          ===============================================================
          第二種方法:
          at24cxx_drv.c源碼:
          #include "linux/kernel.h"
          #include "linux/module.h"
          #include "linux/platform_device.h"
          #include "linux/i2c.h"
          #include "linux/err.h"
          #include "linux/regmap.h"
          #include "linux/slab.h"
          static int __devinit at24cxx_probe(struct i2c_client *client,
          const struct i2c_device_id *id)
          {
          printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__);
          return 0;
          }
          static int __devexit at24cxx_remove(struct i2c_client *client)
          {
          printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__);
          return 0;
          }
          static const struct i2c_device_id at24cxx_id_table[] = {
          { "at24c08", 0 },
          {}
          };
          // 1. 分配/設(shè)置i2c_driver //
          static struct i2c_driver at24cxx_driver = {
          .driver = {
          .name = "100ask",
          .owner = THIS_MODULE,
          },
          .probe = at24cxx_probe,
          .remove = __devexit_p(at24cxx_remove),
          .id_table = at24cxx_id_table,
          };
          static int at24cxx_drv_init(void)
          {
          // 2. 注冊(cè)i2c_driver //
          i2c_add_driver(&at24cxx_driver);
          return 0;
          }
          static void at24cxx_drv_exit(void)
          {
          i2c_del_driver(&at24cxx_driver);
          }
          module_init(at24cxx_drv_init);
          module_exit(at24cxx_drv_exit);
          MODULE_LICENSE("GPL");
          at24cxx_dev.c源碼:
          #include "linux/kernel.h"
          #include "linux/module.h"
          #include "linux/platform_device.h"
          #include "linux/i2c.h"
          #include "linux/err.h"
          #include "linux/regmap.h"
          #include "linux/slab.h"
          static struct i2c_client *at24cxx_client;
          static const unsigned short addr_list[] = { 0x60, 0x50, I2C_CLIENT_END };
          static int at24cxx_dev_init(void)
          {
          struct i2c_adapter *i2c_adap;
          struct i2c_board_info at24cxx_info;
          memset(&at24cxx_info, 0, sizeof(struct i2c_board_info));
          strlcpy(at24cxx_info.type, "at24c08", I2C_NAME_SIZE);
          i2c_adap = i2c_get_adapter(0);
          at24cxx_client = i2c_new_probed_device(i2c_adap, &at24cxx_info, addr_list, NULL);
          i2c_put_adapter(i2c_adap);
          if (at24cxx_client)
          return 0;
          else
          return -ENODEV;
          }
          static void at24cxx_dev_exit(void)
          {
          i2c_unregister_device(at24cxx_client);
          }
          module_init(at24cxx_dev_init);
          module_exit(at24cxx_dev_exit);
          MODULE_LICENSE("GPL");
          =============================================================
          第四種方法:
          at24cxx_drv.c源碼:
          #include "linux/kernel.h"
          #include "linux/module.h"
          #include "linux/platform_device.h"
          #include "linux/i2c.h"
          #include "linux/err.h"
          #include "linux/regmap.h"
          #include "linux/slab.h"
          static int __devinit at24cxx_probe(struct i2c_client *client,
          const struct i2c_device_id *id)
          {
          printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__);
          return 0;
          }
          static int __devexit at24cxx_remove(struct i2c_client *client)
          {
          printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__);
          return 0;
          }
          static const struct i2c_device_id at24cxx_id_table[] = {
          { "at24c08", 0 },
          {}
          };
          static int at24cxx_detect(struct i2c_client *client,
          struct i2c_board_info *info)
          {
          // 能運(yùn)行到這里, 表示該addr的設(shè)備是存在的
          * 但是有些設(shè)備單憑地址無法分辨(A芯片的地址是0x50, B芯片的地址也是0x50)
          * 還需要進(jìn)一步讀寫I2C設(shè)備來分辨是哪款芯片
          * detect就是用來進(jìn)一步分辨這個(gè)芯片是哪一款,并且設(shè)置info->type
          //
          printk("at24cxx_detect : addr = 0x%xn", client->addr);
          // 進(jìn)一步判斷是哪一款 //
          strlcpy(info->type, "at24c08", I2C_NAME_SIZE);
          return 0;
          }
          static const unsigned short addr_list[] = { 0x60, 0x50, I2C_CLIENT_END };
          // 1. 分配/設(shè)置i2c_driver //
          static struct i2c_driver at24cxx_driver = {
          .class = I2C_CLASS_HWMON, // 表示去哪些適配器上找設(shè)備 //
          .driver = {
          .name = "100ask",
          .owner = THIS_MODULE,
          },
          .probe = at24cxx_probe,
          .remove = __devexit_p(at24cxx_remove),
          .id_table = at24cxx_id_table,
          .detect = at24cxx_detect, // 用這個(gè)函數(shù)來檢測(cè)設(shè)備確實(shí)存在 //
          .address_list = addr_list, // 這些設(shè)備的地址 //
          };
          static int at24cxx_drv_init(void)
          {
          // 2. 注冊(cè)i2c_driver //
          i2c_add_driver(&at24cxx_driver);
          return 0;
          }
          static void at24cxx_drv_exit(void)
          {
          i2c_del_driver(&at24cxx_driver);
          }
          module_init(at24cxx_drv_init);
          module_exit(at24cxx_drv_exit);
          MODULE_LICENSE("GPL");
          ===============================================================
          1. 框架
          1.1 硬件協(xié)議簡(jiǎn)介
          1.2 驅(qū)動(dòng)框架
          1.3 bus-drv-dev模型及寫程序
          a. 設(shè)備的4種構(gòu)建方法(對(duì)于以下4種方法建議使用前3種,第四種方法迫不得已情況下使用)
          a.1 定義一個(gè)i2c_board_info, 里面有:名字, 設(shè)備地址
          然后i2c_register_board_info(busnum, ...) (把它們放入__i2c_board_list鏈表)
          list_add_tail(&devinfo->list, &__i2c_board_list);
          鏈表何時(shí)使用:
          i2c_register_adapter > i2c_scan_static_board_info > i2c_new_device
          使用限制:必須在 i2c_register_adapter 之前 i2c_register_board_info
          所以:不適合我們動(dòng)態(tài)加載insmod
          a.2 直接i2c_new_device, i2c_new_probed_device
          a.2.1 i2c_new_device : 認(rèn)為設(shè)備肯定存在
          a.2.2 i2c_new_probed_device :對(duì)于"已經(jīng)識(shí)別出來的設(shè)備"(probed_device),才會(huì)創(chuàng)建("new")
          i2c_new_probed_device
          probe(adap, addr_list[i]) // 確定設(shè)備是否真實(shí)存在 //
          info->addr = addr_list[i];
          i2c_new_device(adap, info);
          a.3 從用戶空間創(chuàng)建設(shè)備
          創(chuàng)建設(shè)備
          echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-0/new_device
          導(dǎo)致i2c_new_device被調(diào)用
          刪除設(shè)備
          echo 0x50 > /sys/class/i2c-adapter/i2c-0/delete_device
          導(dǎo)致i2c_unregister_device
          a.4 前面的3種方法都要事先確定適配器(I2C總線,I2C控制器)
          如果我事先并不知道這個(gè)I2C設(shè)備在哪個(gè)適配器上,怎么辦?去class表示的所有的適配器上查找
          有上一些I2C設(shè)備的地址是一樣,怎么繼續(xù)分配它是哪一款?用detect函數(shù)
          static struct i2c_driver at24cxx_driver = {
          .class = I2C_CLASS_HWMON, // 表示去哪些適配器上找設(shè)備 //
          .driver = {
          .name = "100ask",
          .owner = THIS_MODULE,
          },
          .probe = at24cxx_probe,
          .remove = __devexit_p(at24cxx_remove),
          .id_table = at24cxx_id_table,
          .detect = at24cxx_detect, // 用這個(gè)函數(shù)來檢測(cè)設(shè)備確實(shí)存在 //
          .address_list = addr_list, // 這些設(shè)備的地址 //
          };
          去"class表示的這一類"I2C適配器,用"detect函數(shù)"來確定能否找到"address_list里的設(shè)備",
          如果能找到就調(diào)用i2c_new_device來注冊(cè)i2c_client, 這會(huì)和i2c_driver的id_table比較,
          如果匹配,調(diào)用probe
          i2c_add_driver
          i2c_register_driver
          a. at24cxx_driver放入i2c_bus_type的drv鏈表
          并且從dev鏈表里取出能匹配的i2c_client并調(diào)用probe
          driver_register
          b. 對(duì)于每一個(gè)適配器,調(diào)用__process_new_driver
          對(duì)于每一個(gè)適配器,調(diào)用它的函數(shù)確定address_list里的設(shè)備是否存在
          如果存在,再調(diào)用detect進(jìn)一步確定、設(shè)置,然后i2c_new_device
          // Walk the adapters that are already present //
          i2c_for_each_dev(driver, __process_new_driver);
          __process_new_driver
          i2c_do_add_adapter
          // Detect supported devices on that bus, and instantiate them //
          i2c_detect(adap, driver);
          for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
          err = i2c_detect_address(temp_client, driver);
          // 判斷這個(gè)設(shè)備是否存在:簡(jiǎn)單的發(fā)出S信號(hào)確定有ACK //
          if (!i2c_default_probe(adapter, addr))
          return 0;
          memset(&info, 0, sizeof(struct i2c_board_info));
          info.addr = addr;
          // 設(shè)置info.type
          err = driver->detect(temp_client, &info);
          i2c_new_device
          b. 驅(qū)動(dòng)的寫法
          2. 完善設(shè)備驅(qū)動(dòng)程序
          3. 不自己寫驅(qū)動(dòng)直接訪問
          Device Drivers
          I2C support
          <*> I2C device interface
          4. 編寫"總線(適配器adapter)"驅(qū)動(dòng)
          Device Drivers
          I2C support
          I2C Hardware Bus support
          < > S3C2410 I2C Driver
          nfs 30000000 192.168.1.123:/work/nfs_root/uImage_noi2cbus; bootm 30000000


          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();