編寫MTK6737平臺的GPIO驅動例程(三)
阿新 • • 發佈:2019-01-10
在原先的裝置驅動檔案上增加上更加方便的互動方式那就是sysfs介面,使用device_create_file用於在sys下建立裝置的屬性節點。
注意一下device_attribute可以使用一下兩種方法初始化
1、使用DEVICE_ATTR初始化結構體device_attribute,下面程式碼示例:
static DEVICE_ATTR(demo, (S_IRUGO | S_IWUSR | S_IWGRP),demo_show,demo_store);
static DEVICE_ATTR(demo, 0444,demo_show,NULL);
其中引數:mode可以直接定義成只讀0444,只寫0222,或者讀寫都行的0666。。
_show和_store函式當沒有的時候用NULL賦值,對函式的名稱和內容沒有具體要求,甚至可以和別的屬性相同。
2、也可以使用直接賦值的方法初始化device_attribute結構體,下面程式碼示例:
static struct device_attribute dev_attr_demo = {
.attr = {
.name = "demo",
.mode = (S_IRUGO | S_IWUSR)
},
.show = demo_show,
.store = demo_store,
};
下面上程式碼,其實就是增加了這麼一個介面操作立馬很容易了,你就可以不用寫測試程式了。
#include <linux/slab.h> #include <linux/device.h> #include <linux/miscdevice.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <generated/autoconf.h> #include <linux/platform_device.h> #include <linux/fs.h> #include <linux/ioctl.h> #include <linux/types.h> #include <linux/spinlock.h> #include <linux/cdev.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/atomic.h> #include "mt-plat/mtgpio.h" #include <linux/types.h> #include <mt-plat/mt_gpio.h> #include <mt-plat/mt_gpio_core.h> #include <mach/gpio_const.h> #include <linux/interrupt.h> #include <linux/time.h> #include <linux/seq_file.h> #include <linux/list.h> #include <linux/proc_fs.h> #include <linux/kobject.h> #include <linux/regulator/consumer.h> /* 生命函式定義 */ static int mygpio_probe(struct platform_device *pdev); static int mygpio_remove(struct platform_device *pdev); static ssize_t my_gpio96_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); struct pinctrl *pinctrlio96; struct pinctrl_state *pio96_output0, *pio96_output1; static const struct of_device_id mygpio_of_match[] = { { .compatible = "mykgpio", }, {}, }; static struct platform_driver mygpio_driver = { .remove = mygpio_remove, .probe = mygpio_probe, .driver = { .name = "myGPIO", .owner = THIS_MODULE, .of_match_table = mygpio_of_match, }, }; static struct device_attribute mygpio96_attr = { .attr = { .name = "mygpio96", .mode = 0222, /*mode可以直接定義成只讀0444,只寫0222,或者讀寫都行的0666。*/ }, .store = &my_gpio96_store, }; /* 設定管教的狀態 level=1 輸出高電平 level=0 輸出低電平*/ void my673x_gpio_output(int level) { printk("[myGPIO]my673x_gpio_output level = %d\n", level); /* 設定名字為"my_state_io96_output0"這個pinctrl對應引腳的pin state */ if (level==1) pinctrl_select_state(pinctrlio96, pio96_output1); if (level==0) pinctrl_select_state(pinctrlio96, pio96_output0); } //屬性檔案的store方法(也就是寫) static ssize_t my_gpio96_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int temp=0; sscanf(buf, "%d", &temp); /*將buf中的值以%d的形式賦值給temp*/ printk("[myGPIO]my673x_gpio_output level = %d \n", temp); my673x_gpio_output(temp); return count; } static int mygpio_misc_open(struct inode *inode, struct file *file) { printk("MyGPIO OPen. \r\n"); return 0; } static int mygpio_misc_release(struct inode *inode, struct file *file) { printk("MyGPIO Release. \r\n"); return 0; } static long mygpio_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { printk("MyGPIO Ioctl. \r\n"); printk("MyGPIO cmd=%d \r\n", cmd); /* 根據命令執行相應的操作 */ switch(cmd) { /* 輸出GPIO96高電平 */ case 1: my673x_gpio_output(1); break; /* 輸出GPIO96低電平 */ case 0: my673x_gpio_output(0); break; default: return -EINVAL; } return 0; } static const struct file_operations mygpio_fops = { /* .owner = THIS_MODULE, */ .open = mygpio_misc_open, .release = mygpio_misc_release, .unlocked_ioctl = mygpio_unlocked_ioctl, }; static struct miscdevice mygpio_misc_device = { .minor = MISC_DYNAMIC_MINOR, //動態裝置號 .name = "myGPIO", .fops = &mygpio_fops, }; /* My GPIO probe */ static int mygpio_probe(struct platform_device *pdev) { int ret = 0; printk("MyGPIO Probe. \r\n"); /* 註冊一個misc裝置 */ ret = misc_register(&mygpio_misc_device); if (ret != 0 ) printk("myGPIO: mygpio_device register failed\n"); /* 在/sys/devices/節點下建立名字是“mygpio96”裝置節點 */ /* 所生成的裝置節點:/sys/devices/soc/soc:
[email protected] */ /* echo 0 > mygpio96 燈亮 | echo 1 > mygpio96 燈滅 */ if (device_create_file(&pdev->dev, &mygpio96_attr)) //關聯到哪個裝置 printk("[MyGPIO] Unable to create sysfs entry: '%s'\n", mygpio96_attr.attr.name); /* 獲取pin control state holder 的控制代碼 */ pinctrlio96 = devm_pinctrl_get(&pdev->dev); if (IS_ERR(pinctrlio96)) { ret = PTR_ERR(pinctrlio96); printk("fwq Cannot find mygpio pinctrlio96!\n"); return ret; } /* dts中 pinctrl-names = "my_state_io96_output0", "my_state_io96_output1"; */ /* 得到裝置樹中名字為 my_state_io96_output0和 my_state_io96_output1對應的pin state */ pio96_output0 = pinctrl_lookup_state(pinctrlio96, "my_state_io96_output0"); if (IS_ERR(pio96_output0)) { ret = PTR_ERR(pio96_output0); printk("fwq Cannot find touch pinctrl my_state_io96_output0!\n"); return ret; } pio96_output1 = pinctrl_lookup_state(pinctrlio96, "my_state_io96_output1"); if (IS_ERR(pio96_output1)) { ret = PTR_ERR(pio96_output1); printk("fwq Cannot find touch pinctrl my_state_io96_output1!\n"); return ret; } return ret; } static int mygpio_remove(struct platform_device *pdev) { int err; printk("MyGPIO remove. \r\n"); err = misc_deregister(&mygpio_misc_device); if (err) printk("deregister gpio\n"); return err; } static int __init my_gpio_init(void) { int ret = 0; printk("Register MyGPIO platform_driver. \r\n"); ret = platform_driver_register(&mygpio_driver); if(ret != 0 ) printk("unable to register MyGPIO driver.\n"); return ret; } /*---------------------------------------------------------------------------*/ static void __exit my_gpio_exit(void) { platform_driver_unregister(&mygpio_driver); } subsys_initcall(my_gpio_init); /*module_init(my_gpio_init);*/ module_exit(my_gpio_exit); MODULE_AUTHOR("zue"); MODULE_DESCRIPTION("MY General Purpose Driver (GPIO)"); MODULE_LICENSE("GPL v2");
在設備註冊後會在/sys/devices/soc/soc:[email protected]目錄下生成一個裝置節點,其實也可以使用find命令直接搜尋你註冊裝置節點名稱。
可以看到連線在96號管腳的LED會隨著echo的1或者0滅或者亮。這樣測試LED驅動就不用再次寫測試程式了。