簡體   English   中英

讀取設備硬件寄存器

[英]Reading Device Hardware Register

我正在嘗試創建一個設備驅動程序,盡管是一個天真簡單的驅動程序,它只是讀取代表撥碼開關的硬件寄存器的狀態。 這方面很新,我不確定在哪里可以找到有關該主題的足夠資源。 最好在 sysfs 中公開數據。

數據傳輸系統:

switches@c1000000 {
      compatible = "test, test-switches";
      label = "security_switch";
      reg = c1000000;
      mask = 0x1000;
      status = "okay";
    };

司機:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/regmap.h>

/* Declare the probe and remove functions */
static int dt_probe(struct platform_device *pdev);
static int dt_remove(struct platform_device *pdev);
/* Declare the read switch function */
int read_switch(struct platform_device *pdev);


int read_switch(struct platform_device *pdev)
{
    static void *reg_data;
    int ret;
    unsigned int adr_reg, bit_mask;
    struct device *dev = &pdev->dev;

    ret = device_property_read_u32(dev, "reg", &adr_reg);
    if(ret) {
        printk("Error! Could not read 'reg'\n");
        return -1;
    }
    printk("Reg read as - %d\n", adr_reg);
    ret = device_property_read_u32(dev, "mask", &bit_mask);
    if(ret) {
        printk("Error! Could not read 'mask'\n");
        return -1;
    }
    printk("Mask read as - %d\n", bit_mask);
    reg_data = ioremap(adr_reg, bit_mask);
    printk("Value @%d", adr_reg);
    printk("-%d ", bit_mask);
    printk(": %d\n", ioread32(reg_data));
    iounmap(reg_data);
    return 0;
}

/**
 * @brief This structure is used to match the DTS entry
 */

static const struct of_device_id switch_driver_ids[] = {
    {
        .compatible = "test,test-switches",
    }, {}
};
MODULE_DEVICE_TABLE(of, switch_driver_ids);

/**
 * @brief Platform Driver definition including functions used for adding, removing and probing 
 * the device
 */
static struct platform_driver switch_driver = {
    .probe = dt_probe,
    .remove = dt_remove,
    .driver = {
        .name = "switch_device_driver",
        .of_match_table = switch_driver_ids,
    },
};

/**
 * @brief This function is called loading the driver 
 */
static int dt_probe(struct platform_device *pdev) {
    struct device *dev = &pdev->dev;
    int ret;
    const char *label;
    const char *status;
    unsigned int reg;

    printk("dt_probe - Probing function!\n");

    /* Check for device properties */
    if(!device_property_present(dev, "label")) {
        printk("dt_probe - Error! Device property 'label' not found!\n");
        return -1;
    }
    printk("dt_probe - Error! Device property 'label' found!\n");

    if(!device_property_present(dev, "status")) {
        printk("dt_probe - Error! Device property 'status' not found!\n");
        return -1;
    }
    printk("dt_probe - Error! Device property 'status' found!\n");

    
    if(!device_property_present(dev, "reg")) {
        printk("dt_probe - Error! Device property 'reg' not found!\n");
        return -1;
    }
    printk("dt_probe - Error! Device property 'reg' found!\n");


    /* Read device properties */
    ret = device_property_read_string(dev, "label", &label);
    if(ret) {
        printk("dt_probe - Error! Could not read 'label'\n");
        return -1;
    }
    printk("dt_probe - label: %s\n", label);
    ret = device_property_read_string(dev, "status", &status);
    if(ret) {
        printk("dt_probe - Error! Could not read 'status'\n");
        return -1;
    }
    printk("dt_probe - status: %s\n", status);
    ret = device_property_read_u32(dev, "reg", &reg);
    if(ret) {
        printk("dt_probe - Error! Could not read 'reg'\n");
        return -1;
    }
    printk("dt_probe - reg: %d\n", reg);

    read_switch(pdev);

    return 0;
}

/**
 * @brief This function is called unloading the driver 
 */
static int dt_remove(struct platform_device *pdev) {
    printk("dt_probe - Removing driver\n");
    return 0;
}

/**
 * @brief This function is called when the module is loaded into the kernel
 */
static int __init init_drv(void) {
    printk("dt_probe - Loading the driver...\n");
    if(platform_driver_register(&switch_driver)) {
        printk("dt_probe - Error! Could not load driver\n");
        return -1;
    }
    return 0;
}

/**
 * @brief This function is called when the module is removed from the kernel
 */
static void __exit exit_drv(void) {
    printk("dt_probe - Unload driver");
    platform_driver_unregister(&switch_driver);
}

module_init(init_drv);
module_exit(exit_drv);

這里有關於 sysfs 的基本文檔:
https://docs.kernel.org/filesystems/sysfs.html

在 include/linux/sysfs.h 和 include/linux/device.h 中有更多信息。

不過一般來說:學習這些東西的最佳方法是閱讀 kernel 文檔(kernel 源代碼樹下的文檔文件夾)、Kernel 源代碼本身、郵件列表和其他完善/編寫的主線驅動程序。

這曾經是設備驅動程序的一本不錯的入門書,現在已經過時了,但一些概念可能仍然適用: https://lwn.net/Kernel/LDD3/

不確定我是否遵循 DIP 開關如何“映射”到特定寄存器。 如果這是您的 SOC 上的 GPIO 引腳,那么獲得 sysfs 訪問權限的簡單方法是通過 sysfs 使用 GPIO,盡管根據您的平台整理引腳號可能很棘手。

也就是說,如果這確實需要它自己的驅動程序——那么通常您會希望使用DEVICE_ATTR宏系列來定義您的屬性,然后使用sysfs_create_group / sysfs_remove_groupsysfs_add_file / sysfs_remove_file來注冊/注銷您的probe / remove

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM