0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

設(shè)備樹下的字符設(shè)備驅(qū)動框架

CHANBAEK ? 來源:嵌入式攻城獅 ? 作者:安迪西 ? 2023-04-14 11:35 ? 次閱讀

設(shè)備樹下的字符設(shè)備驅(qū)動框架

沒有引入設(shè)備樹時,相關(guān)寄存器物理地址是直接定義在驅(qū)動文件中的,通過地址映射成為虛擬地址后,再操作虛擬地址完成GPIO的初始化。 設(shè)備樹的本質(zhì)也是操作寄存器,只不過寄存器的相關(guān)信息 放在了設(shè)備樹中,配置寄存器時使用OF函數(shù)從設(shè)備樹中讀取寄存器數(shù)據(jù)后再進行配置

下圖為設(shè)備樹下的字符設(shè)備驅(qū)動框架圖:

圖片

接下來根據(jù)上面的框架圖,以驅(qū)動LED (GPIO1_IO03)為例,分步介紹具體的代碼編寫流程

1. 修改設(shè)備樹文件

在內(nèi)核源碼的/arch/arm/boot/dts/文件夾中復(fù)制一份官方I.MX6ULL EVK EMMC版的設(shè)備樹文件imx6ull-14x14-evk-emmc.dts,并自定義文件名,此處重命名為了imx6ull-andyxi-emmc.dts,在根節(jié)點中添加LED設(shè)備節(jié)點

andyxiled {
    #address-cells = <1>;      /*reg中起始地址占用一個字長*/
    #size-cells = <1>;         /*reg中地址長度占用一個字長*/
    compatible = "andyxi-led";
    status = "okay";
    reg = < 0X020C406C 0x04    /*CCM_CCGR1_BASE*/ 
            0X020E0068 0x04    /*SW_MUX_GPIO1_IO03_BASE*/
            0X020E02F4 0x04    /*SW_PAD_GPIO1_IO03_BASE*/
            0X0209C000 0x04    /*GPIO1_DR_BASE*/
            0X0209C004 0x04 >; /*GPIO1_GDIR_BASE*/
};

設(shè)備樹修改完成后,在內(nèi)核源碼的根目錄下執(zhí)行make命令編譯設(shè)備樹

make dtbs                       #編譯設(shè)備樹
make imx6ull-andyxi-emmc.dtb    #單獨編譯指定設(shè)備樹

編譯完成后,使用新的設(shè)備樹啟動Linux內(nèi)核,之后可進入/proc/device-tree文件夾查看dtsled節(jié)點是否存在

#啟動Linux系統(tǒng)后,在開發(fā)板中查看節(jié)點
cd /proc/device-tree         #查看andyxiled節(jié)點是否存在

2. 編寫驅(qū)動程序

創(chuàng)建驅(qū)動程序文件dtsled.c,添加如下代碼

宏定義及設(shè)備結(jié)構(gòu)體定義

#define DTSLED_CNT 1            //設(shè)備號個數(shù)
#define DTSLED_NAME "dtsled"    //名字
#define LEDOFF 0                //關(guān)燈
#define LEDON 1                 //開燈
/* 映射后的寄存器虛擬地址指針 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;
/* dtsled 設(shè)備結(jié)構(gòu)體 */
struct dtsled_dev{
    dev_t devid;               //設(shè)備號
    struct cdev cdev;          //cdev
    struct class *class;       //類
    struct device *device;     //設(shè)備
    int major;                 //主設(shè)備號
    int minor;                 //次設(shè)備號
    struct device_node *nd;    //設(shè)備節(jié)點
};

struct dtsled_dev dtsled;      //led設(shè)備

編寫設(shè)備操作函數(shù):設(shè)備操作函數(shù)和LED開關(guān)函數(shù),具體代碼可參考Linux點燈一文相關(guān)部分

驅(qū)動入口函數(shù)中:使用OF函數(shù)獲取設(shè)備樹中的屬性值,并初始化

static int __init led_init(void) { 
    u32 val = 0; 
    int ret; 
    u32 regdata[14]; 
    const char *str; 
    struct property *proper; 
    /* 獲取設(shè)備樹中的屬性數(shù)據(jù) */ 
    /* 1、獲取設(shè)備節(jié)點:andyxiled */ 
    dtsled.nd = of_find_node_by_path("/andyxiled"); 
    if(dtsled.nd == NULL) { 
        printk("andyxiled node can not found!\\r\\n"); 
        return -EINVAL; 
    } else { 
        printk("andyxiled node has been found!\\r\\n"); 
    } 
    /* 2、獲取compatible屬性內(nèi)容 */ 
    proper = of_find_property(dtsled.nd, "compatible", NULL); 
    if(proper == NULL) { 
        printk("compatible property find failed\\r\\n"); 
    } else { 
        printk("compatible = %s\\r\\n", (char*)proper->value); 
    }  
    /* 3、獲取status屬性內(nèi)容 */ 
    ret = of_property_read_string(dtsled.nd, "status", &str); 
    if(ret < 0){ 
        printk("status read failed!\\r\\n"); 
    } else { 
        printk("status = %s\\r\\n",str); 
    }
    /* 4、獲取reg屬性內(nèi)容 */ 
    ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10); 
    if(ret < 0) { 
        printk("reg property read failed!\\r\\n"); 
    } else { 
        u8 i = 0; 
        printk("reg data:\\r\\n"); 
        for(i = 0; i < 10; i++) 
        printk("%#X ", regdata[i]); 
        printk("\\r\\n"); 
    }

    /* 初始化LED */ 
#if 0 
    /* 1、寄存器地址映射 */ 
    IMX6U_CCM_CCGR1 = ioremap(regdata[0], regdata[1]); 
    SW_MUX_GPIO1_IO03 = ioremap(regdata[2], regdata[3]); 
    SW_PAD_GPIO1_IO03 = ioremap(regdata[4], regdata[5]); 
    GPIO1_DR = ioremap(regdata[6], regdata[7]); 
    GPIO1_GDIR = ioremap(regdata[8], regdata[9]); 
#else 
    IMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0); 
    SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1); 
    SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2); 
    GPIO1_DR = of_iomap(dtsled.nd, 3); 
    GPIO1_GDIR = of_iomap(dtsled.nd, 4); 
#endif 
    /* 2、使能GPIO1時鐘 */ 
    val = readl(IMX6U_CCM_CCGR1); 
    val &= ~(3 << 26);     //之前的設(shè)置
    val |= (3 << 26);      //設(shè)置新值
    writel(val, IMX6U_CCM_CCGR1); 
    /* 3、設(shè)置GPIO1_IO03復(fù)用功能,并設(shè)置IO屬性 */ 
    writel(5, SW_MUX_GPIO1_IO03); 
    writel(0x10B0, SW_PAD_GPIO1_IO03); 
    /* 4、設(shè)置GPIO1_IO03為輸出功能 */ 
    val = readl(GPIO1_GDIR); 
    val &= ~(1 << 3);      //之前的設(shè)置 
    val |= (1 << 3);       //設(shè)置為輸出
    writel(val, GPIO1_GDIR); 
    /* 5、默認關(guān)閉LED */ 
    val = readl(GPIO1_DR); 
    val |= (1 << 3); 
    writel(val, GPIO1_DR);

驅(qū)動入口函數(shù)中:注冊字符設(shè)備驅(qū)動,代碼與Linux點燈一文中的一樣

驅(qū)動出口函數(shù)中:注銷設(shè)備驅(qū)動,刪除類和設(shè)備,代碼可參考Linux點燈一文

3. 編寫測序程序

實現(xiàn)操作驅(qū)動文件對外設(shè)進行控制的功能。 創(chuàng)建測試程序文件dtsledApp.c,代碼內(nèi)容與Linux點燈一文中的測試程序代碼一致,此處不再贅述

4. 編譯測試

編譯驅(qū)動程序:當(dāng)前目錄下創(chuàng)建Makefile文件,并make編譯

KERNELDIR := /home/andyxi/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga_andyxi
CURRENT_PATH := $(shell pwd)
obj-m := dtsled.o

build: kernel_modules

kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

編譯測試程序:無需內(nèi)核參與,直接編譯即可

arm-linux-gnueabihf-gcc dtsledApp.c -o dtsledApp

運行測試:拷貝驅(qū)動模塊和測試程序到開發(fā)板,啟動開發(fā)板,加載驅(qū)動模塊后,使用應(yīng)用程序測試驅(qū)動是否正常工作

depmod                         #第一次加載驅(qū)動的時候需運行此命令
modprobe dtsled.ko             #加載驅(qū)動
./dtsledApp /dev/dtsled 1      #打開LED燈
./dtsledApp /dev/dtsled 0      #關(guān)閉LED燈
rmmod dtsled.ko                #卸載驅(qū)動模塊
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5295

    瀏覽量

    119824
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    3

    文章

    1361

    瀏覽量

    40185
  • 字符
    +關(guān)注

    關(guān)注

    0

    文章

    232

    瀏覽量

    25154
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1189

    瀏覽量

    51839
  • 設(shè)備樹
    +關(guān)注

    關(guān)注

    0

    文章

    38

    瀏覽量

    3105
收藏 人收藏

    評論

    相關(guān)推薦

    Linux平臺設(shè)備框架驅(qū)動

    ? 平臺設(shè)備框架(platform)是將一個驅(qū)動分為設(shè)備層和驅(qū)動層兩個部分,通過總線模型將設(shè)備
    的頭像 發(fā)表于 09-25 08:59 ?1731次閱讀
    Linux平臺<b class='flag-5'>設(shè)備</b><b class='flag-5'>框架</b><b class='flag-5'>驅(qū)動</b>

    Linux字符設(shè)備驅(qū)動開發(fā)框架介紹

    字符設(shè)備是Linux驅(qū)動中最基本的一類設(shè)備驅(qū)動字符設(shè)備
    發(fā)表于 04-15 11:52 ?1312次閱讀
    Linux<b class='flag-5'>字符</b><b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動</b>開發(fā)<b class='flag-5'>框架</b>介紹

    ArmSoM系列板卡 嵌入式Linux驅(qū)動開發(fā)實戰(zhàn)指南 之 字符設(shè)備驅(qū)動

    字符設(shè)備驅(qū)動 本章,我們將學(xué)習(xí)字符設(shè)備使用、字符設(shè)備
    的頭像 發(fā)表于 04-10 09:53 ?986次閱讀
    ArmSoM系列板卡 嵌入式Linux<b class='flag-5'>驅(qū)動</b>開發(fā)實戰(zhàn)指南 之 <b class='flag-5'>字符</b><b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動</b>

    「正點原子Linux連載」第五十五章設(shè)備樹下的platform驅(qū)動編寫

    學(xué)習(xí)一下如何在設(shè)備樹下編寫platform驅(qū)動。55.1設(shè)備樹下的platform驅(qū)動簡介pla
    發(fā)表于 03-21 10:03

    字符設(shè)備驅(qū)動 —— 字符設(shè)備驅(qū)動框架

      3、字符設(shè)備驅(qū)動框架作為字符設(shè)備驅(qū)動要素:1,必
    發(fā)表于 10-19 17:08

    什么是字符設(shè)備驅(qū)動字符設(shè)備驅(qū)動開發(fā)步驟有哪些?

    什么是字符設(shè)備驅(qū)動?字符設(shè)備驅(qū)動開發(fā)步驟有哪些?如何實現(xiàn)實現(xiàn)
    發(fā)表于 10-20 08:02

    字符設(shè)備驅(qū)動的開發(fā)流程

    做嵌入式linux驅(qū)動開發(fā),首先要搞明白大致框架。linux的驅(qū)動通常分為字符設(shè)備驅(qū)動、塊
    發(fā)表于 12-24 08:30

    嵌入式Linux字符設(shè)備驅(qū)動的設(shè)計與應(yīng)用

    描述了基于嵌入式Linux的字符設(shè)備驅(qū)動程序的設(shè)計方法和實現(xiàn)過程。以電機、數(shù)碼管、串口和mini鍵盤的驅(qū)動設(shè)計為例,詳細闡述了嵌入式linux下字符
    發(fā)表于 02-23 15:45 ?24次下載

    深度解析字符設(shè)備驅(qū)動模型

    ,read,write和ioctl等例程。所以根據(jù)應(yīng)用不同,字符驅(qū)動能會調(diào)用其他驅(qū)動模塊,如i2c、spi和v4l2等,于是字符驅(qū)動還可分W
    發(fā)表于 10-17 10:09 ?0次下載

    VxWorks設(shè)備驅(qū)動字符設(shè)備驅(qū)動詳解

    VxWorks設(shè)備驅(qū)動字符設(shè)備驅(qū)動詳解
    發(fā)表于 10-26 10:28 ?7次下載
    VxWorks<b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動</b>之<b class='flag-5'>字符</b><b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動</b>詳解

    《Linux設(shè)備驅(qū)動開發(fā)詳解》第6章、字符設(shè)備驅(qū)動

    《Linux設(shè)備驅(qū)動開發(fā)詳解》第6章、字符設(shè)備驅(qū)動
    發(fā)表于 10-27 11:46 ?23次下載
    《Linux<b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動</b>開發(fā)詳解》第6章、<b class='flag-5'>字符</b><b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動</b>

    你了解過Linux字符設(shè)備驅(qū)動框架?

    字符設(shè)備是Linux三大設(shè)備之一(另外兩種是塊設(shè)備,網(wǎng)絡(luò)設(shè)備),字符
    發(fā)表于 05-08 14:28 ?442次閱讀

    驅(qū)動之路-高級字符設(shè)備驅(qū)動程序

    高級字符設(shè)備驅(qū)動在簡單字符驅(qū)動的基礎(chǔ)上添加ioctl方法、阻塞非阻塞讀寫、poll方法、和自動創(chuàng)建設(shè)備
    發(fā)表于 05-15 14:24 ?793次閱讀
    <b class='flag-5'>驅(qū)動</b>之路-高級<b class='flag-5'>字符</b><b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動</b>程序

    字符設(shè)備驅(qū)動框架

    1、概述: linux中一切皆文件,設(shè)備也如此,并且以操作文件即文件IO的方式訪問設(shè)備。 應(yīng)用程序只能通過庫函數(shù)中的系統(tǒng)調(diào)用來操作硬件,對于每個系統(tǒng)調(diào)用,驅(qū)動程序中都會有一個與之對應(yīng)的函數(shù),對于
    發(fā)表于 10-19 17:20 ?705次閱讀

    Linux新字符設(shè)備驅(qū)動開發(fā)方式

    Linux字符設(shè)備驅(qū)動開發(fā)模板中介紹了舊版本的驅(qū)動開發(fā)模板,其需要手動分配設(shè)備號后,再進行注冊,驅(qū)動
    的頭像 發(fā)表于 04-14 12:02 ?836次閱讀
    Linux新<b class='flag-5'>字符</b><b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動</b>開發(fā)方式