Trình điều khiển i2c khởi động lên - raspbian


8

Tôi tương đối mới với trình điều khiển thiết bị trên linux. Điều tôi đang cố gắng đạt được là khi khởi động Raspberry của tôi, trình điều khiển RGB bên ngoài sẽ nhận được lệnh i2c để bạn có thể thấy đèn LED sáng lên khi khởi động.

Cách tiếp cận của tôi là cố gắng thực hiện điều này thông qua một mô-đun hạt nhân sẽ được tải khi khởi động. Tôi đã cố gắng rất nhiều thứ để đạt được điều này, nhưng hiện tại tôi cảm thấy mình có một lỗ hổng kiến ​​thức. Có lẽ ai đó có thể giúp tôi? (lưu ý rằng đó không phải là vấn đề phần cứng, từ không gian người dùng tôi có thể gửi lệnh đến thiết bị.)

Mã mô-đun hạt nhân của tôi như sau:

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

Đây là tệp thực hiện:

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*

Trong tệp /boot/config.txt tôi đã thêm phần này:

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

Ngoài ra, tôi đã thực hiện một dtoverlay tùy chỉnh:

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

Không may khi khởi động không có gì xảy ra. Tất cả những gì tôi nhận được từ dmesg bootup là như sau:

rgb_driver: loading out-of-tree module taints kernel

Bất cứ ai cũng có thể giúp tôi, hoặc có thể là một cách tiếp cận khác để đạt được mục tiêu của tôi?

Cảm ơn trước!



Khi bạn nói rằng bạn muốn gửi lệnh i2c để bật đèn LED khi khởi động, bạn có nghĩa là trong quá trình khởi động hoặc sau khi quá trình khởi động hoàn tất và bạn có thể đăng nhập không?
rnorris

Trong quá trình khởi động
Nelizzsan

Tùy thuộc vào thời gian bạn muốn thực hiện việc này trong quá trình khởi động, có thể đáng để xem việc thực hiện điều này như một tập lệnh bên dưới /etc/init.d/hoặc tương tự thay vì mô-đun hạt nhân.
rnorris

Câu trả lời:


4

Một vài điều cần xem xét - một hạt nhân bị nhiễm độc thường bị giảm tính năng và bạn có thể không muốn đến đó nếu bạn không phải làm vậy. Tôi sẽ cố gắng giải quyết vấn đề vô vị. Tôi đã xây dựng các mô-đun hạt nhân dưới dạng độc lập và không gặp phải vấn đề khó khăn. Bạn có thể muốn xem lại tệp tạo tệp của mình, đây là tệp tạo tệp mô-đun chuẩn hơn với một vài nếp nhăn, tất nhiên, bạn đang biên dịch chéo -

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

và xây dựng nó với một cái gì đó như -

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

Vì vậy, có đó.

Tiếp theo, công cụ thăm dò thiết bị của bạn trông thú vị. Tôi không có thời gian để gỡ lỗi cho bạn, nhưng tôi khuyên bạn nên thêm một số printk vào đó để xác minh đầu dò đang bị tấn công. Nếu đúng thì thật tuyệt, đó chỉ là vấn đề tìm ra lý do tại sao bạn không 'khớp'. Nếu nó không bị ảnh hưởng, thì hãy đọc tiếp ..

Như bạn có thể biết, xe buýt i2c hơi đặc biệt khi nói đến việc thăm dò thiết bị. Không có sự thăm dò tự động hoặc ma thuật thực sự thường xảy ra trên một chiếc xe buýt PCI. Thay vào đó, bạn cần xây dựng một cây thiết bị mà kernel có thể đi bộ trong thời gian khởi động để hoàn thành tất cả các đầu dò.

Tôi thấy rằng bạn đã tạo một đoạn mã lớp phủ. Bạn cần chắc chắn rằng thứ đó được biên dịch thành nhị phân mã byte '.dtb' mà kernel có thể phân tích cú pháp và sau đó đặt đúng vị trí trong phương tiện khởi động của bạn, nơi grub có thể tìm thấy nó.

Bạn cũng có thể cần cập nhật dtb chính của thiết bị để tham khảo lớp phủ này, để hạt nhân biết nơi nó có thể đi. Hãy nghĩ về dtb của thiết bị như một cây thông giáng sinh nhân tạo và lớp phủ như một chi có thể được gắn vào một lúc nào đó trong tương lai - bạn sẽ cần chỉ định các điểm đính kèm trong dtb của thiết bị. Tôi ước rằng tôi có thể chính xác hơn ở đây, nhưng hy vọng sẽ đưa bạn đi đúng hướng về điểm này ít nhất.


@Nelizzsan: câu trả lời này có giúp bạn đáng kể không?
shellter

@Andrew AtDR: Cảm ơn bạn đã trả lời! Bạn đã xác nhận tất cả các giả định của tôi: P. Tôi đồng ý, vấn đề có thể là do vấn đề cây thiết bị. Tôi thực sự đã có nó làm việc trên Rpi bình thường. Vì vậy, tôi nên bắt đầu đào vào cây thiết bị.
Nelizzsan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.