简体   繁体   English

i2c 驱动程序启动 - raspbian

[英]i2c driver boot up - raspbian

I'm relative new to device drivers on linux.我对 linux 上的设备驱动程序比较陌生。 What im trying to achieve is that on boot-up of my Raspberry an external RGB driver will receive an i2c command so you can see a LED light up at boot.我试图实现的是,在我的 Raspberry 启动时,外部 RGB 驱动程序将收到一个 i2c 命令,因此您可以在启动时看到 LED 亮起。

My approach is trying to accomplish this via a kernel module that will be loaded at bootup.我的方法是尝试通过将在启动时加载的内核模块来完成此操作。 I tried a lot of things to achieve this, but at the moment I feel like I have a knowledge gap.我尝试了很多方法来实现这一点,但目前我觉得我有知识差距。 Maybe someone can help me?也许有人可以帮助我? (note that its not a hardware issue, from user space I can send commands to the device.) (请注意,这不是硬件问题,我可以从用户空间向设备发送命令。)

My kernel module code is as following:我的内核模块代码如下:

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

Here is the 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 the /boot/config.txt file I have added this:在 /boot/config.txt 文件中,我添加了以下内容:

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

In addition I made a custom dtoverlay:另外我做了一个自定义的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>;
            };
        };
    };
};

Unfortunalty on boot-up nothing happens.启动时不幸没有任何反应。 All I get from the bootup dmesg is the following:我从启动 dmesg 得到的信息如下:

rgb_driver: loading out-of-tree module taints kernel

Anyone can give me any help, or a maybe a different approach to achieve my goal?任何人都可以给我任何帮助,或者可能采用不同的方法来实现我的目标?

Thanks in advance!提前致谢!

A couple of things to look at - a tainted kernel is often feature-reduced and you probably don't want to go there if you don't have to.需要注意的几件事 - 受污染的内核通常会减少功能,如果不需要,您可能不想去那里。 I'd try to solve the tainting issue.我会尝试解决污染问题。 I've built kernel modules as standalones and not hit the taint issue.我已经将内核模块构建为独立的并且没有遇到污点问题。 You may wish to revisit your makefile, this is a more standard module-building makefile with a couple of wrinkles as, of course, you are crossing compiling -您可能希望重新访问您的 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

and build it with something like -并用类似的东西构建它 -

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

So there is that.所以就是这样。

Next, your device probe stuff looks interesting.接下来,您的设备探针看起来很有趣。 I don't have time to debug it for you, but I'd suggest adding some printk's in there to verify the probe is getting hit.我没有时间为您调试它,但我建议在其中添加一些 printk 以验证探针是否被击中。 If it is, then great, it's just a matter of figuring out why you are not 'matching'.如果是,那就太好了,这只是弄清楚为什么你不“匹配”的问题。 If it is not getting hit, then read on ..如果它没有被击中,请继续阅读..

As you probably know, i2c buses are a little special when it comes to device probing.您可能知道,i2c 总线在设备探测方面有点特殊。 There is no real automated or magical probing that would normally happen on say a PCI bus.没有真正的自动化或神奇的探测,通常会发生在 PCI 总线上。 Instead you need to build out a device tree that the kernel can walk at boot-time to complete all of the probes.相反,您需要构建一个设备树,内核可以在启动时遍历它以完成所有探测。

I see that you've created an overlay snippet.我看到您创建了一个叠加片段。 You need to make sure that thing is compiled into a '.dtb' byte code binary that the kernel can parse and then put in the correct place in your boot media where grub can find it.您需要确保该内容已编译为内核可以解析的“.dtb”字节码二进制文件,然后将其放在引导媒体中 grub 可以找到它的正确位置。

You may also need to update your device's master dtb to refer to this overlay, so that the kernel knows where it might go.您可能还需要更新设备的主 dtb 以引用此覆盖,以便内核知道它可能会去哪里。 Think of the device's dtb as being an artificial christmas tree, and the overlay as a limb that could be attached at some point in the future - you'll need to specify the attachment points in the device dtb.将设备的 dtb 视为人造圣诞树,而将覆盖层视为可以在未来某个时间点连接的树枝 - 您需要在设备 dtb 中指定连接点。 I wish that I could be more precise here, but hope sets you off in the correct direction on this point at least.我希望我在这里可以更准确,但希望至少在这一点上让你朝着正确的方向前进。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM