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, ®map_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!
/etc/init.d/
oder ähnlich anstelle eines Kernelmoduls zu implementieren .