Linux_IIC_Driver系統(tǒng)分析

IIC系統(tǒng)分析

by:Cat_With_Apple/吃蘋果的貓轉(zhuǎn)載請主名

//只是調(diào)用順序 不是調(diào)用關(guān)系
mini2440_init()
├──s3c_i2c0_set_platdata()//set bus_number
├──i2c_register_board_info()
├──platform_add_devices()//add i2c設(shè)備

s3c24xx_i2c_probe()
├──i2c_register_adapter()
├──2c_scan_static_board_info()
│   ├──2c_new_device()//add client根據(jù)bus_number匹配client和adapte

i2c_device_probe()
├──client->driver = driver;
├──driver->probe()

  1. 在i2c_init()函數(shù)中注冊 i2c_bus_type
//i2c-core.c
static int __init i2c_init(void)
{
    ...
    bus_register(&i2c_bus_type);
    ...
}
postcore_initcall(i2c_init); //這里表示代碼會在內(nèi)核初始化階段完成
  1. 然后就要考慮 i2c_client i2c_driver adapter是如何注冊到i2c_bus_type喻杈?
    請自己先思考這個問題,然后試著自己追代碼,這里這個教程只是提供追代碼的思路。
// mach-mini2440.c這個函數(shù)在內(nèi)核完成一定的初始化之后執(zhí)行
mini2440_init(void)
{
    ...
    s3c_i2c0_set_platdata(NULL);  //主要完成adapter額外信息的配制--bus_num = 0;
    i2c_register_board_info(0, mini2440_i2c_devs,
                ARRAY_SIZE(mini2440_i2c_devs)); //
    platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
    ...

}

MACHINE_START(MINI2440, "MINI2440")
    /* Maintainer: Michel Pollet <buserror@gmail.com> */
    .atag_offset    = 0x100,
    .map_io     = mini2440_map_io,
    .init_machine   = mini2440_init,
    .init_irq   = s3c24xx_init_irq,
    .timer      = &s3c24xx_timer,
    .restart    = s3c244x_restart,
MACHINE_END
s3c_i2c0_set_platdata(NULL);
{
    struct s3c2410_platform_i2c *npd;

    if (!pd) {
        pd = &default_i2c_data;
        pd->bus_num = 0; //這里的number會在后面注冊adapter時候使用到
    }

    npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c),
                   &s3c_device_i2c0);  //將i2c控制器信息,即adapter更啄,放在s3c_device_i2c0中

    if (!npd->cfg_gpio)
        npd->cfg_gpio = s3c_i2c0_cfg_gpio;
}

int __init
i2c_register_board_info(int busnum,
    struct i2c_board_info const *info, unsigned len)
{
    int status;
    for (status = 0; len; len--, info++) { //循環(huán)info中的內(nèi)容
        struct i2c_devinfo  *devinfo;

        devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
        ...
        devinfo->busnum = busnum;
        devinfo->board_info = *info;
        list_add_tail(&devinfo->list, &__i2c_board_list);//將設(shè)備信息注冊到__i2c_board_list這個鏈表中
    }
    return status;
}

//linux-3.4/arch/arm/plat-samsung/devs.c
struct platform_device s3c_device_i2c0 = {
    .name       = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
    .id     = 0,
#else
    .id     = -1,
#endif
    .num_resources  = ARRAY_SIZE(s3c_i2c0_resource),
    .resource   = s3c_i2c0_resource,
};


//mach_mini2440.c
static struct platform_device *mini2440_devices[] __initdata = {
    ...
    &s3c_device_i2c0
    ...
}

platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));


3.接下分析s3c_device_i2c0對應(yīng)的driver

//linux-3.4/drivers/i2c/busses/i2c-s3c2410.c
struct s3c24xx_i2c {
    ...
    struct i2c_adapter  adap;
    ...
    struct s3c2410_platform_i2c *pdata;
    ...
};


static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
    ...//
    struct s3c2410_platform_i2c *pdata = NULL;
    pdata = pdev->dev.platform_data;
    ...

    struct s3c24xx_i2c *i2c;
    i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
    if (pdata)
        memcpy(i2c->pdata, pdata, sizeof(*pdata));
    ...


    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->adap.nr = i2c->pdata->bus_num; //這里使用前面s3c_i2c0_set_platdata(NULL)提供的bus_num
    i2c->adap.dev.of_node = pdev->dev.of_node;
    ret = i2c_add_numbered_adapter(&i2c->adap);//注冊adapter



}


////linux-3.4/drivers/i2c/i2c-core.c
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
    ...
    i2c_register_adapter(adap);
    ...
}

static int i2c_register_adapter(struct i2c_adapter *adap)
{
    ...
    dev_set_name(&adap->dev, "i2c-%d", adap->nr);
    //同i2c_client 和i2c_driver一樣是i2c_bus_type
    //這樣會導(dǎo)致注冊這個三個結(jié)構(gòu)體會使用相同的mach函數(shù),在后面會分析內(nèi)核是如何解決的
    adap->dev.bus = &i2c_bus_type;
    adap->dev.type = &i2c_adapter_type;
    res = device_register(&adap->dev);//注冊device到i2c_bus中

    ...
    /*
    *這里會使用之前i2c_register_board_info()提供的client信息
    *同時注冊client到i2c_bus上面
     */
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);
    ...

}
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
    /*
    *遍歷__i2c_board_list注冊新的client到總線上
     */
    list_for_each_entry(devinfo, &__i2c_board_list, list) {
        if (devinfo->busnum == adapter->nr
                && !i2c_new_device(adapter,//關(guān)鍵函數(shù)
                        &devinfo->board_info))
    }

}

struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
    struct i2c_client   *client;
    ...
    client = kzalloc(sizeof *client, GFP_KERNEL);
    client->adapter = adap;//將client和adapter聯(lián)系到一起

    client->addr = info->addr;
    client->irq = info->irq;

    client->dev.bus = &i2c_bus_type;
    client->dev.type = &i2c_client_type;//mach函數(shù)根據(jù)這個參數(shù)判讀這個設(shè)備是client還是adapter
    status = device_register(&client->dev);//注冊client

    ...
    return client;
}

4.到這里client和adapter都已經(jīng)注冊到了i2c_bus上了,還差i2c_driver
i2c_driver是在模塊的module_init中注冊的帮孔,不需要分析

5.最后就要看i2c_driver和i2c_client的匹配的


static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
    struct i2c_client   *client = i2c_verify_client(dev);//這里驗證設(shè)備是否是i2c_client
    struct i2c_driver   *driver;

    if (!client)//如果不是client,即是adapter不撑,這里直接返回
        return 0;
    /* Attempt an OF style match */
    if (of_driver_match_device(dev, drv))
        return 1;
    driver = to_i2c_driver(drv);
    /* match on an id table if there is one */
    if (driver->id_table)
        return i2c_match_id(driver->id_table, client) != NULL;
    return 0;
}

struct i2c_client *i2c_verify_client(struct device *dev)
{
    return (dev->type == &i2c_client_type)  //根據(jù)dev->type來判斷
            ? to_i2c_client(dev)
            : NULL;
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末文兢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子焕檬,更是在濱河造成了極大的恐慌姆坚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件实愚,死亡現(xiàn)場離奇詭異兼呵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)腊敲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門击喂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碰辅,你說我怎么就攤上這事懂昂。” “怎么了没宾?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵凌彬,是天一觀的道長潮尝。 經(jīng)常有香客問我,道長饿序,這世上最難降的妖魔是什么勉失? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮原探,結(jié)果婚禮上乱凿,老公的妹妹穿的比我還像新娘。我一直安慰自己咽弦,他們只是感情好徒蟆,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著型型,像睡著了一般段审。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闹蒜,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天寺枉,我揣著相機(jī)與錄音,去河邊找鬼绷落。 笑死姥闪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的砌烁。 我是一名探鬼主播筐喳,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼函喉!你這毒婦竟也來了避归?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤管呵,失蹤者是張志新(化名)和其女友劉穎梳毙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撇寞,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡顿天,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔑担。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡咽白,死狀恐怖啤握,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晶框,我是刑警寧澤排抬,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布懂从,位于F島的核電站,受9級特大地震影響蹲蒲,放射性物質(zhì)發(fā)生泄漏番甩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一届搁、第九天 我趴在偏房一處隱蔽的房頂上張望缘薛。 院中可真熱鬧,春花似錦卡睦、人聲如沸宴胧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恕齐。三九已至,卻和暖如春瞬逊,著一層夾襖步出監(jiān)牢的瞬間显歧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工确镊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留追迟,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓骚腥,卻偏偏與公主長得像敦间,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子束铭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • linux設(shè)備模型bus,device,driver作者 codercjg 在 10 十一月 2015, 2:43...
    codercjg閱讀 415評論 0 1
  • 簡介 I2C驅(qū)動由I2C核心,I2C總線驅(qū)動和I2C設(shè)備驅(qū)動組成.I2C核心是I2C總線驅(qū)動和I2C設(shè)備驅(qū)動的中間...
    傀儡世界閱讀 1,117評論 0 1
  • Linux i2c system I2C總線是由PHILIPS公司開發(fā)的兩線式串行總線廓块,每個連接到總線的器件都可以...
    Creator_Ly閱讀 1,830評論 0 8
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)契沫,斷路器带猴,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 參考鏈接:http://blog.csdn.net/sweetsnow24/article/details/863...
    Tony1213閱讀 4,440評論 0 0