<var id="fnfpo"><source id="fnfpo"></source></var>
<rp id="fnfpo"></rp>

<em id="fnfpo"><object id="fnfpo"><input id="fnfpo"></input></object></em>
<em id="fnfpo"><acronym id="fnfpo"></acronym></em>
  • <th id="fnfpo"><track id="fnfpo"></track></th>
  • <progress id="fnfpo"><track id="fnfpo"></track></progress>
  • <tbody id="fnfpo"><pre id="fnfpo"></pre></tbody>

  • x
    x

    思路清晰!Linux設備驅動子系統之I2C

    發布時間:2017-12-2 09:48    發布者:技術小白
    1. Overview
    2. Data Structure
    3. Adapter
    4. I2C-core
    5. Slave Device

    1. Overview
    1.1 Definition
    ·  I2C           Inter-Integrated Circuit
    ·  SMBUS      System Management Bus, the I2C subset

    1.2 Characteristics
    ·  The amount of data exchanged is small.
    ·  The required data transfer rate is low.

    1.3 Speed
    ·  Fast speed     400 kbps
    ·  Full speed      100 kbps
      1.4 Topology

    2 Data Structure

    理解數據結構對理解整個驅動程序子系統是很重要的。I2C的主要有兩大數據結構,struct i2c_client 和 struct

    i2c_adapter。

      2.1 i2c_client

        struct i2c_client {
            unsigned short flags;  /* div., see below  */
            unsigned short addr;  /* chip address */
            char name[I2C_NAME_SIZE];
            struct i2c_adapter *adapter; /* the adapter we sit on */
            struct i2c_driver *driver; /* and our access routines */
            struct device dev;  /* the device structure  */
            int irq;   /* irq issued by device (or -1) */
            char driver_name[KOBJ_NAME_LEN];
            struct list_head list;  /* DEPRECATED */
            struct completion released;
    };

    struct i2c_client代表一個掛載到i2c總線上的i2c從設備,該設備所需要的數據結構,其中包括
    · 該i2c從設備所依附的i2c主設備 struct i2c_adapter *adapter
    · 該i2c從設備的驅動程序struct i2c_driver *driver
    · 作為i2c從設備所通用的成員變量,比如addr, name等
    · 該i2c從設備驅動所特有的數據,依附于dev->driver_data下

    2.2 i2c_adapter
         struct i2c_adapter {
            struct module *owner;
            unsigned int id;
            unsigned int class;
            const struct i2c_algorithm *algo; /* the algorithm to access the bus */
            void *algo_data;
            ... ...
         };

    struct i2c_adapter代表主芯片所支持的一個i2c主設備,該設備所需要的數據結構,

    其中,struct i2c_algorithm *algo是該i2c主設備傳輸數據的一種算法,或者說是在i2c總線上完成主從設備間數

    據通信的一種能力。
    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子系統的驅動,便圍繞這兩個數據結構展開,其主要步驟可總結為以下三步,
    · 實現i2c主設備驅動                (drivers/i2c/bus/*)
    · 注冊i2c從設備的i2c_client    (drivers/i2c/i2c-core)
    · 實現i2c從設備驅動

    3 Adapter
    內核目錄drivers/i2c下有兩個文件夾,algorithm和bus,其中bus存放i2c主設備的驅動,主設備驅動完成兩大

    任務,
    · 提供該i2c主設備與從設備間完成數據通信的能力
    · 完成該i2c_adapter和所有已知的i2c_client的注冊

    以i2c-pxa.c為例,
      /* drivers/i2c/bus/i2c-pxa.c */
    static int __init i2c_adap_pxa_init(void)
    {
    return platform_driver_register(&i2c_pxa_driver);
    }
    static struct platform_driver i2c_pxa_driver = {
    .probe  = i2c_pxa_probe,
    ... ...
    .id_table = i2c_pxa_id_table,
    };
    static int i2c_pxa_probe(struct platform_device *dev)
    {
    struct pxa_i2c *i2c;
      i2c->adap.algo = i2c_pxa_algorithm;             // 提供該i2c主設備與從設備間完成數據通信的能力
      i2c_add_numbered_adapter(&i2c->adap);      // 調用i2c-core.c中的接口函數,完成該i2c_adapter和

    i2c_client的注冊
      ... ...
    }
    static const struct i2c_algorithm i2c_pxa_algorithm = {
    .master_xfer = i2c_pxa_xfer,                  // 根據pxa具體芯片的要求,完成i2c數據傳輸
    .functionality = i2c_pxa_functionality,
    };

    4 I2C-core
    內核目錄drivers/i2c下的i2c-core.c,顧名思義,是內核為I2C提供的統一系統接口。

    看看i2c_add_numbered_adapter做了些什么,
    int i2c_add_numbered_adapter(struct i2c_adapter *adap)
    {
       ... ...
      status = i2c_register_adapter(adap);
      return status;
    }

    static int i2c_register_adapter(struct i2c_adapter *adap)
    {
       ... ...
      device_register(&adap->dev);     //完成I2C主設備adapter的注冊,即注冊object和發送uevent等
      i2c_scan_static_board_info(adap);      
       ... ...
    }

    i2c_scan_static_board_info(adap),此函數為整個I2C子系統的核心,它會去遍歷一個由I2C從設備組成的雙向

    循環鏈表,并完成所有I2C從設備的i2c_client的注冊,具體過程如下,
    static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
    {
    struct i2c_devinfo *devinfo;     //已經建立好了的I2C從設備鏈表

    list_for_each_entry(devinfo, &__i2c_board_list, list) {
         i2c_new_device(adapter,&devinfo->board_info);
         ... ...
    }
    }
    struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
    {
       ... ...
       i2c_attach_client(client);
       ... ...
    }
    int i2c_attach_client(struct i2c_client *client)
    {
       ... ...
       device_register(&client->dev);     //完成I2C從設備client的注冊
       ... ...
    }

    那么,這個I2C從設備組成的雙向循環鏈表,是什么時候通過什么方式建立起來的呢?

    以某重力感應設備為例,
    /* /arch/arm/mach-pxa/starwood_p1.c */
    static void __init saar_init(void)
    {
       ... ...
       i2c_register_board_info(0, ARRAY_AND_SIZE(saar_i2c_bma220_info));
       ... ...
    }
    static struct i2c_board_info saar_i2c_bma220_info[] = {
    {
      .driver_name = "bma220",
      .addr  = 0x0B,
      .irq  = IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO15)),
    },
    };
    /* drivers/i2c/i2c-boardinfo.c */
    int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
    {
       ... ...
      struct i2c_devinfo *devinfo;
      devinfo->board_info = *info;
      list_add_tail(&devinfo->list, &__i2c_board_list);    //將I2C從設備加入該鏈表中
       ... ...
    }

    所以,在系統初始化的過程中,我們可以通過 i2c_register_board_info,將所需要的I2C從設備加入一個名為

    __i2c_board_list雙向循環鏈表,系統在成功加載I2C主設備adapt后,就會對這張鏈表里所有I2C從設備逐一地

    完成 i2c_client的注冊。


    5 Slave Driver

    如果說硬件方面,I2C主設備已經集成在主芯片內,軟件方面,linux也為我們提供了相應的驅動程序,位于

    drivers/i2c/bus下,那么接下來I2C從設備驅動就變得容易得多。既然系統加載I2C主設備驅動時已經注冊了

    i2c_adapter和i2c_client,那么I2C從設備主要完成三大任務,
    · 系統初始化時添加以i2c_board_info為結構的I2C從設備的信息
    · 在I2C從設備驅動程序里使用i2c_adapter里所提供的算法,即實現I2C通信。
    · 將I2C從設備的特有數據結構掛在到i2c_client.dev->driver_data下。

    以重力感應裝置為例,
    static int __init BMA220_init(void)
    {
    return i2c_add_driver(&bma220_driver);
    }
    static struct i2c_driver bma220_driver = {
    .driver = {
      .owner = THIS_MODULE,
      .name = "bma220",
    },
    .class  = I2C_CLASS_HWMON,
    .probe  = bma220_probe,
    .remove  = bma220_remove,
    };
    static int bma220_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
    struct bma220_data *data;      
    i2c_check_functionality(client->adapter, I2C_FUNC_I2C)
    i2c_smbus_read_word_data(client, 0x00);    // i2c-core提供的接口,利用i2c_adapter的算法實現I2C通信
    i2c_set_clientdata(bma220_client, data);      // 將設備的數據結構掛到i2c_client.dev->driver_data下
    misc_register(&bma_device);
    request_irq(client->irq, bma220_irq_handler, IRQF_TRIGGER_RISING, "bma220", &data->bma220);
    bma220_set_en_tt_xyz(0);
    bma220_reset_int();
    ... ...
    }

    信盈達靠技術打天下
    以下課程可免費試聽C語言、電子、PCB、STM32、Linux、FPGA、JAVA、安卓等。
    想學習的你和我聯系預約就可以免費聽課了。
    宋工企鵝號:35--24-65--90-88   Tel/WX:173--17--95--19--08



    本文地址:http://www.portaltwn.com/thread-520316-1-1.html     【打印本頁】

    本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
    您需要登錄后才可以發表評論 登錄 | 立即注冊

    廠商推薦

    • Microchip視頻專區
    • EtherCAT®和Microchip LAN925x從站控制器介紹培訓教程
    • MPLAB®模擬設計器——在線電源解決方案,加速設計
    • 讓您的模擬設計靈感,化為觸手可及的現實
    • 深度體驗Microchip自動輔助駕駛應用方案——2025巡展開啟報名!
    • 貿澤電子(Mouser)專區
    關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
    電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
    快速回復 返回頂部 返回列表
    精品一区二区三区自拍图片区_国产成人亚洲精品_亚洲Va欧美va国产综合888_久久亚洲国产精品五月天婷