🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

Q&A

解決済

2回答

5763閲覧

組み込みLinux(Ubuntu)でのデバイスドライバー(SPI通信)について

hero1000

総合スコア56

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

0グッド

4クリップ

投稿2020/11/29 15:16

編集2020/11/30 23:54

Linuxにおけるデバイスドライバーについて

NVIDIA社のJetson nano (tegra210-p3448-0002-p3449-0000-b00)
を260pin-SODIMMコネクタで接続して使うボードの開発をC言語で進めています。
私は組み込みソフトでC言語、OSレスでの開発は慣れているのですがLinuxは初めてです。

使用しているLinuxのディストリビューションはUbuntuで、バージョンは18.04、64bit版です。

ハード構成はひとまず「お試し」という感じでSPI0の先にmicrochip社の93LC56Bを接続して
読み書きをしようとしています。
ピン配置は次の通りです。

  • MOSI:89pin
  • MISO:93pin
  • SCK:91pin
  • CS0:95pin

ピン配置の設定はNVIDIA社のページからダウンロードできる「NV_Jetson_Nano_Module_Pinmux_Config_Template.xlsm」で設定を行い、データツリーの設定ファイルを自動生成させています。(なのでピン関係の設定は合っていると思っています)

「Linuxでは、デバイスはファイルとしてアクセスする」のが原則ということで、open、write、read等の関数からアクセスできるドライバー開発を目指しています。

普段レジスタを叩いて制御してた私としては「簡単だろう」と高をくくっていたのですが、LinuxによってCPU(SoC)が見えない状態で戸惑っている状況です。

現状困っていること

Linuxの仕組み自体を理解していないので的を射ていないかも知れませんが、大きく悩んでいるのは次の3点です。
0. 「/dev」フォルダの下にデバイスが現れてくれないこと(EEPROMも、SPIも)
0. デバイスツリーの設定によってEEPROMドライバだけがロードされたり、されなかったりすること
0. EEPROMドライバーはGitにあった型番の近いソースを改変しようとしているが、それがそもそも意図に沿っているかどうかがわからないこと

デバイスツリーのDTSIファイルが膨大なため、SPIとEEPROMに関連していそうなところだけ触っています。
上記1と2はデバイスツリーの記述を変えると挙動が変わります。

試したこと

たくさんのDTSIファイルがありますが、いじっているのはtegra210-porg-p3448-common.dtsiとtegra210-porg-eeprom-manager.dtsiだけです。

ケース1:上記2で、EEPROMドライバだけが自動ロードされる(lsmodコマンドのリストに表れる)

dtsi

1 /* common.dtsi */ 2 ... 3 spi@7000d400 { 4 status = "okay"; 5 compatible = "spidev"; 6 }; 7 ... 8---------------------------------------------------------------------------------- 9 /* eeprom-manager.dtsi */ 10/ { 11 eeprom-manager { 12 data-size = <0x100>; 13 eep@0 { 14 spi = <&spi0>; 15 status = "okay"; 16 compatible = "microchip,93xx56"; 17 }; 18 }; 19};

ケース2:上記2で、EEPROMドライバが自動ロードされない(lsmodコマンドのリストには表れない)

dtsi

1 /* common.dtsi */ 2 ... 3 spi@7000d400 { 4 status = "okay"; 5 compatible = "spidev"; 6 eep@0 { 7 spi = <&spi0>; 8 status = "okay"; 9 compatible = "microchip,93xx56"; 10 }; 11 }; 12 ... 13---------------------------------------------------------------------------------- 14 /* eeprom-manager.dtsi */ 15/ { 16 eeprom-manager { 17 data-size = <0x100>; 18 eep@0 { 19 spi = <&spi0>; 20 status = "disable"; 21 compatible = "microchip,93xx56"; 22 }; 23 };

ドライバのソースはほぼダウンロードしたものそのままです。いずれファイルとして扱えるようになったら、open関数等を実装しようと思っている物です。probe関数で必ず通るところにprintkを入れてもdmesgに何も出てきません。

c

1 ... 2static const struct of_device_id eeprom_93xx56_of_table[] = { 3 { .compatible = "microchip,eeprom-93xx56", }, 4 {} 5}; 6MODULE_DEVICE_TABLE(of, eeprom_93xx56_of_table); 7 8static int eeprom_93xx46_probe_dt(struct spi_device *spi) 9{ 10 const struct of_device_id *of_id = 11 of_match_device(eeprom_93xx46_of_table, &spi->dev); 12 struct device_node *np = spi->dev.of_node; 13 struct eeprom_93xx46_platform_data *pd; 14 u32 tmp; 15 int ret; 16 17 pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL); 18 if (!pd) 19 return -ENOMEM; 20 21 ret = of_property_read_u32(np, "data-size", &tmp); 22 if (ret < 0) { 23 dev_err(&spi->dev, "data-size property not found\n"); 24 return ret; 25 } 26 27 if (tmp == 8) { 28 pd->flags |= EE_ADDR8; 29 } else if (tmp == 16) { 30 pd->flags |= EE_ADDR16; 31 } else { 32 dev_err(&spi->dev, "invalid data-size (%d)\n", tmp); 33 return -EINVAL; 34 } 35 36 if (of_property_read_bool(np, "read-only")) 37 pd->flags |= EE_READONLY; 38 39 pd->select = devm_gpiod_get_optional(&spi->dev, "select", 40 GPIOD_OUT_LOW); 41 if (IS_ERR(pd->select)) 42 return PTR_ERR(pd->select); 43 44 pd->prepare = select_assert; 45 pd->finish = select_deassert; 46 gpiod_direction_output(pd->select, 0); 47 48 if (of_id->data) { 49 const struct eeprom_93xx46_devtype_data *data = of_id->data; 50 51 pd->quirks = data->quirks; 52 } 53 54 spi->dev.platform_data = pd; 55 56 return 0; 57} 58 59static int eeprom_93xx46_probe(struct spi_device *spi) 60{ 61 struct eeprom_93xx46_platform_data *pd; 62 struct eeprom_93xx46_dev *edev; 63 int err; 64 65 if (spi->dev.of_node) { 66 err = eeprom_93xx46_probe_dt(spi); 67 if (err < 0) 68 return err; 69 } 70 71 pd = spi->dev.platform_data; 72 if (!pd) { 73 dev_err(&spi->dev, "missing platform data\n"); 74 return -ENODEV; 75 } 76 77 edev = devm_kzalloc(&spi->dev, sizeof(*edev), GFP_KERNEL); 78 if (!edev) 79 return -ENOMEM; 80 81 if (pd->flags & EE_ADDR8) 82 edev->addrlen = 7; 83 else if (pd->flags & EE_ADDR16) 84 edev->addrlen = 6; 85 else { 86 dev_err(&spi->dev, "unspecified address type\n"); 87 return -EINVAL; 88 } 89 90 mutex_init(&edev->lock); 91 92 edev->spi = spi; 93 edev->pdata = pd; 94 95 edev->size = 128; 96 edev->nvmem_config.type = NVMEM_TYPE_EEPROM; 97 edev->nvmem_config.name = dev_name(&spi->dev); 98 edev->nvmem_config.dev = &spi->dev; 99 edev->nvmem_config.read_only = pd->flags & EE_READONLY; 100 edev->nvmem_config.root_only = true; 101 edev->nvmem_config.owner = THIS_MODULE; 102 edev->nvmem_config.compat = true; 103 edev->nvmem_config.base_dev = &spi->dev; 104 edev->nvmem_config.reg_read = eeprom_93xx46_read; 105 edev->nvmem_config.reg_write = eeprom_93xx46_write; 106 edev->nvmem_config.priv = edev; 107 edev->nvmem_config.stride = 4; 108 edev->nvmem_config.word_size = 1; 109 edev->nvmem_config.size = edev->size; 110 111 edev->nvmem = devm_nvmem_register(&spi->dev, &edev->nvmem_config); 112 if (IS_ERR(edev->nvmem)) 113 return PTR_ERR(edev->nvmem); 114 115 dev_info(&spi->dev, "%d-bit eeprom %s\n", 116 (pd->flags & EE_ADDR8) ? 8 : 16, 117 (pd->flags & EE_READONLY) ? "(readonly)" : ""); 118 119 if (!(pd->flags & EE_READONLY)) { 120 if (device_create_file(&spi->dev, &dev_attr_erase)) 121 dev_err(&spi->dev, "can't create erase interface\n"); 122 } 123 124 spi_set_drvdata(spi, edev); 125 return 0; 126} 127 128static int eeprom_93xx46_remove(struct spi_device *spi) 129{ 130 struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi); 131 132 if (!(edev->pdata->flags & EE_READONLY)) 133 device_remove_file(&spi->dev, &dev_attr_erase); 134 135 return 0; 136} 137 138static struct spi_driver eeprom_93xx56_driver = { 139 .driver = { 140 .name = "93xx56", 141 .of_match_table = of_match_ptr(eeprom_93xx46_of_table), 142 }, 143 .probe = eeprom_93xx46_probe, 144 .remove = eeprom_93xx46_remove, 145}; 146 147module_spi_driver(eeprom_93xx56_driver); 148 149MODULE_LICENSE("GPL"); 150MODULE_DESCRIPTION("Driver for 93xx56 EEPROMs"); 151MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); 152MODULE_ALIAS("spi:93xx56");

結局のところ

そもそもLinuxの知識が乏しいことと、デバイスツリーの理解も進んでいないことから、どこまでが正しいのかの線引きすらできていない状態です。デバイスツリー内のcompatibleの記述と、ドライバーのソース内のof_device_tableにある.compatibleメンバーの記述が合致していれば、kernelが勝手にドライバーを読み込んでくれるものと思っていました。

「/dev」フォルダ下にデバイスが現れ、それをファイルとして扱うことにこだわっていいのか、それとも別の方法があるのかも含めてご教示いただければと思います。

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

次のようにしたところ、spidev.cと自作ドライバの両方が読み込まれました。(dmesgはどうやっても表示がされませんが、lsmodではリストに出てきます)

dtsi

1 [tegra210-porg-p3448-common.dtsi] 2 ... 3 spi@7000d400 { 4 status = "okay"; 5 compatible = "nvidia,tegra210-spi"; 6 reg = <0x0 0x7000d400 0x0 0x200>; 7 spi-max-frequency = <1000000>; 8 nvidia,enable-hw-based-cs; 9 nvidia,cs-setup-clk-count = <0x1e>; 10 nvidia,cs-hold-clk-count = <0x1e>; 11 nvidia,rx-clk-tap-delay = <0x1f>; 12 nvidia,tx-clk-tap-delay = <0x0>; 13 14 spidev: spi@0 { 15 status = "okay"; 16 compatible = "spidev"; 17 reg = <0>; 18 spi-max-frequency = <1000000>; 19 spi-cs-high; 20 spi-cpha; 21 size = <256>; 22 }; 23 }; 24 ... 25-------------------------------------------------------------- 26 [tegra210-porg-eeprom-manager.dtsi] 27 ... 28/ { 29 maker_eep: eep@0 { 30 status = "okay"; 31 bus = <&spidev>; 32 compatible = "microchip,eeprom-93xx56"; 33 devnode = "m_eep"; 34 data-size = <16>; /* 93LC56B */ 35 }; 36};

読み込みたい、というところは解決したのでこちらはこれで閉じたいと思います。

投稿2020/12/14 06:34

hero1000

総合スコア56

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

デバイスツリー内のcompatibleの記述と、ドライバーのソース内のof_device_tableにある.compatibleメンバーの記述が合致していれば、kernelが勝手にドライバーを読み込んでくれるものと思っていました。

これは、ご認識の通りかと思います。

ケース1のとき、下記でe2prom,spiが見えたりしませんか?

console

1# find /proc/device-tree 2# find /sys/class 3# find /sys/device 4# find /sys/module

probe関数で必ず通るところにprintkを入れてもdmesgに何も出てきません。

ログレベルによっては表示されませんが、その辺は問題ないでしょうか?
デフォルトでもKERN_ERR以上であれば表示されるとは思います。

/dev配下のファイルについては、ファイルを生成するのはudevだと思うので、別途ルールファイルを作成しないと自動生成されないのではないか、という気がしています。

投稿2020/12/05 14:48

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hero1000

2020/12/08 23:56

ありがとうございます。findコマンドで各フォルダ下には見えています。ログレベルは確かに確認していませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問