日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gpio_request 原形代码

發布時間:2023/12/10 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gpio_request 原形代码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

[cpp] view plaincopyprint?
  • 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;???
  • }??
  • 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 plaincopyprint?
  • /*??
  • *?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?*/ ??
  • ???
  • /* * 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 */

    總結

    以上是生活随笔為你收集整理的gpio_request 原形代码的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。