i2c Treiber bootet - raspbian

8

Ich bin relativ neu bei Gerätetreibern unter Linux. Was ich erreichen möchte, ist, dass ein externer RGB-Treiber beim Booten meines Raspberry einen i2c-Befehl erhält, sodass beim Booten eine LED aufleuchtet.

Mein Ansatz ist es, dies über ein Kernelmodul zu erreichen, das beim Booten geladen wird. Ich habe viele Dinge versucht, um dies zu erreichen, aber im Moment habe ich das Gefühl, eine Wissenslücke zu haben. Vielleicht kann mir jemand helfen? (Beachten Sie, dass es sich nicht um ein Hardwareproblem handelt. Aus dem Benutzerbereich kann ich Befehle an das Gerät senden.)

Mein Kernelmodulcode lautet wie folgt:

    #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);

Hier ist das 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*

In der Datei /boot/config.txt habe ich Folgendes hinzugefügt:

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

Außerdem habe ich ein benutzerdefiniertes Dtoverlay erstellt:

/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>;
            };
        };
    };
};

Leider passiert beim Booten nichts. Alles, was ich vom Bootup-Dmesg bekomme, ist das Folgende:

rgb_driver: loading out-of-tree module taints kernel

Kann mir jemand helfen oder einen anderen Ansatz, um mein Ziel zu erreichen?

Danke im Voraus!

Nelizzsan
quelle
Wenn Sie sagen, dass Sie einen i2c-Befehl senden möchten, um beim Booten eine LED zu leuchten , meinen Sie dies während des Startvorgangs oder nachdem der Startvorgang abgeschlossen ist und Sie sich anmelden können?
Rnorris
Während des Startvorgangs
Nelizzsan
Abhängig davon, wie schnell Sie dies im Startvorgang tun möchten, kann es sinnvoll sein, dies als Skript unter /etc/init.d/oder ähnlich anstelle eines Kernelmoduls zu implementieren .
Rnorris

Antworten:

4

Ein paar Dinge zu beachten - ein verdorbener Kernel ist oft funktionsreduziert und Sie möchten wahrscheinlich nicht dorthin gehen, wenn Sie nicht müssen. Ich würde versuchen, das Problem der Verschmutzung zu lösen. Ich habe Kernelmodule als eigenständige Module erstellt und bin nicht auf das Problem der Verschmutzung gestoßen. Vielleicht möchten Sie Ihr Makefile erneut besuchen. Dies ist ein Standard-Makefile zum Erstellen von Modulen mit ein paar Falten, da Sie natürlich das Kompilieren überqueren.

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

und baue es mit so etwas wie -

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

Da ist also das.

Als nächstes sieht Ihr Gerätesondenmaterial interessant aus. Ich habe keine Zeit, es für Sie zu debuggen, aber ich würde vorschlagen, einige Printks hinzuzufügen, um zu überprüfen, ob die Sonde getroffen wird. Wenn es so ist, dann ist es großartig, herauszufinden, warum Sie nicht "zusammenpassen". Wenn es nicht getroffen wird, lesen Sie weiter ..

Wie Sie wahrscheinlich wissen, sind i2c-Busse etwas Besonderes, wenn es um Geräteprüfungen geht. Es gibt keine echte automatisierte oder magische Prüfung, die normalerweise auf einem PCI-Bus stattfinden würde. Stattdessen müssen Sie einen Gerätebaum erstellen, den der Kernel beim Booten ausführen kann, um alle Tests abzuschließen.

Ich sehe, dass Sie ein Overlay-Snippet erstellt haben. Sie müssen sicherstellen, dass das Ding in eine '.dtb'-Bytecode-Binärdatei kompiliert ist, die der Kernel analysieren und dann an der richtigen Stelle in Ihrem Boot-Medium ablegen kann, wo grub es finden kann.

Möglicherweise müssen Sie auch die Master-DBB Ihres Geräts aktualisieren, um auf dieses Overlay zu verweisen, damit der Kernel weiß, wohin es möglicherweise führt. Stellen Sie sich das dtb des Geräts als künstlichen Weihnachtsbaum und das Overlay als Glied vor, das zu einem späteren Zeitpunkt angebracht werden könnte. Sie müssen die Befestigungspunkte im dtb des Geräts angeben. Ich wünschte, ich könnte hier genauer sein, aber die Hoffnung bringt Sie zumindest in diesem Punkt in die richtige Richtung.

Andrew Atrens
quelle
@Nelizzsan: Hat dir diese Antwort wesentlich geholfen?
Shellter
@ Andrew Atrens: Danke für deine Antwort! Sie haben alle meine Annahmen bestätigt: P. Ich stimme zu, das Problem ist wahrscheinlich auf ein Gerätebaumproblem zurückzuführen. Ich hatte es tatsächlich auf dem normalen Rpi arbeiten. Also sollte ich anfangen, in den Gerätebaum zu graben.
Nelizzsan