Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Linuxカーネル] RTCドライバから学ぶ i2c の読書きについて

[Linuxカーネル] RTCドライバから学ぶ i2c の読書きについて

RTCデバイスドライバから実際にどのようにi2cの読み書きを行うデバイスドライバにつなぎこまれているかを調べました。以下の解説動画の資料になります。

[Linuxカーネル] RTCドライバから学ぶ i2c の読書きについて #nekoi7_tech
https://youtu.be/YSWZpv1bkl0

nekomatu

May 09, 2021
Tweet

More Decks by nekomatu

Other Decks in Programming

Transcript

  1. Linuxカーネルのコードリーディング RTCドライバから学ぶ i2c の読書きについて https://en.wikipedia.org/wiki/Real- time_clock#/media/File:Types_of_RTC_modules.jpg /CC BY-SA 4.0) はじめに

    (前回に分からなかったこと) i2cコントローラーについて 実装(ソースコード)の確認 i2cサブシステムとのつなぎこみ
  2. はじめに • 前に分からなかったことが分かったので、その補足動画です。 • RTCドライバから学ぶLinuxカーネルについて • https://www.youtube.com/watch?v=oHUA7KMRhgw • 何が分からなかったか? •

    RTCのデバイスドライバのコードを読んだ時に読み飛ばした部分がある • 複数へのレジスタアクセスが1回で行えているように見える部分 • 結論 • i2cコントローラー次第
  3. i2cコントローラーについて • i2cはClockとDataの2つの線をパタパタさせることで通信する • 規格に沿ってGPIOをパタパタさせればよい • 欠点: i2cのクロックはとても遅いのでCPUがもったいない • i2cコントローラー

    = オフロードしてくれるハードウェア専用モジュール • スレーブアドレス、レジスタ、長さを指定すると所定の処理をして完了後に割込み をかけてくれる みたいな感じ Creative Commons Attribution-Share Alike 3.0 Unported license. https://upload.wikimedia.org/wikipedia/commons/thumb/d/d8/I2C_ACK.svg/640px-I2C_ACK.svg.png
  4. drivers/i2c/i2c-core-smbus.c • int rx8025_read_regs(const struct i2c_client *client, u8 number, u8

    length, u8 *values) • s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command,u8 length, u8 *values) • s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data) • 引数: I2C_SMBUS_READ, I2C_SMBUS_I2C_BLOCK_DATA data.block[0] = length;
  5. drivers/i2c/i2c-core-smbus.c • s32 __i2c_smbus_xfer(..) xfer_func = adapter->algo->smbus_xfer; (SMBusが実装されていないときはNULLとなる) • 少しややこしいが実装されてる時はi2c_smbus_xfer_emulated()は飛ばされる

    • s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) • if (read_write == I2C_SMBUS_READ) { • msg[1].len = data->block[0]; • i2c_smbus_try_get_dmabuf(&msg[1], 0);
  6. drivers/i2c/busses/i2c-mv64xxx.c • static const struct i2c_algorithm mv64xxx_i2c_algo = { .master_xfer

    = mv64xxx_i2c_xfer, .functionality = mv64xxx_i2c_functionality, } 後はロックを取って、SFR(Special Function Register)を操作するだけ • 表現がちょっと適切じゃないかも • ここではマップされているレジスタを触るとコントローラを制御できるという文脈 で利用
  7. drivers/i2c/busses/i2c-mv64xxx.c • int mv64xxx_i2c_offload_xfer(struct mv64xxx_i2c_data *drv_data) • アドレス値のセット • ctrl_reg

    = MV64XXX_I2C_BRIDGE_CONTROL_ENABLE | (msgs[0].addr << MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT); • 長さのセット(一括読み出し) • ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_WR | (len <<MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT); • 作った値を実際に書き出して、完了を待つ • writel(ctrl_reg, drv_data->reg_base +MV64XXX_I2C_REG_BRIDGE_CONTROL); • mv64xxx_i2c_wait_for_completion(drv_data);