來源:ARM9, Linux-2.6.10 BSP之gpio.c淺析

 

針對該gpio.c的硬體手冊是SPRUE25.pdf,可到TI的網站(www.ti.com)上下載,或直接在谷歌裡搜索。
以下是兩個文件gpio.c和gpio.h的淺析。

gpio.c

/*
 * TI DaVinci GPIO Support
 *
 * Copyright (c) 2006 David Brownell
 * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com>
 *
 * 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(- 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 (= 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. <source@mvista.com>
 *
 * 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 */

huenlil 發表在 痞客邦 PIXNET 留言(2) 人氣()


留言列表 (2)

發表留言
  • isly
  • Application直接呼叫kernel的function

    您好~~~
    我目前在porting Android,現在遇到一個問題
    我在kernel這一層利用一些gpio的函式寫出一些控制chip的function,例如我使用gpio_request、gpio_set_value、gpio_direction_output寫出一個function叫做chip_deinit來控制我的晶片的某一根pin腳,但是,我卻需要在我的application這一層直接呼叫chip_deinit()這個我寫出來的function,請問要怎麼直接呼叫?又或者要怎麼間接去呼叫到這個function?
  • huenlil
  • kernel driver 可實作一個 file operation 的介面,讓AP 可透過JNI 實作一個介面去 ioctl 即可。
    如果Android原本就有規劃的功能,則是利用HAL去連接。