i2cドライバーの起動-raspbian


8

Linuxのデバイスドライバーは比較的新しいです。達成しようとしているのは、ラズベリーの起動時に外部RGBドライバーがi2cコマンドを受信するため、起動時にLEDが点灯することを確認できます。

私のアプローチは、起動時にロードされるカーネルモジュールを介してこれを達成しようとしています。私はこれを達成するために多くのことを試みましたが、現時点では知識のギャップがあるように感じています。多分誰かが私を助けることができますか?(ハードウェアの問題ではないことに注意してください。ユーザー空間からデバイスにコマンドを送信できます。)

私のカーネルモジュールコードは次のとおりです。

    #include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/regmap.h>


MODULE_AUTHOR ("Niels");
MODULE_DESCRIPTION("driver rgb led");
MODULE_LICENSE("GPL");

/*CAT3626 control registers*/
#define CAT3626_ADDRESS     0x66
#define CAT3626_ENA         0x03
#define CAT3626_REGA        0x00
#define CAT3626_REGB        0x01
#define CAT3626_REGC        0x02

struct cat3626 {
    struct device *dev;
    struct regmap * regmap;
};


enum {
    cat3626, 
};

static const struct of_device_id cat3626_dt_ids[] = {
    { .compatible = "onsemi,cat3626", .data = (void *)cat3626},
    { }
};

MODULE_DEVICE_TABLE(of, cat3626_dt_ids);


static const struct i2c_device_id cat3626_id[] = {
    {"cat3626",cat3626},
    { }
};

MODULE_DEVICE_TABLE(i2c, cat3626_id);

static const struct regmap_config regmap_config = {
    .reg_bits = 8,
    .val_bits = 8,
};

static int cat3626_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct cat3626 *cat3626;
    const struct of_device_id *match;
    int ret;

    cat3626 = devm_kzalloc(&client->dev, sizeof(struct cat3626), GFP_KERNEL);
    if (!cat3626){
        return -ENOMEM;
    }

    dev_set_drvdata(&client->dev, cat3626);
    cat3626->dev = &client->dev;

    cat3626->regmap = devm_regmap_init_i2c(client, &regmap_config);
    if (IS_ERR(cat3626->regmap)) {
        dev_err(cat3626->dev, "regmap allocation failed\n");
        return PTR_ERR(cat3626->regmap);
    }

    i2c_set_clientdata(client, cat3626);

    match = of_match_device(cat3626_dt_ids, &client->dev);
        if (!match) {
        dev_err(&client->dev, "unknown device model\n");
        return -ENODEV;
    }

    ret = i2c_smbus_write_byte_data(client, CAT3626_ENA, 0x30);   /* write LED C on*/
    ret = i2c_smbus_write_byte_data(client, CAT3626_REGC, 19);    /* write mA*/

    return ret;
}

static struct i2c_driver cat3626_driver = {
    .driver = {
        .name = "cat3626",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(cat3626_dt_ids),
    },
    .probe = cat3626_probe,
    .remove = cat3626_remove,
    .id_table = cat3626_id,
};

module_i2c_driver(cat3626_driver);

ここにmakefileがあります:

ifneq ($(KERNELRELEASE),)
    obj-m := hiber_rgb_driver.o

else
    KERNELDIR ?= \
    /lib/modules/`uname -r`/build/
    PWD := `pwd`

default:
    $(MAKE) -C $(KERNELDIR) \
    M=$(PWD) modules

endif

clean:
    rm -f *.ko *.o Module* *mod*

/boot/config.txtファイルにこれを追加しました:

dtoverlay = i2c-gpio, bus = 80, i2c_gpio_delay_us = 2, i2c_gpio_sda = 44, i2c_gpio_scl = 45.

さらに、カスタムdtoverlayを作成しました。

/dts-v1/;
/plugin/;

/ {
    fragment@0 {
        target = <&i2c80>;
        __overlay__ {
            status = "okay";
            #address-cells = <1>;
            #size-cells = <0>;

            cat3626: cat3626@66 {
                compatible = "onsemi,cat3626";
                reg = <0x66>;
                clock-frequency = <400000>;
            };
        };
    };
};

起動時の不幸は何も起こりません。ブートアップdmesgから取得するのは次のとおりです。

rgb_driver: loading out-of-tree module taints kernel

誰でも私に助けを与えることができますか、または私の目標を達成するための多分異なるアプローチですか?

前もって感謝します!



あなたはLED点灯にI2Cコマンドを送信したいと言うときブートは、ブートプロセス中に意味ですか、またはブートプロセスが完了しており、それがログインすることが可能です後?
rnorris

起動プロセス中
Nelizzsan

ブートプロセスでこれをどのくらい早く実行したいかに応じて、これを/etc/init.d/カーネルモジュールの代わりに、または同様のスクリプトとして実装することを検討する価値があります。
rnorris

回答:


4

注目すべき点が2つあります。汚染されたカーネルは機能が低下していることが多く、必要がない場合はそこに行きたくないでしょう。汚染の問題を解決しようと思います。カーネルモジュールをスタンドアロンとしてビルドしましたが、汚染の問題は発生しません。あなたはあなたのメイクファイルをもう一度見たいかもしれません、これはもちろん、あなたがコンパイルを横断しているので、いくつかのしわがあるより標準的なモジュール構築メイクファイルです-

PWD = $(shell pwd)
obj-m += hiber_rgb_driver.o

all:
    make ARCH=arm CROSS_COMPILE=$(CROSS) -C $(KERNEL) SUBDIRS=$(PWD) modules

clean:
    make -C $(KERNEL) SUBDIRS=$(PWD) clean

そしてそれを次のようなもので構築します-

make KERNEL=<LINUX_SOURCE_DIR> CROSS=<TOOLCHAIN_DIR>/bin/arm-linux-gnueabihf-

それがあります。

次に、デバイスプローブの内容が興味深いように見えます。デバッグする時間はありませんが、そこにprintkを追加して、プローブがヒットしていることを確認することをお勧めします。それが優れている場合、それはなぜあなたが「マッチング」していないのかを理解するだけの問題です。ヒットしない場合は、..を読んでください。

おそらくご存じのとおり、デバイスのプローブに関しては、i2cバスは少し特殊です。通常、PCIバスなどで発生する、自動化された、または魔法のような実際のプローブはありません。代わりに、カーネルがブート時にすべてのプローブを完了するために歩くことができるデバイスツリーを構築する必要があります。

オーバーレイスニペットを作成しました。カーネルが解析できる「.dtb」バイトコードバイナリにコンパイルされていることを確認してから、grubがそれを検出できるブートメディアの正しい場所に配置する必要があります。

このオーバーレイを参照するようにデバイスのマスターdtbを更新して、カーネルがどこに移動するかを認識できるようにする必要がある場合もあります。デバイスのdtbは人工的なクリスマスツリーであり、オーバーレイは将来のある時点で接続できるリムであると考えてください。デバイスのdtbで接続ポイントを指定する必要があります。ここでもっと正確になればいいのですが、少なくともこの点であなたを正しい方向に導いてくれることを願っています。


@Nelizzsan:この答えはあなたを大きく助けましたか?
シェルター

@Andrew Atrens:回答ありがとうございます!あなたは私のすべての仮定を確認しました:P。私は同意します、問題はおそらくデバイスツリーの問題が原因です。私は実際にそれを通常のRpiで動作させていました。だから私はデバイスツリーを掘り下げ始めるべきです。
Nelizzsan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.