1. 程式人生 > >基於裝置樹下gpio的簡單操作

基於裝置樹下gpio的簡單操作

目標: 
學習裝置樹中GPIO資源的使用,實現按鍵中斷簡單驅動程式。

原理圖: 
這裡寫圖片描述 
tiny4412 底板上有4顆按鍵,分別為連線在 GPX3_2、GPX3_3、GPX3_4、GPX3_5 ,引腳狀態常高。

裝置樹:

    interrupt_demo: interrupt_demo {
            compatible         = "tiny4412,interrupt_demo";
            tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;
            tiny4412,int_gpio2 = <&gpx3
3 GPIO_ACTIVE_HIGH>
; tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>; tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>; };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

<&gpx3 2 GPIO_ACTIVE_HIGHT> 代表什麼含義呢?

Eg: <&gpx2 6 0> 
  <[phandle of the gpio controller node] 
  [pin number within the gpio controller] 
  [flags]> 
  Values for gpio specifier: 
  - Pin number: is a value between 0 to 7. 
  - Flags: 0 - Active High 1 - Active Low

  • &gpx3 引用 gpx3 這個節點,代表這個 GPIO 是屬於控制器 gpx3
  • 2 則表示gpx3 這組管腳中的哪一個,gpx3_2
  • GPIO_ACTIVE_HIGHT 則表示引腳狀態為常高的

驅動程式:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
typedef struct { int gpio; int irq; char name[20]; }int_demo_data_t; static irqreturn_t int_demo_isr(int irq, void *dev_id) { int_demo_data_t *data = dev_id; printk("%s enter, %s: gpio:%d, irq: %d\n", __func__, data->name, data->gpio, data->irq); return IRQ_HANDLED; } static int int_demo_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int irq_gpio = -1; int irq = -1; int ret = 0; int i = 0; int_demo_data_t *data = NULL; printk("%s enter.\n", __func__); if (!dev->of_node) { dev_err(dev, "no platform data.\n"); goto err1; } data = devm_kmalloc(dev, sizeof(*data)*4, GFP_KERNEL); if (!data) { dev_err(dev, "no memory.\n"); goto err0; } #if 1 for (i = 3; i >= 0; i--) { sprintf(data[i].name, "tiny4412,int_gpio%d", i+1);//名字是我們自己填充的,並不是獲取到的 #else for (i = 0; i < 4; i++) { #endif irq_gpio = of_get_named_gpio(dev->of_node, data[i].name, 0);//通過名字獲取gpio if (irq_gpio < 0) { dev_err(dev, "Looking up %s property in node %s failed %d\n", data[i].name, dev->of_node->full_name, irq_gpio); goto err1; } data[i].gpio = irq_gpio; irq = gpio_to_irq(irq_gpio); //將gpio轉換成對應的中斷號 if (irq < 0) { dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n", irq_gpio, irq); goto err1; } data[i].irq = irq; printk("%s: gpio: %d ---> irq (%d)\n", __func__, irq_gpio, irq); //註冊中斷 ret = devm_request_any_context_irq(dev, irq, int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i); if (ret < 0) { dev_err(dev, "Unable to claim irq %d; error %d\n", irq, ret); goto err1; } } return 0; err1: devm_kfree(dev, data); err0: return -EINVAL; } static int int_demo_remove(struct platform_device *pdev) { printk("%s enter.\n", __func__); return 0; } static const struct of_device_id int_demo_dt_ids[] = { { .compatible = "tiny4412,interrupt_demo", }, {}, }; MODULE_DEVICE_TABLE(of, int_demo_dt_ids); static struct platform_driver int_demo_driver = { .driver = { .name = "interrupt_demo", .of_match_table = of_match_ptr(int_demo_dt_ids), }, .probe = int_demo_probe, .remove = int_demo_remove, }; static int __init int_demo_init(void) { int ret; ret = platform_driver_register(&int_demo_driver); if (ret) printk(KERN_ERR "int demo: probe failed: %d\n", ret); return ret; } module_init(int_demo_init); static void __exit int_demo_exit(void) { platform_driver_unregister(&int_demo_driver); } module_exit(int_demo_exit); MODULE_LICENSE("GPL");