新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 3.4.2內核下的I2C驅動框架解析

        3.4.2內核下的I2C驅動框架解析

        作者: 時間:2016-11-21 來源:網絡 收藏
        第一種方法:
        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. 分配/設置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. 注冊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. 分配/設置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. 注冊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)
        {
        // 能運行到這里, 表示該addr的設備是存在的
        * 但是有些設備單憑地址無法分辨(A芯片的地址是0x50, B芯片的地址也是0x50)
        * 還需要進一步讀寫I2C設備來分辨是哪款芯片
        * detect就是用來進一步分辨這個芯片是哪一款,并且設置info->type
        //
        printk("at24cxx_detect : addr = 0x%xn", client->addr);
        // 進一步判斷是哪一款 //
        strlcpy(info->type, "at24c08", I2C_NAME_SIZE);
        return 0;
        }
        static const unsigned short addr_list[] = { 0x60, 0x50, I2C_CLIENT_END };
        // 1. 分配/設置i2c_driver //
        static struct i2c_driver at24cxx_driver = {
        .class = I2C_CLASS_HWMON, // 表示去哪些適配器上找設備 //
        .driver = {
        .name = "100ask",
        .owner = THIS_MODULE,
        },
        .probe = at24cxx_probe,
        .remove = __devexit_p(at24cxx_remove),
        .id_table = at24cxx_id_table,
        .detect = at24cxx_detect, // 用這個函數來檢測設備確實存在 //
        .address_list = addr_list, // 這些設備的地址 //
        };
        static int at24cxx_drv_init(void)
        {
        // 2. 注冊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 硬件協議簡介
        1.2 驅動框架
        1.3 bus-drv-dev模型及寫程序
        a. 設備的4種構建方法(對于以下4種方法建議使用前3種,第四種方法迫不得已情況下使用)
        a.1 定義一個i2c_board_info, 里面有:名字, 設備地址
        然后i2c_register_board_info(busnum, ...) (把它們放入__i2c_board_list鏈表)
        list_add_tail(&devinfo->list, &__i2c_board_list);
        鏈表何時使用:
        i2c_register_adapter > i2c_scan_static_board_info > i2c_new_device
        使用限制:必須在 i2c_register_adapter 之前 i2c_register_board_info
        所以:不適合我們動態加載insmod
        a.2 直接i2c_new_device, i2c_new_probed_device
        a.2.1 i2c_new_device : 認為設備肯定存在
        a.2.2 i2c_new_probed_device :對于"已經識別出來的設備"(probed_device),才會創建("new")
        i2c_new_probed_device
        probe(adap, addr_list[i]) // 確定設備是否真實存在 //
        info->addr = addr_list[i];
        i2c_new_device(adap, info);
        a.3 從用戶空間創建設備
        創建設備
        echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-0/new_device
        導致i2c_new_device被調用
        刪除設備
        echo 0x50 > /sys/class/i2c-adapter/i2c-0/delete_device
        導致i2c_unregister_device
        a.4 前面的3種方法都要事先確定適配器(I2C總線,I2C控制器)
        如果我事先并不知道這個I2C設備在哪個適配器上,怎么辦?去class表示的所有的適配器上查找
        有上一些I2C設備的地址是一樣,怎么繼續分配它是哪一款?用detect函數
        static struct i2c_driver at24cxx_driver = {
        .class = I2C_CLASS_HWMON, // 表示去哪些適配器上找設備 //
        .driver = {
        .name = "100ask",
        .owner = THIS_MODULE,
        },
        .probe = at24cxx_probe,
        .remove = __devexit_p(at24cxx_remove),
        .id_table = at24cxx_id_table,
        .detect = at24cxx_detect, // 用這個函數來檢測設備確實存在 //
        .address_list = addr_list, // 這些設備的地址 //
        };
        去"class表示的這一類"I2C適配器,用"detect函數"來確定能否找到"address_list里的設備",
        如果能找到就調用i2c_new_device來注冊i2c_client, 這會和i2c_driver的id_table比較,
        如果匹配,調用probe
        i2c_add_driver
        i2c_register_driver
        a. at24cxx_driver放入i2c_bus_type的drv鏈表
        并且從dev鏈表里取出能匹配的i2c_client并調用probe
        driver_register
        b. 對于每一個適配器,調用__process_new_driver
        對于每一個適配器,調用它的函數確定address_list里的設備是否存在
        如果存在,再調用detect進一步確定、設置,然后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);
        // 判斷這個設備是否存在:簡單的發出S信號確定有ACK //
        if (!i2c_default_probe(adapter, addr))
        return 0;
        memset(&info, 0, sizeof(struct i2c_board_info));
        info.addr = addr;
        // 設置info.type
        err = driver->detect(temp_client, &info);
        i2c_new_device
        b. 驅動的寫法
        2. 完善設備驅動程序
        3. 不自己寫驅動直接訪問
        Device Drivers
        I2C support
        <*> I2C device interface
        4. 編寫"總線(適配器adapter)"驅動
        Device Drivers
        I2C support
        I2C Hardware Bus support
        < > S3C2410 I2C Driver
        nfs 30000000 192.168.1.123:/work/nfs_root/uImage_noi2cbus; bootm 30000000


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 黑水县| 大田县| 宜黄县| 昌黎县| 新平| 华阴市| 绥宁县| 唐山市| 抚顺县| 云浮市| 达尔| 上杭县| 宜宾市| 定西市| 固阳县| 铁岭县| 长垣县| 海口市| 绥宁县| 崇阳县| 浦城县| 婺源县| 岢岚县| 天祝| 江口县| 通城县| 进贤县| 石嘴山市| 绿春县| 延吉市| 阿坝| 邛崃市| 宣城市| 井研县| 双城市| 都昌县| 思南县| 白沙| 陈巴尔虎旗| 丹巴县| 酉阳|