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