?? 其原型為 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 平臺:?
- /*??
- *?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(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.?<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?*/ ??
- ???