樓主在這邊給大家介紹下如何使用PopMetal的GPIO。先講過程,再講原理吧, 該驅動需要涉及到的知識點:1,DTS設備樹的作用,2,platform虛擬總線驅動的編寫。 第一步,添加DTS節點 在/kernel/arch/arm/boot/dts/rockchip.dts下添加如下內容。 下圖rockchip-leds-gpio這部分的內容,修改保存, 第二步,在kernel/drivers下創建個LED文件夾,然后加入如下幾個文件驅動文件leds.c,Makefile和Kconfig.如下圖 源碼: /*********************************************************************************** * driver for led0 * **********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include static int leds_probe(struct platform_device *pdev) { int ret =-1 int i int led enum of_gpio_flags flag struct device_node *led_node = pdev->dev.of_node led = of_get_named_gpio_flags(led_node,"led-gpios",0,&flag) printk("get gpio id successful\n") if(!gpio_is_valid(led)){ printk("invalid led-gpios: %d\n",led) return -1 } if(gpio_request(led,"led_gpio")){ printk("led gpio request failed!\n") return ret } gpio_direction_output(led,1) for(i=0 i < 10 i++) { gpio_set_value(led,1) mdelay(500) gpio_set_value(led,0) mdelay(500) printk("it's %d\n",i) } return 0 } static int leds_remove(struct platform_device *pdev) { return 0 } static struct of_device_id leds_of_match[] = { { .compatible = "rockchip-leds-gpio" }, { } } MODULE_DEVICE_TABLE(of, leds_of_match) static struct platform_driver leds_driver = { .driver = { .name = "leds-drivers", .owner = THIS_MODULE, .of_match_table = of_match_ptr(leds_of_match), }, .probe = leds_probe, .remove = leds_remove, }; /*static int __init leds_init(void) { printk(KERN_INFO "Enter %s\n", __FUNCTION__) return platform_driver_register(&leds_driver) return 0 } static void __exit leds_exit(void) { platform_driver_unregister(&leds_driver) printk("close leds\n") }*/module_platform_driver(leds_driver) module_platform_driver(leds_driver) MODULE_DESCRIPTION("leds Driver") MODULE_LICENSE("GPL") MODULE_ALIAS("platform:leds-drivers") /*********************************************************************************** * driver for led0 * **********************************************************************************/ Kconfig: Makefile: 第三步,修改drivers下的Kconfig和Makefile,修改內容如下 在Kconfig末尾添加:source “drivers/led/Kconfig” 在Makefile末尾添加: obj-$(CONFIG_LED0_TEST) +=led/ 第四步,編譯新的kernel與resource并燒寫進板子里, 然后DTS中定義的引腳就會按照驅動的內容,進行高低電平的變化。 需要源碼可下載: 好了,現在我們來介紹下原理,首先是DTS,和另一塊開發板PX2不一樣,PopMetal并沒有寫相應的mach-*****文件,而是通過設備樹的方式獲取引腳的編號,設備樹的引入可減少了內核為支持新硬件而需要的改變,提高代碼重用,加速了Linux支持包的開發,使得單個內核鏡像能支持多個系統。簡單來說,它就是給內核的一個參數,這些參數會啟動相應的驅動,這樣參數不一樣,內核源碼支持的系統就不一樣。 而在這里我們要清楚的是我們要用相應的引腳就必須創建相應的節點,并且賦上一些參數。 而驅動又是怎么識別到這些參數的呢?這里我們先講講platform虛擬總線驅動,這個總線跟IIC,SPI等總線不一樣,是由內核虛擬出來的,我們就以上面的代碼為例,給大家講講他是怎么工作的, 首先這個驅動的核心是: static struct platform_driver leds_driver = { .driver = { .name = "leds-drivers",//驅動名 .owner = THIS_MODULE, .of_match_table = of_match_ptr(leds_of_match),//匹配設備樹 }, .probe = leds_probe,//探測函數,檢測硬件上是否存在設備,檢測到便執行 .remove = leds_remove,//移除函數,硬件移除時,執行 }; 在這里我們只給部分內容賦予了值,本身這個結構體還有別的子項,需要了解的同學可以在這編博客看看:http://blog.sina.com.cn/s/blog_53c733350100zdav.html 在這個結構體中,我們就是通過.of_match_table = of_match_ptr(leds_of_match),來匹配設備樹上的參數,而即系統會根據設備樹種定義的compatible參數比較驅動中的leds_of_match中定義的 .compatible 參數, 來為參數找到相應的驅動,而定義的probe和remove函數則是對探測到設備做出反應,及移除設備時做出反應,而module_platform_driver(leds_driver)是將驅動掛到總線上去, 現在我們看看probe是怎么獲取到GPIO的值的,其中它的主要函數如下: struct device_node *led_node = pdev->dev.of_node led = of_get_named_gpio_flags(led_node,"led-gpios",0,&flag) 功能就是將led_node節點上的led-gpios的值取下,而我們之前在rockchip.dts中隊led-gpios的定義如下: led-gpios=&GPIO6 GPIO_A6 GPIO_ACTIVE_LOW,意思就是選擇引腳gpio6_a6,且該引腳低電平有效。 上面這句賦值便已經將引腳的編號賦給了led-gpios,故接下來我們就可以用GPIO_requset_one GPIO_set_value,等函數去操作這個GPIO了,像gpio_set_value(led-gpios,1)將該引腳設置為高電平。 當然這些操作只是相對于引腳沒復用的GPIO口,引腳如果有復用功能,我們還得進行一些別的操作把引腳的功能選好。 |