Linux下gpio的相關函數分析

 gpio_request 原形代碼

  其原型爲 int gpio_request(unsigned gpio, const char *label) 先說說其參數,gpio則爲你要申請的哪一個管腳,label則是爲其取一個名字。其具體實現如下:


int gpio_request(unsigned gpio, const char *label)   
{   
        struct gpio_desc *desc;//這個自己看源碼   
        struct gpio_chip *chip;//這個自己看源碼   
        int   status = -EINVAL;   
        unsigned long  flags;  
        spin_lock_irqsave(&gpio_lock, flags);//屏蔽中斷  
        if (!gpio_is_valid(gpio))//判斷是否有效,也就是參數的取值範圍判斷   
             goto done;   
        desc = &gpio_desc[gpio];   
//這個是關鍵gpio_desc爲定義的一個全局的數組變量,這個函數的實值也就是,  
//用gpio_desc裏面的一個變量來表示數組中的這個元素已經被申請了,而這個變量就是下面會看到的desc->flags。   
chip = desc->chip;//按理說這個這個全局的gpio_desc如果沒有初始化的話,這個chip就爲空了,隨後就直接返回-EINVAL了。   
if (chip == NULL)如果不爲空繼續往下走   
  goto done;  
if (!try_module_get(chip->owner))   
  goto done;  
/* NOTE:  gpio_request() can be called in early boot,  
  * before IRQs are enabled, for non-sleeping (SOC) GPIOs.  
  */  
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {  
//這裏測試並設置flags的第FLAG_REQUESTED位,如果沒有被申請就返回該位的原值0,分析到這兒,也差不多滿足了我的個人要求。   
  desc_set_label(desc, label ? : "?");   
  status = 0;   
} else {   
  status = -EBUSY;   
  module_put(chip->owner);   
  goto done;   
}  
if (chip->request) {   
  /* chip->request may sleep */   
  spin_unlock_irqrestore(&gpio_lock, flags);   
  status = chip->request(chip, gpio - chip->base);   
  spin_lock_irqsave(&gpio_lock, flags);  
  if (status < 0) {   
   desc_set_label(desc, NULL);   
   module_put(chip->owner);   
   clear_bit(FLAG_REQUESTED, &desc->flags);   
  }   
}  
done:   
if (status)   
  pr_debug("gpio_request: gpio-%d (%s) status %d\n",   
   gpio, label ? : "?", status);   
spin_unlock_irqrestore(&gpio_lock, flags);   
return status;   
}  

davinci 平臺: 
[cpp] view plaincopy
/*  
* TI DaVinci GPIO Support  
*  
* Copyright (c) 2006 David Brownell  
* Copyright (c) 2007, MontaVista Software, Inc. <[email protected]>  
*  
* This program is free software; you can redistribute it and/or modify  
* it under the terms of the GNU General Public License as published by  
* the Free Software Foundation; either version 2 of the License, or  
* (at your option) any later version.  
*/   
  
#include <linux/errno.h>   
#include <linux/kernel.h>   
#include <linux/list.h>   
#include <linux/module.h>   
#include <linux/err.h>   
#include <linux/bitops.h>   
  
#include <asm/irq.h>   
#include <asm/io.h>   
#include <asm/hardware/clock.h>   
  
#include <asm/arch/irqs.h>   
#include <asm/arch/hardware.h>   
#include <asm/arch/gpio.h>   
#include <asm/arch/cpu.h>   
  
#include <asm/mach/irq.h>   
  
/*   
該文件實現了gpio的各種應用功能和向內核註冊gpio的中斷例程等功能。  
用戶的驅動程序可調用gpio_request和gpio_free使用或釋放該gpio,  
可以調用gpio_direction_input和gpio_direction_output函數設置gpio輸入輸出方向,  
調用gpio_get_value和gpio_set_value獲取設置值。  
*/   
  
static DEFINE_SPINLOCK(gpio_lock);   
  
/* 總共有DAVINCI_N_GPIO(71)個gpio引腳,故使用相應多的bit來記錄這些引腳的使用狀態 */   
static DECLARE_BITMAP(gpio_in_use, DAVINCI_N_GPIO);   
  
/*  
申請一個gpio,其實就是檢查該gpio是否空閒,如果空閒就可以使用並將該gpio相應的bit置位  
(在gpio_in_use中)。  
*/   
int gpio_request(unsigned gpio, const char *tag)   
{   
    if (gpio >= DAVINCI_N_GPIO)   
        return -EINVAL;   
    if (test_and_set_bit(gpio, gpio_in_use))   
        return -EBUSY;   
    return 0;   
}   
EXPORT_SYMBOL(gpio_request);   
  
/*  
釋放一個gpio,其實就是清除gpio相應的控制bit位(在gpio_in_use中)。  
*/   
void gpio_free(unsigned gpio)   
{   
    if (gpio >= DAVINCI_N_GPIO)   
        return;   
    clear_bit(gpio, gpio_in_use);   
}   
EXPORT_SYMBOL(gpio_free);   
  
/* 獲得gpio_controller結構體指針,gpio_controller結構體是gpio的核心控制單元,裏面包含  
gpio的設置和數據寄存器。該結構體和__gpio_to_controller函數在/include/asm-arm/  
arch-davinci/gpio.h中定義,具體如下:  
struct gpio_controller {  
    u32    dir;  
    u32    out_data;  
    u32    set_data;  
    u32    clr_data;  
    u32    in_data;  
    u32    set_rising;  
    u32    clr_rising;  
    u32    set_falling;  
    u32    clr_falling;  
    u32    intstat;  
};  
 
static inline struct gpio_controller *__iomem  
__gpio_to_controller(unsigned gpio)  
{  
    void *__iomem ptr;  
    if (gpio >= DAVINCI_N_GPIO)  
        return NULL;  
 
    if (gpio < 32)  
        ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);  
    else if (gpio < 64)  
        ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);  
    else if (gpio < 96)  
        ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);  
    else  
        ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x88);  
    return ptr;  
}  
由上面的定義和ti的SPRUE25.pdf手冊可以看出,__gpio_to_controller函數返回的是  
gpio_controller結構體到第一個成員dir的虛擬地址。獲取了這個結構體指針後,  
便可以控制相應的gpio了。dm644x共有71個gpio,  
所以使用三個gpio_controller結構體控制,關於這個後面會由更詳細的分析,  
*/   
/* create a non-inlined version */   
static struct gpio_controller *__iomem gpio2controller(unsigned gpio)   
{   
    return __gpio_to_controller(gpio);   
}   
  
/*   
向某個gpio設置值,0或1。如果向gpio寫1,則向set_data寄存器相應的位置1,如果寫0,  
則向clr_data寄存器相應的位置1.__gpio_mask函數在gpio.h中定義,定義如下,  
static inline u32 __gpio_mask(unsigned gpio)  
{  
    return 1 << (gpio % 32);  
}  
因爲71個引腳由3個結構體控制,第一個控制前32個gpio,第二個控制次32個gpio,  
最後一個控制剩餘的7個gpio,故__gpio_mask函數的作用是找到在其相應控制結構體裏的偏移數,  
比如gpio34,那麼其由第二個結構體控制,在這個機構體裏的偏移是3(從0開始算,就是第二位)。  
使用這個函數之前,必須確認該gpio設置成輸出模式。  
*/   
/*  
* Assuming the pin is muxed as a gpio output, set its output value.  
*/   
void __gpio_set(unsigned gpio, int value)   
{   
    struct gpio_controller *__iomem g = gpio2controller(gpio);   
    // 設置gpio的值   
    __raw_writel(__gpio_mask(gpio), value ? &g->set_data : &g->clr_data);    
}   
EXPORT_SYMBOL(__gpio_set);   
  
/*   
通過讀取in_data寄存器相應該gpio的位來讀取gpio的值。  
使用這個函數之前,必須確認該gpio設置成輸入模式,否則獲得到值不可預料。   
*/   
/*  
* Read the pin's value (works even if it's set up as output);  
* returns zero/nonzero.  
*  
* Note that changes are synched to the GPIO clock, so reading values back  
* right after you've set them may give old values.  
*/   
int __gpio_get(unsigned gpio)   
{   
    struct gpio_controller *__iomem g = gpio2controller(gpio);   
    /* 讀取gpio的值,!!的目的是使得返回的值爲0或1.*/   
    return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));       
}                                                                                                                  }   
EXPORT_SYMBOL(__gpio_get);   
  
/*   
通過dir寄存器相應該gpio的位來設置gpio輸入輸出方向,爲0,則設置成輸出,爲1,則設置出輸入。  
該函數是設置成輸入,故設置dir寄存器爲1.  
 正如應爲所說的,必須確認該引腳是作爲gpio功能,而不是某個模塊到功能,比如spi。通過PINMUX0  
和PINMUX1兩個寄存器來設置。  
*/   
/*--------------------------------------------------------------------------*/   
  
/*  
* board setup code *MUST* set PINMUX0 and PINMUX1 as  
* needed, and enable the GPIO clock.  
*/   
int gpio_direction_input(unsigned gpio)   
{   
    struct gpio_controller *__iomem g = gpio2controller(gpio);   
    u32 temp;   
    u32 mask;   
  
    if (!g)   
        return -EINVAL;   
    spin_lock(&gpio_lock);   
    mask = __gpio_mask(gpio);   
    temp = __raw_readl(&g->dir);   
    temp |= mask;    // 設置成1   
    __raw_writel(temp, &g->dir);    // 設置該gpio爲輸入   
    spin_unlock(&gpio_lock);   
    return 0;   
}   
EXPORT_SYMBOL(gpio_direction_input);   
  
/*  
通過dir寄存器相應該gpio的位來設置gpio輸入輸出方向,爲0,則設置成輸出,爲1,則設置出輸入。  
該函數是設置成輸出,故設置dir寄存器爲0.  
value參數用於選擇gpio設置成輸出後該gpio輸出的值。  
*/   
int gpio_direction_output(unsigned gpio, int value)   
{   
    struct gpio_controller *__iomem g = gpio2controller(gpio);   
    u32 temp;   
    u32 mask;   
    if (!g)   
        return -EINVAL;   
  
    spin_lock(&gpio_lock);   
    mask = __gpio_mask(gpio);   
    temp = __raw_readl(&g->dir);   
    temp &= ~mask;    // 設置成0    
    //設置該gpio輸出值   
    __raw_writel(mask, value ? &g->set_data : &g->clr_data);   
    __raw_writel(temp, &g->dir);    // 設置gpio爲輸出   
    spin_unlock(&gpio_lock);   
    return 0;   
}   
EXPORT_SYMBOL(gpio_direction_output);   
  
/*  
向gpio設置值,0或1。  
*/   
void gpio_set_value(unsigned gpio, int value)   
{   
    if (__builtin_constant_p(value)) {   
        struct gpio_controller *__iomem g;   
        u32 mask;   
  
        if (gpio >= DAVINCI_N_GPIO)   
            __error_inval_gpio();   
  
        g = __gpio_to_controller(gpio);   
        mask = __gpio_mask(gpio);   
        if (value)   
            __raw_writel(mask, &g->set_data);    // 該gpio輸出高   
  
        else   
            __raw_writel(mask, &g->clr_data);    // 該gpio輸出低   
  
        return;   
    }   
  
    __gpio_set(gpio, value);   
}   
EXPORT_SYMBOL(gpio_set_value);   
  
/*  
讀取gpio的值,0或1.  
*/   
int gpio_get_value(unsigned gpio)   
{   
    struct gpio_controller *__iomem g;   
  
    if (!__builtin_constant_p(gpio))/* 判斷該gpio值是否爲編譯時常數,如果是常數,  
                                     函數返回 1,否則返回 0 */   
        return __gpio_get(gpio);   
  
    if (gpio >= DAVINCI_N_GPIO)   
        return __error_inval_gpio();   
  
    g = __gpio_to_controller(gpio);   
       
    // 讀取該gpio的值   
  
    return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));   
}   
EXPORT_SYMBOL(gpio_get_value);   
  
/*  
* We expect irqs will normally be set up as input pins, but they can also be  
* used as output pins ... which is convenient for testing.  
*  
* NOTE: GPIO0..GPIO7 also have direct INTC hookups, which work in addition  
* to their GPIOBNK0 irq (but with a bit less overhead). But we don't have  
* a good way to hook those up ...  
*  
* All those INTC hookups (GPIO0..GPIO7 plus five IRQ banks) can also  
* serve as EDMA event triggers.  
*/   
  
/*  
禁止相應該irq的gpio的中斷。每個gpio都可以作爲中斷的來源,其中gpio0-gpio7是獨立的中斷來源,  
也就是分配獨立的中斷號,其他gpio則共用5個GPIOBNK中斷線。其優先級可以在board-evm.c  
中設置(已經介紹過)。在dm644x平臺上,中斷是電平邊緣觸發的,禁止中斷其實就是既不設置  
上升沿觸發,也不設置下降沿觸發。  
*/   
static void gpio_irq_disable(unsigned irq)   
{   
    struct gpio_controller *__iomem g = get_irq_chipdata(irq);   
    u32 mask = __gpio_mask(irq_to_gpio(irq));   
  
    __raw_writel(mask, &g->clr_falling);    // 清除下降沿觸發   
  
    __raw_writel(mask, &g->clr_rising);        // 清除上升沿觸發   
  
}   
  
/*  
中斷使能。  
在dm644x平臺上,中斷是電平邊緣觸發的,其實就是設置爲上升沿或下降沿中斷。  
*/   
static void gpio_irq_enable(unsigned irq)   
{   
    struct gpio_controller *__iomem g = get_irq_chipdata(irq);   
    u32 mask = __gpio_mask(irq_to_gpio(irq));   
  
    // 如果先前爲下降沿中斷,則使能爲下降沿中斷   
  
    if (irq_desc[irq].status & IRQT_FALLING)   
        __raw_writel(mask, &g->set_falling);   
       
    // 如果先前爲上升沿中斷,則使能爲上升沿中斷   
  
    if (irq_desc[irq].status & IRQT_RISING)       
        __raw_writel(mask, &g->set_rising);   
}   
  
/*  
設置中斷類型。  
在dm644x平臺上,中斷有上升沿和下降沿兩種觸發方式。  
*/   
static int gpio_irq_type(unsigned irq, unsigned trigger)   
{   
    struct gpio_controller *__iomem g = get_irq_chipdata(irq);   
    u32 mask = __gpio_mask(irq_to_gpio(irq));   
  
    if (trigger & ~(IRQT_FALLING | IRQT_RISING))   
        return -EINVAL;   
  
    irq_desc[irq].status &= ~IRQT_BOTHEDGE;   
    irq_desc[irq].status |= trigger;   
  
    __raw_writel(mask, (trigger & IRQT_FALLING)   
         ? &g->set_falling : &g->clr_falling);     // 設置爲下降沿觸發   
  
    __raw_writel(mask, (trigger & IRQT_RISING)   
         ? &g->set_rising : &g->clr_rising);    // 設置爲上升沿觸發   
  
    return 0;   
}   
  
/*   
該結構體用於註冊到所有irq的中斷描述結構體中(struct irqdesc),  
而所有中斷描述結構體定義成一個全局數組irq_desc 。  
*/   
static struct irqchip gpio_irqchip = {   
    .unmask        = gpio_irq_enable, /* 用於使能中斷,  
                                     在enable_irq()等內核函數中會用到。*/       
    .mask        = gpio_irq_disable,/* 用於禁止中斷,  
                                     在disable_irq()等內核函數中會用到。*/   
    .type        = gpio_irq_type, /* 用於設置中斷類型,  
                                     在set_irq_type()內核函數中會用到。*/   
};   
  
/*  
該函數將在下面的davinci_gpio_irq_setup中使用,將被註冊到五個gpio bank中斷的  
irq_desc結構中,目的是處理所有級聯的gpio中斷。所謂級聯的中斷, 就是指有n箇中斷  
共用同一個中斷線。  
在dm644x平臺中,除了gpio0-gpio7外,其他63個gpio都共用五個gpiobank中斷線,在這裏,  
gpio0-gpio7也被註冊到gpiobank中斷線,但實際上並不會使用,因爲它們擁有自己的  
中斷線。其中,gpio0-gpio15共用IRQ_GPIOBNK0(56)中斷線,gpio16-gpio31共用  
IRQ_GPIOBNK1(57)中斷線,gpio32-gpio47共用IRQ_GPIOBNK2(58)中斷線,  
gpio48-gpio63共用IRQ_GPIOBNK4(59)中斷線,gpio64-gpio70共用  
IRQ_GPIOBNK5(60)中斷線,  
因爲寄存器是32位的,所以實際上只有三組寄存器,第一組包含bank0和bank1,  
也就是gpio0-gpio31,第二組包含bank2和bank3,也就是gpio32-gpio63,  
第三組包含bank4和bank5,也就是gpio64-gpio70,剩餘了25個位沒有使用。  
*/   
static void   
gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs *regs)   
{   
    struct gpio_controller *__iomem g = get_irq_chipdata(irq);   
    u32 mask = 0xffff;   
  
    /* we only care about one bank */   
    // 如果bank中斷線是寄數,則說明該中斷的中斷狀態位在INTSTATn寄存器的高16位   
  
    if (irq & 1)   
        mask <<= 16;   
  
    /* temporarily mask (level sensitive) parent IRQ */   
    desc->chip->ack(irq);// 該ack函數會在arch/arm/mach-davinci/irq.c中註冊。   
  
    while (1) {   
        u32        status;   
        struct irqdesc    *gpio;   
        int        n;   
        int        res;   
  
        /* ack any irqs */   
        /*gpio中斷髮生後,硬件會在INTSTATn寄存器中置位相應位,  
         以備程序查詢,確定是哪個gpio*/   
        status = __raw_readl(&g->intstat) & mask;    
        if (!status)   
            break;   
        __raw_writel(status, &g->intstat);    // 向該位寫1清除   
  
        if (irq & 1)   
            status >>= 16;   
  
        /* now demux them to the right lowlevel handler */   
        // 從下面的davinci_gpio_irq_setup函數可以看出來以下程序的運作。   
  
        n = (int)get_irq_data(irq);    // 獲取該bank對應的第一個gpio號   
  
        gpio = &irq_desc[n];    // 獲取該bank第一個gpio號對應的中斷描述符   
  
        while (status) {    // 該bank可能有多個gpio發生了中斷   
  
            res = ffs(status);    // 獲取第一個發生了中斷的位(1-32)   
  
            n += res;    /* 獲得該gpio的中斷線(系統實際上只有64(0-63)箇中斷線,  
                        但那些共用的gpio的中斷也有自己的斷描述符和中斷線(從64開始),  
                        僅僅是爲了管理,不能通過request_irq()函數來申請。*/   
            gpio += res;    //     獲得該gpio的中斷描述符   
  
               
            /* 調用下面註冊的do_simple_IRQ例程  
             其又會調用用戶通過request_irq()  
             註冊的中斷例程  
            */   
            desc_handle_irq(n - 1, gpio - 1, regs);       
            status >>= res;           
        }   
    }   
    desc->chip->unmask(irq);    // 打開該irq中斷線   
  
    /* now it may re-trigger */   
}   
  
/*  
* NOTE: for suspend/resume, probably best to make a sysdev (and class)  
* with its suspend/resume calls hooking into the results of the set_wake()  
* calls ... so if no gpios are wakeup events the clock can be disabled,  
* with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0  
* can be set appropriately for GPIOV33 pins.  
*/   
/*  
註冊gpio中斷例程到內核中,並初始化了一些寄存器。  
該函數將會被board_evm.c(其淺析已經發表)中的evm_init()函數調用。具體調用過程如下:  
start_kernel()-->setup_arch()-->init_machine = mdesc->init_machine  
(init_machine是個全局函數指針變量,其指向的就是已經註冊到機器描述符裏evm_init());  
調用函數指針init_machine()的例程是customize_machine(),其定義爲  
arch_initcall(customize_machine),所以,接下來的調用過程是:  
start_kernel()-->do_basic_setup()-->do_initcalls()-->customize_machine()-->  
init_machine()(也就是evm_init())-->davinci_gpio_irq_setup。  
從上可以看出經歷了兩個過程,才調用davinci_gpio_irq_setup例程來初始化gpio中斷。  
*/   
int __init davinci_gpio_irq_setup(void)   
{   
    unsigned    gpio, irq, bank, banks;   
    struct clk    *clk;   
  
    clk = clk_get(NULL, "gpio");    // 獲取時鐘   
  
    if (IS_ERR(clk)) {   
        printk(KERN_ERR "Error %ld getting gpio clock?\n",   
         PTR_ERR(clk));   
        return 0;   
    }   
  
    clk_enable(clk);    // 使能gpio時鐘並打開該模塊電源   
  
  
    for (gpio = 0, irq = gpio_to_irq(0), bank = (cpu_is_davinci_dm355() ?   
     IRQ_DM355_GPIOBNK0 : (cpu_is_davinci_dm6467() ?   
     IRQ_DM646X_GPIOBNK0 : IRQ_GPIOBNK0));    // dm644x的IRQ_GPIOBNK0(56)   
  
     gpio < DAVINCI_N_GPIO; bank++) {    // dm644x的DAVINCI_N_GPIO(71)   
  
        struct gpio_controller    *__iomem g = gpio2controller(gpio);   
        unsigned        i;   
  
        // 關該bank所有gpio的中斷   
  
        __raw_writel(~0, &g->clr_falling);   
        __raw_writel(~0, &g->clr_rising);   
  
        /* set up all irqs in this bank */   
        // 同一個bank的所有gpio共用一箇中斷例程gpio_irq_handler   
  
        set_irq_chained_handler(bank, gpio_irq_handler);   
        set_irq_chipdata(bank, g);   
        set_irq_data(bank, (void *)irq);   
  
        for (i = 0; i < 16 && gpio < DAVINCI_N_GPIO;   
         i++, irq++, gpio++) {   
            set_irq_chip(irq, &gpio_irqchip);    /* 註冊用於gpio中斷禁止、設能  
                                                 和類型選擇的回調例程 */   
            set_irq_chipdata(irq, g);            // 保存控制結構體(寄存器)的地址   
  
            set_irq_handler(irq, do_simple_IRQ);/* 爲每個gpio中斷設置同一個中  
                                                    斷例程do_simple_IRQ*/   
            set_irq_flags(irq, IRQF_VALID);        // fiq中斷有效   
  
        }   
    }   
/*      
一個共用bank中斷線的gpio中斷髮生後的大致的流程是:  
--> gpio_irq_handler --> do_simple_IRQ --> __do_irq -->   
action->handler(用戶使用request_irq()註冊的中斷例程)  
*/   
    /* BINTEN -- per-bank interrupt enable. genirq would also let these  
     * bits be set/cleared dynamically.  
     */   
    if (cpu_is_davinci_dm355())   
        banks = 0x3f;   
    else   
        banks = 0x1f;   
       
    // 向BINTEN寄存器寫入0x1f(共5個位,每個位控制1個bank),打開所有的bank中斷   
  
    __raw_writel(banks, (void *__iomem)   
         IO_ADDRESS(DAVINCI_GPIO_BASE + 0x08));   
  
    printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));   
  
    return 0;   
}   
  
   
  
  
gpio.h   
  
  
/*  
* TI DaVinci GPIO Support  
*  
* Copyright (c) 2006 David Brownell  
* Copyright (c) 2007, MontaVista Software, Inc. <[email protected]>  
*  
* This program is free software; you can redistribute it and/or modify  
* it under the terms of the GNU General Public License as published by  
* the Free Software Foundation; either version 2 of the License, or  
* (at your option) any later version.  
*/   
  
#ifndef    __DAVINCI_GPIO_H   
#define    __DAVINCI_GPIO_H   
  
/*  
* basic gpio routines  
*  
* board-specific init should be done by arch/.../.../board-XXX.c (maybe  
* initializing banks together) rather than boot loaders; kexec() won't  
* go through boot loaders.  
*  
* the gpio clock will be turned on when gpios are used, and you may also  
* need to pay attention to PINMUX0 and PINMUX1 to be sure those pins are  
* used as gpios, not with other peripherals.  
*  
* GPIOs are numbered 0..(DAVINCI_N_GPIO-1). For documentation, and maybe  
* for later updates, code should write GPIO(N) or:  
* - GPIOV18(N) for 1.8V pins, N in 0..53; same as GPIO(0)..GPIO(53)  
* - GPIOV33(N) for 3.3V pins, N in 0..17; same as GPIO(54)..GPIO(70)  
*  
* For GPIO IRQs use gpio_to_irq(GPIO(N)) or gpio_to_irq(GPIOV33(N)) etc  
* for now, that's != GPIO(N)  
*/   
#define    GPIO(X)        (X)        /* 0 <= X <= 70 */   
#define    GPIOV18(X)    (X)        /* 1.8V i/o; 0 <= X <= 53 */   
#define    GPIOV33(X)    ((X)+54)    /* 3.3V i/o; 0 <= X <= 17 */   
  
/*   
寄存器都是32位到,每位對應一個gpio。  
*/   
struct gpio_controller {   
    u32    dir;            // gpio方向設置寄存器   
  
    u32    out_data;        // gpio設置爲輸出時,表示輸出狀態(0或1)   
  
    u32    set_data;        // gpio設置爲輸出時,用於輸出高電平   
  
    u32    clr_data;        // gpio設置爲輸出時,用於輸出低電平   
  
    u32    in_data;        // gpio設置爲輸入時,用於讀取輸入值   
  
    u32    set_rising;        // gpio中斷上升沿觸發設置   
  
    u32    clr_rising;        // gpio中斷上升沿觸發清除   
  
    u32    set_falling;    // gpio中斷下降沿觸發設置   
  
    u32    clr_falling;    // gpio中斷下降沿觸發清除   
  
    u32    intstat;        // gpio中斷狀態位,由硬件設置,可讀取,寫1時清除。   
  
};   
  
/* The __gpio_to_controller() and __gpio_mask() functions inline to constants  
* with constant parameters; or in outlined code they execute at runtime.  
*  
* You'd access the controller directly when reading or writing more than  
* one gpio value at a time, and to support wired logic where the value  
* being driven by the cpu need not match the value read back.  
*  
* These are NOT part of the cross-platform GPIO interface  
*/   
static inline struct gpio_controller *__iomem   
__gpio_to_controller(unsigned gpio)   
{   
    void *__iomem ptr;   
  
    if (gpio >= DAVINCI_N_GPIO)   
        return NULL;   
  
    if (gpio < 32)   
        ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);   
    else if (gpio < 64)   
        ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);   
    else if (gpio < 96)   
        ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);   
    else   
        ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x88);   
  
    return ptr;   
}   
  
static inline u32 __gpio_mask(unsigned gpio)   
{   
    return 1 << (gpio % 32);   
}   
  
/* The get/set/clear functions will inline when called with constant  
* parameters, for low-overhead bitbanging. Illegal constant parameters  
* cause link-time errors.  
*  
* Otherwise, calls with variable parameters use outlined functions.  
*/   
extern int __error_inval_gpio(void);   
  
extern void __gpio_set(unsigned gpio, int value);   
extern int __gpio_get(unsigned gpio);   
  
/* Returns zero or nonzero; works for gpios configured as inputs OR  
* as outputs.  
*  
* NOTE: changes in reported values are synchronized to the GPIO clock.  
* This is most easily seen after calling gpio_set_value() and then immediatly  
* gpio_get_value(), where the gpio_get_value() would return the old value  
* until the GPIO clock ticks and the new value gets latched.  
*/   
extern int gpio_get_value(unsigned gpio);   
extern void gpio_set_value(unsigned gpio, int value);   
  
  
/* powerup default direction is IN */   
extern int gpio_direction_input(unsigned gpio);   
extern int gpio_direction_output(unsigned gpio, int value);   
  
#include <asm-generic/gpio.h>    /* cansleep wrappers */   
  
extern int gpio_request(unsigned gpio, const char *tag);   
extern void gpio_free(unsigned gpio);   
  
static inline int gpio_to_irq(unsigned gpio)   
{   
    return DAVINCI_N_AINTC_IRQ + gpio;   
}   
  
static inline int irq_to_gpio(unsigned irq)   
{   
    return irq - DAVINCI_N_AINTC_IRQ;   
}   
  
#endif                /* __DAVINCI_GPIO_H */  
原文地址:http://blog.csdn.net/heanyu/article/details/6709571

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章