[i2c驱动程序启动-树莓派

问题描述 投票:4回答:1

我对linux设备驱动程序还比较陌生。我要实现的目标是,在启动Raspberry时,外部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

任何人都可以给我任何帮助,或者也许以其他方式实现我的目标?

提前感谢!

linux kernel driver raspbian
1个回答
0
投票

要注意的几件事-受污染的内核通常会减少功能,如果不需要的话,您可能不想去那里。我会尝试解决污染问题。我已经将内核模块构建为独立模块,没有遇到任何问题。您可能希望重新访问您的makefile,这是一个更标准的模块构建makefile,带有一些折痕,因为您当然正在编译-

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中指定连接点。我希望我可以在这里更加精确,但是希望至少可以在这一点上使您朝正确的方向前进。

© www.soinside.com 2019 - 2024. All rights reserved.