• 正文
    • 修改設(shè)備樹
    • 驅(qū)動(dòng)源碼platform_led.c編寫
    • 完整的驅(qū)動(dòng)platform_led.c示例源碼
    • 編譯
    • 測(cè)試
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

飛凌嵌入式ElfBoard ELF 1板卡-platform驅(qū)動(dòng)控制LED

04/02 10:40
407
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

例程代碼路徑:ELF 1開發(fā)板資料包3-例程源碼3-2 驅(qū)動(dòng)例程源碼6_platformplatform_led

下面以控制開發(fā)板上的LED_R為例進(jìn)行講解。

修改設(shè)備樹

(一)查看原理圖引腳復(fù)用表格,可以得到LED_R由GPIO1_10控制,所以我們需要配置GPIO1_10引腳為輸出,而且能夠在用戶空間控制它輸出高電平還是低電平。

(二)在設(shè)備樹arch/arm/boot/dts/imx6ull-elf1-emmc.dts中添加leds節(jié)點(diǎn)和引腳復(fù)用,并檢查設(shè)備樹中是否有其它的地方也用到了此引腳,如果用到了就需要將其屏蔽掉,避免復(fù)用沖突。

添加節(jié)點(diǎn):

leds {

????????????????compatible = "platform_led";

????????????????pinctrl-names = "default";

????????????????pinctrl-0 = <&pinctrl_led>;

????????????????gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;

????????};

添加后效果如下:

添加復(fù)用,在iomux中新建pinctrl_led:

pinctrl_led:ledgrp {

????????????????????????fsl,pins = <

????????????????????????????????MX6UL_PAD_JTAG_MOD__GPIO1_IO10 ???????0x10b0

????????????????????????>;

????????????????};

添加后效果如下:

(三)編譯設(shè)備樹:

. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

elf@ubuntu:~/work/linux-imx-imx_4.1.15_2.0.0_ga$ make dtbs

編譯生成的設(shè)備樹文件為imx6ull-elf1-emmc.dtb,參考《01-0 ELF1、ELF1S開發(fā)板_快速啟動(dòng)手冊(cè)_V1》4.4節(jié)單獨(dú)更新設(shè)備樹。

驅(qū)動(dòng)源碼platform_led.c編寫

(一)頭文件引用

#include <linux/init.h>

#include <linux/module.h> ??????// 包含模塊相關(guān)函數(shù)的頭文件

#include <linux/fs.h> ??????????// 包含文件系統(tǒng)相關(guān)函數(shù)的頭文件

#include <linux/platform_device.h>

#include <linux/miscdevice.h>

#include <linux/device.h> ??????//包含設(shè)備節(jié)點(diǎn)相關(guān)的頭文件

#include <linux/gpio.h> ????????//包含gpio操作函數(shù)的相關(guān)頭文件

#include <linux/of_gpio.h>

#include <linux/of.h>

(二)創(chuàng)建相關(guān)宏定義

#define DEVICE_NAME "my_device"

#define LED_IOC_MAGIC 'k'

#define SET_LED_ON _IO(LED_IOC_MAGIC, 0)

#define SET_LED_OFF _IO(LED_IOC_MAGIC, 1)

?

struct device_node *node; ??//設(shè)備樹節(jié)點(diǎn)

int gpio; ??//gpio編號(hào)

這里同樣使用ioctl來(lái)控制,ioctl相關(guān)的定義本節(jié)不在重復(fù)講解。

(三)定義platform_driver類型結(jié)構(gòu)體

static struct platform_driver my_platform_driver = {

????.driver = {

????????.name = "my_platform_driver",

????????.owner = THIS_MODULE,

????????.of_match_table = of_platform_match,

????},

????.probe = my_platform_probe,

????.remove = my_platform_remove,

};

(四)定義of_platform_match,用來(lái)與設(shè)備樹中的compatible匹配,匹配成功后才會(huì)進(jìn)入到probe函數(shù)中

static const struct of_device_id of_platform_match[] = {

????????{ .compatible = "platform_led", },

????????{},

};

(五)probe函數(shù)的實(shí)現(xiàn)

static int my_platform_probe(struct platform_device *pdev)

{

????????struct device *dev = &pdev->dev;

????????int ret;

????????//注冊(cè)雜項(xiàng)設(shè)備

????????ret = misc_register(&my_misc_device);

????????if (ret) {

????????pr_err("Failed to register misc devicen");

????????return ret;

????????}

????????// 獲取設(shè)備節(jié)點(diǎn)

????????node = of_find_node_by_name(NULL,"leds");

????????// 獲取 gpios 屬性中的引腳編號(hào)

????????gpio = of_get_named_gpio(node, "gpios", 0);

????????//判斷是否獲取成功

?????????if (!gpio_is_valid(gpio)) {

?????????pr_err("Failed to get GPIOn");

?????????return -1;

????????}

?

????????gpio_free(gpio);

????????if (gpio_request(gpio, "led_run")) {

????????????????printk("request %s gpio faile n", "led_run");

?????????????????return -1;

?????????}

????????printk(KERN_INFO "my_platform_probe: Platform device probedn");

????return 0;

}

(1)misc_register()用戶注冊(cè)雜項(xiàng)設(shè)備,原型如下:

int misc_register(struct miscdevice *misc);

參數(shù)說明:

misc:指向struct miscdevice結(jié)構(gòu)體的指針,表示要注冊(cè)的雜項(xiàng)設(shè)備。

返回值是一個(gè)整數(shù),表示注冊(cè)結(jié)果。如果注冊(cè)成功,函數(shù)會(huì)返回0;如果注冊(cè)失敗,函數(shù)會(huì)返回一個(gè)負(fù)數(shù),表示錯(cuò)誤代碼。

struct miscdevice結(jié)構(gòu)體用于描述雜項(xiàng)設(shè)備的屬性,包括設(shè)備的次設(shè)備號(hào)(minor number)、設(shè)備名稱、設(shè)備文件操作函數(shù)等。在注冊(cè)雜項(xiàng)設(shè)備之前,需要先初始化struct miscdevice 結(jié)構(gòu)體的字段,然后將其作為參數(shù)傳遞給 misc_register()函數(shù)。

(2)of_find_node_by_name()用于查找設(shè)備樹中的節(jié)點(diǎn),原型如下:

struct device_node *of_find_node_by_name(struct device_node *prev, const char *name);

參數(shù)說明:

prev:指向前一個(gè)設(shè)備樹節(jié)點(diǎn)的指針。如果要從整個(gè)設(shè)備樹中開始查找節(jié)點(diǎn),則可以傳遞NULL。

name:字符串,表示要查找的設(shè)備樹節(jié)點(diǎn)的名稱。

返回值是一個(gè)指向找到的設(shè)備樹節(jié)點(diǎn)的指針。如果找到匹配的節(jié)點(diǎn),則返回該節(jié)點(diǎn)的指針;如果未找到匹配的節(jié)點(diǎn),則返回 NULL。

(3)of_get_named_gpio()用于從設(shè)備樹中獲取GPIO引腳編號(hào),原型如下:

int of_get_named_gpio(const struct device_node *np, const char *propname, int index);

參數(shù)說明:

np:指向設(shè)備樹節(jié)點(diǎn)的指針,表示要從該節(jié)點(diǎn)獲取 GPIO 引腳。

propname:字符串,表示要獲取的 GPIO 引腳屬性的名稱。

index:整數(shù),表示在屬性中指定的 GPIO 引腳的索引。如果屬性中有多個(gè) GPIO 引腳定義,可以通過指定索引來(lái)獲取其中的一個(gè)引腳。

返回值是一個(gè)整數(shù),表示獲取到的 GPIO 引腳編號(hào)。如果獲取失敗,函數(shù)會(huì)返回一個(gè)負(fù)數(shù)。

(六)miscdevice類型結(jié)構(gòu)體定義

static struct miscdevice my_misc_device = {

????.minor = MISC_DYNAMIC_MINOR, ??// 動(dòng)態(tài)分配次設(shè)備號(hào)

????.name = DEVICE_NAME, ??????????// 設(shè)備名稱

????.fops = &my_device_fops, ?????????// 設(shè)備文件操作函數(shù)

};

(七)文件操作函數(shù),file_operations類型結(jié)構(gòu)體定義

static struct file_operations my_device_fops = {

????.owner = THIS_MODULE,

????.open = my_device_open,

????.release = my_device_release,

????.unlocked_ioctl = myled_ioctl,

};

(八)文件操作函數(shù)實(shí)現(xiàn):

static int my_device_open(struct inode *inode, struct file *file)

{

// 打開設(shè)備的操作

//將引腳配置為輸出

????gpio_direction_output(gpio, 1);

????printk(KERN_INFO "This is device_open.n");

????????return 0;

}

?

static long myled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

?

????switch (cmd) {

????????????case SET_LED_ON:

????????????????printk(KERN_INFO "This is set_led_on.n");

????????????// 設(shè)置GPIO引腳為低電平

????????????gpio_set_value(gpio, 0);

????????????break;

?

????????case SET_LED_OFF:

??????????//設(shè)置GPIO引腳為高電平

??????????printk(KERN_INFO "This is set_led_off.n");

??????????gpio_set_value(gpio, 1);

????????????break;

?

????????default:

????????????return -ENOTTY;

????}

?

????return 0;

}

?

static int my_device_release(struct inode *inode, struct file *file)

{

????// 關(guān)閉設(shè)備的操作

????return 0;

}

文件操作函數(shù)同樣使用ioctl來(lái)實(shí)現(xiàn),與之前的LED操作一樣,接收到SET_LED_ON命令后將引腳拉低,接收到SET_LED_OFF命令后,將引腳電平拉高。

完整的驅(qū)動(dòng)platform_led.c示例源碼

#include <linux/init.h>

#include <linux/module.h> ??????// 包含模塊相關(guān)函數(shù)的頭文件

#include <linux/fs.h> ??????????// 包含文件系統(tǒng)相關(guān)函數(shù)的頭文件

#include <linux/platform_device.h>

#include <linux/miscdevice.h>

#include <linux/device.h> ??????//包含設(shè)備節(jié)點(diǎn)相關(guān)的頭文件

#include <linux/gpio.h> ????????//包含gpio操作函數(shù)的相關(guān)頭文件

#include <linux/of_gpio.h>

#include <linux/of.h>

?

#define DEVICE_NAME "my_device"

#define LED_IOC_MAGIC 'k'

#define SET_LED_ON _IO(LED_IOC_MAGIC, 0)

#define SET_LED_OFF _IO(LED_IOC_MAGIC, 1)

?

struct device_node *node; ??//設(shè)備樹節(jié)點(diǎn)

int gpio; ??//gpio編號(hào)

?

static int my_device_open(struct inode *inode, struct file *file)

{

// 打開設(shè)備的操作

//將引腳配置為輸出

????gpio_direction_output(gpio, 1);

????printk(KERN_INFO "This is device_open.n");

????????return 0;

}

?

static long myled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

?

????switch (cmd) {

????????????case SET_LED_ON:

????????????????printk(KERN_INFO "This is set_led_on.n");

????????????// 設(shè)置GPIO引腳為低電平

????????????gpio_set_value(gpio, 0);

????????????break;

?

????????case SET_LED_OFF:

??????????//設(shè)置GPIO引腳為高電平

??????????printk(KERN_INFO "This is set_led_off.n");

??????????gpio_set_value(gpio, 1);

????????????break;

?

????????default:

????????????return -ENOTTY;

????}

?

????return 0;

}

?

static int my_device_release(struct inode *inode, struct file *file)

{

????// 關(guān)閉設(shè)備的操作

????return 0;

}

?

static struct file_operations my_device_fops = {

????.owner = THIS_MODULE,

????.open = my_device_open,

????.release = my_device_release,

????.unlocked_ioctl = myled_ioctl,

};

?

static struct miscdevice my_misc_device = {

????.minor = MISC_DYNAMIC_MINOR,

????.name = DEVICE_NAME,

????.fops = &my_device_fops,

};

?

static int my_platform_probe(struct platform_device *pdev)

{

????????struct device *dev = &pdev->dev;

????????int ret;

????????//注冊(cè)雜項(xiàng)設(shè)備

????????ret = misc_register(&my_misc_device);

????????if (ret) {

????????pr_err("Failed to register misc devicen");

????????return ret;

????????}

????????// 獲取設(shè)備節(jié)點(diǎn)

????????node = of_find_node_by_name(NULL,"leds");

????????// 獲取 gpios 屬性中的引腳編號(hào)

????????gpio = of_get_named_gpio(node, "gpios", 0);

????????//判斷是否獲取成功

?????????if (!gpio_is_valid(gpio)) {

?????????pr_err("Failed to get GPIOn");

?????????return -1;

????????}

?

????????gpio_free(gpio);

????????if (gpio_request(gpio, "led_run")) {

????????????????printk("request %s gpio faile n", "led_run");

?????????????????return -1;

?????????}

????????printk(KERN_INFO "my_platform_probe: Platform device probedn");

????return 0;

}

static int my_platform_remove(struct platform_device *pdev)

{

????????misc_deregister(&my_misc_device);

?

????????printk(KERN_INFO "my_platform_remove: Platform device removedn");

????return 0;

}

?

static const struct of_device_id of_platform_match[] = {

????????{ .compatible = "platform_led", },

????????{},

};

?

static struct platform_driver my_platform_driver = {

????.driver = {

????????.name = "my_platform_driver",

????????.owner = THIS_MODULE,

????????.of_match_table = of_platform_match,

????},

????.probe = my_platform_probe,

????.remove = my_platform_remove,

};

?

module_platform_driver(my_platform_driver);

?

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Your Name");

MODULE_DESCRIPTION("Platform Driver Example");

編譯

復(fù)制7.7.2驅(qū)動(dòng)中的Makefile文件,將其中的platform.o修改為platform_led.o,效果如下:

. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

elf@ubuntu:~/work/test/06_platform/platform_led$?make ?????????????????????????

將編譯生成的platform_led.ko模塊拷貝到開發(fā)板。

測(cè)試

測(cè)試app使用之前章節(jié)的app即可。

root@ELF1:~# insmod platform_led.ko

my_platform_probe: Platform device probed

root@ELF1:~# ./led_app

This is device_open.

This is set_led_on.

This is set_led_off.

This is set_led_on.

This is set_led_off.

This is set_led_on.

This is set_led_off.

This is set_led_on.

This is set_led_off.

This is set_led_on.

This is set_led_off.

root@ELF1:~# rmmod platform_led.ko

my_platform_remove: Platform device removed

此時(shí)可以看到開發(fā)板上的紅色LED,循環(huán)閃爍5次。

相關(guān)推薦