Soy relativamente nuevo en controladores de dispositivos en Linux. Lo que estoy tratando de lograr es que al arrancar mi Raspberry, un controlador RGB externo recibirá un comando i2c para que pueda ver un LED iluminado en el arranque.
Mi enfoque está tratando de lograr esto a través de un módulo de kernel que se cargará en el arranque. Intenté muchas cosas para lograr esto, pero en este momento siento que tengo una brecha de conocimiento. Tal vez alguien me puede ayudar? (tenga en cuenta que no es un problema de hardware, desde el espacio del usuario puedo enviar comandos al dispositivo).
El código de mi módulo de kernel es el siguiente:
#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);
Aquí está el archivo MAKE:
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*
En el archivo /boot/config.txt he agregado esto:
dtoverlay = i2c-gpio, bus = 80, i2c_gpio_delay_us = 2, i2c_gpio_sda = 44, i2c_gpio_scl = 45.
Además hice un dtoverlay personalizado:
/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>;
};
};
};
};
Desafortunadamente en el arranque no pasa nada. Todo lo que obtengo del dmesg de arranque es lo siguiente:
rgb_driver: loading out-of-tree module taints kernel
¿Alguien puede darme alguna ayuda, o tal vez un enfoque diferente para lograr mi objetivo?
¡Gracias por adelantado!
/etc/init.d/
o similar en lugar de un módulo del núcleo.