Linux i 2 cサブシステム(四)i 2 c-s 3 c 24 xxから.c i 2 cコントローラ駆動の作成を見る

25928 ワード

「./drivers/i 2 c/busses/i 2 c-s 3 c 2410.c」は3.14.0カーネル中の三星SoCのi 2 cコントローラドライバであり、本稿ではこのプログラムの分析を通じて、複雑な詳細を剥離し、i 2 cホストコントローラドライバを記述するフレームワークとカーネルドライバを分析するフローをまとめることを試みた.

一致する前に

1287 static int __init i2c_adap_s3c_init(void)
1288 {
1289         return platform_driver_register(&s3c24xx_i2c_driver);
1290 }
1291 subsys_initcall(i2c_adap_s3c_init);

--1291-->ホストコントローラ駆動をシステム起動時に登録する--1289->この駆動はplatformバスに基づいており、デバイス情報の部分はボードレベルファイルi 2 c_board_infoではplatformとして説明されています.デバイスはカーネル起動に伴って登録されているので、コントローラ駆動はシステム起動時に動作します.
1275 static struct platform_driver s3c24xx_i2c_driver = {
1276         .probe          = s3c24xx_i2c_probe,
1277         .remove         = s3c24xx_i2c_remove,
1278         .id_table       = s3c24xx_driver_ids,
1279         .driver         = {
1280                 .owner  = THIS_MODULE,
1281                 .name   = "s3c-i2c",
1282                 .pm     = S3C24XX_DEV_PM_OPS,
1283                 .of_match_table = of_match_ptr(s3c24xx_i2c_match),
1284         },
1285 };

従うplatform作成である以上、すべての情報は1つのplatformでなければなりません.driverでは、分析もこのオブジェクトの周りに展開されます.
--1276-->probe関数、最も重要な関数--1278-->マッチングのためのidテーブルは、プラットフォームファイルで作成されたデバイス情報であるため、このドメインをマッチングの根拠として使用します.
 132 static struct platform_device_id s3c24xx_driver_ids[] = {                                          
 133         {
 134                 .name           = "s3c2410-i2c",
 135                 .driver_data    = 0,
 136         }, {
 137                 .name           = "s3c2440-i2c",
 138                 .driver_data    = QUIRK_S3C2440,
 139         }, {
 140                 .name           = "s3c2440-hdmiphy-i2c",
 141                 .driver_data    = QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO,
 142         }, { }, 
 143 }; 

「arch/arm/plat-samsung」で対応するデバイス情報を見つけることができます.
 485 struct platform_device s3c_device_i2c0 = {
 486         .name           = "s3c2410-i2c",
 487         .id             = 0,
 488         .num_resources  = ARRAY_SIZE(s3c_i2c0_resource),
 489         .resource       = s3c_i2c0_resource,
 490 };

両者が一致するとprobeが実行されます!

照合後


一致すると、分析プロセスは少し変化し、駆動開発はすべてオブジェクト向けの思想に基づいており、カーネルは私たちに多くの「クラス」をカプセル化しているが、私たちが具体的な駆動を開発するときは、やはりそれを「継承」し、さらに具体的な設備に対するリソースオブジェクトを作成し、リソースオブジェクトは駆動中の多くの関数の共通リソースを管理し、駆動運転中のリソース管理者と橋渡しである.主にカーネルクラス+リソース(io,irq,クロック,レジスタ)+の状態表現+その他を含むため、設計駆動の仕事の中で重要な仕事の一つは「設計リソースクラス」である.次はサムスンのデザインのクラスで、私は副次的な部分を取り除きました.

リソースクラス


リソースオブジェクトは駆動動作全体の核心であり、すべての方法に必要なリソースはこのオブジェクトに対する操作であり、その設計は反復的なプロセスであるが、フレームワーク全体が結合された後、大きな変化はあるべきではない.
 103 struct s3c24xx_i2c {
 104         wait_queue_head_t       wait;
 108         struct i2c_msg          *msg;
 109         unsigned int            msg_num;
 110         unsigned int            msg_idx;
 111         unsigned int            msg_ptr;
 113         unsigned int            tx_setup;
 114         unsigned int            irq;
 116         enum s3c24xx_i2c_state  state;
 117         unsigned long           clkrate;
 119         void __iomem            *regs;
 120         struct clk              *clk;
 121         struct device           *dev;
 122         struct i2c_adapter      adap;
 124         struct s3c2410_platform_i2c     *pdata;
 125         int                     gpios[2];
 130 };

struct s3c24xx_i 2 c--108-->受け取ったi 2 c-core.c送ってきたi 2 c_msgオブジェクト配列ヘッダアドレス--109-->i 2 c_msg配列の要素個数--110-->i 2 c_msg配列要素のインデックス--114-->使用する割り込み番号--116-->現在のコントローラの状態を列挙量でSTATE_IDLE, STATE_START,STATE_READ,STATE_WRITE,STATE_STOP--117-->クロック周波数--120-->クロック--121-->はdeviceに属し、deviceに従って--122-->構築して使用するi 2 c_を管理するadapterオブジェクトは、前編のフレームワーク図に対応する124-->カプセル化されたプラットフォーム情報であり、各要素はスレーブアドレス、フラグビット、バス番号などを含む配列ヘッダアドレスである.

probe


Probeは主に「リソースの申請+初期化+インタフェースの提供」を担当し、probeの分析を通じて、駆動全体の構築について要領よく理解することができる.
1072 static int s3c24xx_i2c_probe(struct platform_device *pdev)
1073 {
1074         struct s3c24xx_i2c *i2c;
1075         struct s3c2410_platform_i2c *pdata = NULL;
1076         struct resource *res;
1077         int ret;
1078 
1079         if (!pdev->dev.of_node) {
1080                 pdata = dev_get_platdata(&pdev->dev);
1085         }
1086 
1087         i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
1092 
1093         i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1098 
1099         i2c->quirks = s3c24xx_get_device_quirks(pdev);
1100         if (pdata)
1101                 memcpy(i2c->pdata, pdata, sizeof(*pdata));
1102         else
1103                 s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
1104 
1105         strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
1106         i2c->adap.owner   = THIS_MODULE;
1107         i2c->adap.algo    = &s3c24xx_i2c_algorithm;
1108         i2c->adap.retries = 2;
1109         i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
1110         i2c->tx_setup     = 50;
1111 
1112         init_waitqueue_head(&i2c->wait);
1113 
1114         /* find the clock and enable it */
1116         i2c->dev = &pdev->dev;
1117         i2c->clk = devm_clk_get(&pdev->dev, "i2c");
1124 
1126         /* map the registers */
1128         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1129         i2c->regs = devm_ioremap_resource(&pdev->dev, res);
1136 
1137         /* setup info block for the i2c core */
1139         i2c->adap.algo_data = i2c;
1140         i2c->adap.dev.parent = &pdev->dev;
1141 
1142         i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
1143 
1144         /* inititalise the i2c gpio lines */
1146         if (i2c->pdata->cfg_gpio) {
1147                 i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
1148         } else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) {
1149                 return -EINVAL;
1150         }
1151 
1152         /* initialise the i2c controller */
1154         clk_prepare_enable(i2c->clk);
1155         ret = s3c24xx_i2c_init(i2c);
1156         clk_disable_unprepare(i2c->clk);
1161         /* find the IRQ for this unit (note, this relies on the init call to
1162          * ensure no current IRQs pending
1163          */
1165         if (!(i2c->quirks & QUIRK_POLL)) {
1166                 i2c->irq = ret = platform_get_irq(pdev, 0);
1171 
1172         ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
1173                                 dev_name(&pdev->dev), i2c);
1179         }
1180 
1181         ret = s3c24xx_i2c_register_cpufreq(i2c);
1192 
1193         i2c->adap.nr = i2c->pdata->bus_num;
1194         i2c->adap.dev.of_node = pdev->dev.of_node;
1196         ret = i2c_add_numbered_adapter(&i2c->adap);
1202 
1203         platform_set_drvdata(pdev, i2c);
1204 
1205         pm_runtime_enable(&pdev->dev);
1206         pm_runtime_enable(&i2c->adap.dev);
1209         return 0;
1210 }

s3c24xx_i2c_Probe()--1074-1077->ポインタと変数を用意し、入力されたオブジェクトからデータを抽出する準備をします.これはC 89の文法的要件ですが、この書き方は確かに快適で、知らない変数に出会ったら関数の先頭を探します--1079->pdev->dev.of_Nodeは空です.デバイスがデバイスツリーで取得されていないことを示します.dev_を呼び出します.get_platdata pdev->dev.oplatform_の取得Dataのデータは、明らかに、デバイスファイルを作成するときにここに隠されているのはs 3 c 2410_です.platform_i 2 cオブジェクトなので、pdataで取り出して使用する準備をします.1087-->pdev->devはdeviceタイプで、それを示すdetachをフラグとして自分のオブジェクトの空間を割り当て、割り当てられたヘッダアドレスをi 2 cに返します.ここではdevm_を使用していますkzalloc()関数devm_kzalloc()はkzalloc()と同様にカーネルメモリ割り当て関数ですがdevm_kzalloc()はデバイス(device)に関係しており、デバイス(device)がdetachedまたはドライバ(driver)によってアンインストールされると、メモリが自動的に解放されます.また、メモリが使用されていない場合は、関数devm_を使用できます.kfree()放出.一方、kzalloc()は手動で解放する必要があります(kfree()を使用します).ただし、エンジニアが注意深く検査しないと、メモリが漏洩する可能性があります.--1100-1033-->対応するs 3 c 2410が--1079--で取得された場合platform_i 2 cオブジェクトアドレスは、リソースオブジェクトの対応するドメインにコピーして保存します.そうしないと、自分でデバイスツリーに行って--1106-1101-->割り当てられた方法で、一部のリソースオブジェクトのドメインを直接初期化します--1112->リソースオブジェクトの待機キューヘッダwait_を初期化します.queue_head_t wait--1116->初期化リソースオブジェクトのdevice dev--1117->初期化リソースオブジェクトのstruct clk--1128->pdevのアドレスresourceを取得し、ioremapの後にリソースオブジェクトのregsドメインを初期化するために使用され、devm_ioremap_resource()は、同様にdeviceベースのリソース自動回収API--1139->カスタムリソースオブジェクトポインタをalgo_に隠すdataでは,--1203--の役割と同様にxfer()インタフェース関数に--1140->リソースオブジェクトのi 2 c_を初期化するadapterオブジェクトの一部のメンバーは、親デバイスがコントローラデバイスのdeviceドメインであることを指定します.1142->リソースオブジェクトのpctrlドメインを初期化し、devm_を使用します.pinctrl_get_select_default()--1147->to_の使用platform_デバイス(container_of)i 2 c->devでplatformを見つけますデバイスオブジェクト、コールバックcfg_gpio()関数、GPIOピンを構成する--1154-->初期化クロック--1166->割り込みリソースの取得--1171->登録割り込み、devm_request_IRq--1193-1940-->i 2 c->adapオブジェクトの初期化、バス番号はデバイスからの--1196->構築されたadapterオブジェクトをカーネルに登録--1203->プライベートデータの設定、pdev->dev->p->driver_data = i2c; i 2 c->dev=pdev->devなので、実はリソースオブジェクトのヘッダアドレスをdevice->device_に割り当てることですprivate->driver_dataでは、すべてのインタフェースがplatform_を使用しているためデバイスはパラメータとして、カスタムリソースオブジェクトを簡単に見つけることができるので、void*driver_と呼ばれます.data--1205->devの電源管理を設定--1206->adapの電源管理を設定

s3c24xx_i2c_algorithm


Probeで私たちが最も関心を持っているのはこの--1107--実装のインタフェースです.i 2 c-coreは最終的にalgo->xferを通じてデバイス駆動のデータを送信します.ハードウェア関連の関数です.
 787 static const struct i2c_algorithm s3c24xx_i2c_algorithm = {                                        
 788         .master_xfer            = s3c24xx_i2c_xfer,
 789         .functionality          = s3c24xx_i2c_func,
 790 };
 748 static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msgs, int num)
 750 {
 751         struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
 758         for (retry = 0; retry < adap->retries; retry++) {
 760                 ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
 770                 udelay(100);
 771         }
 776 }

s3c24xx_i2c_xfer()--760->ループ呼び出し送信関数は、レジスタの読み書き、デバイス駆動における送信要求が、これらreadl()、writel()によって実現されることが分かる.770-->シーケンス要件!
 256 static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,                                     
 257                                       struct i2c_msg *msg)
 258 {
 275         /* todo - check for whether ack wanted or not */
 276         s3c24xx_i2c_enable_ack(i2c);
 277 
 278         iiccon = readl(i2c->regs + S3C2410_IICCON);
 279         writel(stat, i2c->regs + S3C2410_IICSTAT);
 280 
 281         dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS
"
, stat, addr); 282 writeb(addr, i2c->regs + S3C2410_IICDS); 287 ndelay(i2c->tx_setup); 288 290 writel(iiccon, i2c->regs + S3C2410_IICCON); 291 292 stat |= S3C2410_IICSTAT_START; 293 writel(stat, i2c->regs + S3C2410_IICSTAT); 294 295 if (i2c->quirks & QUIRK_POLL) { 296 while ((i2c->msg_num != 0) && is_ack(i2c)) { 297 i2c_s3c_irq_nextbyte(i2c, stat); 298 stat = readl(i2c->regs + S3C2410_IICSTAT); 299 300 if (stat & S3C2410_IICSTAT_ARBITR) 301 dev_err(i2c->dev, "deal with arbitration loss
"
); 302 } 303 } 304 }