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ホストコントローラドライバを記述するフレームワークとカーネルドライバを分析するフローをまとめることを試みた.
--1291-->ホストコントローラ駆動をシステム起動時に登録する--1289->この駆動はplatformバスに基づいており、デバイス情報の部分はボードレベルファイルi 2 c_board_infoではplatformとして説明されています.デバイスはカーネル起動に伴って登録されているので、コントローラ駆動はシステム起動時に動作します.
従うplatform作成である以上、すべての情報は1つのplatformでなければなりません.driverでは、分析もこのオブジェクトの周りに展開されます.
--1276-->probe関数、最も重要な関数--1278-->マッチングのためのidテーブルは、プラットフォームファイルで作成されたデバイス情報であるため、このドメインをマッチングの根拠として使用します.
「arch/arm/plat-samsung」で対応するデバイス情報を見つけることができます.
両者が一致するとprobeが実行されます!
一致すると、分析プロセスは少し変化し、駆動開発はすべてオブジェクト向けの思想に基づいており、カーネルは私たちに多くの「クラス」をカプセル化しているが、私たちが具体的な駆動を開発するときは、やはりそれを「継承」し、さらに具体的な設備に対するリソースオブジェクトを作成し、リソースオブジェクトは駆動中の多くの関数の共通リソースを管理し、駆動運転中のリソース管理者と橋渡しである.主にカーネルクラス+リソース(io,irq,クロック,レジスタ)+の状態表現+その他を含むため、設計駆動の仕事の中で重要な仕事の一つは「設計リソースクラス」である.次はサムスンのデザインのクラスで、私は副次的な部分を取り除きました.
リソースオブジェクトは駆動動作全体の核心であり、すべての方法に必要なリソースはこのオブジェクトに対する操作であり、その設計は反復的なプロセスであるが、フレームワーク全体が結合された後、大きな変化はあるべきではない.
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の分析を通じて、駆動全体の構築について要領よく理解することができる.
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の電源管理を設定
Probeで私たちが最も関心を持っているのはこの--1107--実装のインタフェースです.i 2 c-coreは最終的にalgo->xferを通じてデバイス駆動のデータを送信します.ハードウェア関連の関数です.
s3c24xx_i2c_xfer()--760->ループ呼び出し送信関数は、レジスタの読み書き、デバイス駆動における送信要求が、これらreadl()、writel()によって実現されることが分かる.770-->シーケンス要件!
一致する前に
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 }