多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > Linux GPIO 的注冊與申請

Linux GPIO 的注冊與申請

來源:程序員人生   發布時間:2014-11-11 09:14:37 閱讀次數:3004次

Linux GPIO 的注冊與申請

Linux Kernel, GPIO, ARM

在Linux kernel代碼中,常常會使用 GPIO 來作為1個特殊的信號,如作為芯片的片選信號等。
GPIO 申請的函數,我們常常用到,如 gpio_request ,那末 GPIO 是什么時候,和如何注冊的,本文就來探索1下。
基于的平臺上 freesccale 的 i.MX6

先從函數 gpio_request 的實現開始。

/* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. */ 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; // 這兒從 gpio_desc 數組中取了1個 gpio_desc 結構體 // 后面的代碼基本上都是基于這個結構體進行的操作 // 我們是從數組中取了1個 gpio 的描寫,這個描寫應當是在 gpio 注冊的時候添加到這個數組的 // 以這個數組為線索,看看 gpio 是如何注冊的 desc = &gpio_desc[gpio]; chip = desc->chip; 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) { 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 ", gpio, label ? : "?", status); spin_unlock_irqrestore(&gpio_lock, flags); return status; }


以數組 gpio_desc 為線索。
既然我們申請 GPIO 的時候是從這個數字中取數據,那末注冊 GPIO 的時候就應當往這個數字中添加數據了。
反過來,往這個數組添加數據的地方應當也就是注冊 GPIO 的地方了。
這個數組定義在 Gpiolib.c 文件中:

static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];


搜索發現, gpiochip_add 函數中有給數組 gpio_desc 賦值。
 
看看誰調用了函數 gpiochip_add 。
平臺相干目錄下的 Gpio.c 文件中的 mxc_gpio_init 函數調用了 gpiochip_add :

if (!initialed) /* its a serious configuration bug when it fails */ BUG_ON(gpiochip_add(&port[i].chip) < 0);


繼續往上找,平臺相干目錄下的 Devices.c 有以下函數:

int mx6q_register_gpios(void) { /* 7 ports for Mx6 */ return mxc_gpio_init(mxc_gpio_ports, 7); }


mxc_gpio_ports 的定義:

static struct mxc_gpio_port mxc_gpio_ports[] = { { .chip.label = "gpio-0", .base = IO_ADDRESS(GPIO1_BASE_ADDR), .irq = MXC_INT_GPIO1_INT15_0_NUM, .irq_high = MXC_INT_GPIO1_INT31_16_NUM, .virtual_irq_start = MXC_GPIO_IRQ_START }, { .chip.label = "gpio⑴", .base = IO_ADDRESS(GPIO2_BASE_ADDR), .irq = MXC_INT_GPIO2_INT15_0_NUM, .irq_high = MXC_INT_GPIO2_INT31_16_NUM, .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 1 }, { .chip.label = "gpio⑵", .base = IO_ADDRESS(GPIO3_BASE_ADDR), .irq = MXC_INT_GPIO3_INT15_0_NUM, .irq_high = MXC_INT_GPIO3_INT31_16_NUM, .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2 }, { .chip.label = "gpio⑶", .base = IO_ADDRESS(GPIO4_BASE_ADDR), .irq = MXC_INT_GPIO4_INT15_0_NUM, .irq_high = MXC_INT_GPIO4_INT31_16_NUM, .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 3 }, { .chip.label = "gpio⑷", .base = IO_ADDRESS(GPIO5_BASE_ADDR), .irq = MXC_INT_GPIO5_INT15_0_NUM, .irq_high = MXC_INT_GPIO5_INT31_16_NUM, .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 4 }, { .chip.label = "gpio⑸", .base = IO_ADDRESS(GPIO6_BASE_ADDR), .irq = MXC_INT_GPIO6_INT15_0_NUM, .irq_high = MXC_INT_GPIO6_INT31_16_NUM, .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 5 }, { .chip.label = "gpio⑹", .base = IO_ADDRESS(GPIO7_BASE_ADDR), .irq = MXC_INT_GPIO7_INT15_0_NUM, .irq_high = MXC_INT_GPIO7_INT31_16_NUM, .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 6 }, };


繼續往上,找到了同目錄下 Irq.c 文件中的 mx6_init_irq 函數調用了 mx6q_register_gpios 。
board.c 文件中將 mx6_init_irq 函數賦值給了 machine_desc 結構體的 init_irq 函數:

MACHINE_START(MX6XXXX, "Freescale i.MX 6 Board") .boot_params = MX6_PHYS_OFFSET + 0x100, .fixup = fixup_mxc_board, .map_io = mx6_map_io, .init_irq = mx6_init_irq, .init_machine = mx6_board_init, .timer = &mxc_timer, .reserve = mx6q_reserve, MACHINE_END


arch/arm/kernel/irq.c 文件中有以下函數:

void __init init_IRQ(void) { machine_desc->init_irq(); }


 

init/main.c 文件中的 start_kernel 函數調用了 init_IRQ 。

至于 start_kernel 函數什么時候被調用,有時間再作研究。

總結1下 GPIO 的注冊進程:
start_kernel 函數會調用 init_IRQ 函數。
init_IRQ 函數調用了 machine_desc 結構體的 init_irq 函數。
machine_desc 結構體在 board.c 文件中定義,其中 init_irq 被賦值為 mx6_init_irq 。
mx6_init_irq 函數中調用了 mx6q_register_gpios 函數。
mx6q_register_gpios 函數的定義見前文,其中調用了函數 mxc_gpio_init 。

函數 mxc_gpio_init 的實現:

int mxc_gpio_init(struct mxc_gpio_port *port, int cnt) { int i, j; static bool initialed; /* save for local usage */ // port 是前面定義的數組 mxc_gpio_ports , cnt 是數組中元素的個數 mxc_gpio_ports = port; gpio_table_size = cnt; printk(KERN_INFO "MXC GPIO hardware "); for (i = 0; i < cnt; i++) { /* disable the interrupt and clear the status */ __raw_writel(0, port[i].base + GPIO_IMR); __raw_writel(~0, port[i].base + GPIO_ISR); for (j = port[i].virtual_irq_start; j < port[i].virtual_irq_start + 32; j++) { irq_set_lockdep_class(j, &gpio_lock_class); /* static struct irq_chip gpio_irq_chip = { .name = "GPIO", .irq_ack = gpio_ack_irq, .irq_mask = gpio_mask_irq, .irq_unmask = gpio_unmask_irq, .irq_set_type = gpio_set_irq_type, .irq_set_wake = gpio_set_wake_irq, }; */ /** * handle_level_irq - Level type irq handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq * * Level type interrupts are active as long as the hardware line has * the active level. This may require to mask the interrupt and unmask * it after the associated handler has acknowledged the device, so the * interrupt line is back to inactive. */ irq_set_chip_and_handler(j, &gpio_irq_chip, handle_level_irq); set_irq_flags(j, IRQF_VALID); } /* register gpio chip */ // mxc_gpio_direction_input 將對應 gpio 設置為輸入, mxc_gpio_direction_output 將對應 gpio 設置為輸出,并會設置1個初始值 // 這兒的輸入/輸出是對 cpu 來講的 port[i].chip.direction_input = mxc_gpio_direction_input; port[i].chip.direction_output = mxc_gpio_direction_output; // 獲得/設置 gpio 狀態 port[i].chip.get = mxc_gpio_get; port[i].chip.set = mxc_gpio_set; port[i].chip.base = i * 32; port[i].chip.ngpio = 32; spin_lock_init(&port[i].lock); if (!initialed) /* its a serious configuration bug when it fails */ // 添加 gpio chip , 調用的是我們前面用到的1個線索函數, 該函數中有給 gpio_desc 數組賦值 BUG_ON(gpiochip_add(&port[i].chip) < 0); if (cpu_is_mx1() || cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx51() || cpu_is_mx53() || cpu_is_mx6q() || cpu_is_mx6dl() || cpu_is_mx6sl()) { /* setup one handler for each entry */ irq_set_chained_handler(port[i].irq, mx3_gpio_irq_handler); irq_set_handler_data(port[i].irq, &port[i]); if (port[i].irq_high) { /* setup handler for GPIO 16 to 31 */ irq_set_chained_handler(port[i].irq_high, mx3_gpio_irq_handler); irq_set_handler_data(port[i].irq_high, &port[i]); } } } initialed = true; if (cpu_is_mx2()) { /* setup one handler for all GPIO interrupts */ irq_set_chained_handler(port[0].irq, mx2_gpio_irq_handler); irq_set_handler_data(port[0].irq, port); } return 0; }


gpiochip_add 函數的實現:

/** * gpiochip_add() - register a gpio_chip * @chip: the chip to register, with chip->base initialized * Context: potentially before irqs or kmalloc will work * * Returns a negative errno if the chip can't be registered, such as * because the chip->base is invalid or already associated with a * different chip. Otherwise it returns zero as a success code. * * When gpiochip_add() is called very early during boot, so that GPIOs * can be freely used, the chip->dev device must be registered before * the gpio framework's arch_initcall(). Otherwise sysfs initialization * for GPIOs will fail rudely. * * If chip->base is negative, this requests dynamic assignment of * a range of valid GPIOs. */ int gpiochip_add(struct gpio_chip *chip) { unsigned long flags; int status = 0; unsigned id; int base = chip->base; if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1)) && base >= 0) { status = -EINVAL; goto fail; } spin_lock_irqsave(&gpio_lock, flags); if (base < 0) { base = gpiochip_find_base(chip->ngpio); if (base < 0) { status = base; goto unlock; } chip->base = base; } /* these GPIO numbers must not be managed by another gpio_chip */ for (id = base; id < base + chip->ngpio; id++) { if (gpio_desc[id].chip != NULL) { status = -EBUSY; break; } } if (status == 0) { for (id = base; id < base + chip->ngpio; id++) { // 發現這兒只是賦值了 gpio_desc 成員的 chip 成員 gpio_desc[id].chip = chip; /* REVISIT: most hardware initializes GPIOs as * inputs (often with pullups enabled) so power * usage is minimized. Linux code should set the * gpio direction first thing; but until it does, * we may expose the wrong direction in sysfs. */ gpio_desc[id].flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; } } of_gpiochip_add(chip); unlock: spin_unlock_irqrestore(&gpio_lock, flags); if (status) goto fail; // 創建裝備, 并添加對應的 sysfs status = gpiochip_export(chip); if (status) goto fail; return 0; fail: /* failures here can mean systems won't boot... */ pr_err("gpiochip_add: gpios %d..%d (%s) failed to register ", chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); return status; }


gpio_desc 結構體的定義:

struct gpio_desc { struct gpio_chip *chip; unsigned long flags; /* flag symbols are bit numbers */ #define FLAG_REQUESTED 0 #define FLAG_IS_OUT 1 #define FLAG_RESERVED 2 #define FLAG_EXPORT 3 /* protected by sysfs_lock */ #define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ #define FLAG_TRIG_FALL 5 /* trigger on falling edge */ #define FLAG_TRIG_RISE 6 /* trigger on rising edge */ #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ #define ID_SHIFT 16 /* add new flags before this one */ #define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1) #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE)) #ifdef CONFIG_DEBUG_FS const char *label; #endif };


 

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产三级手机在线 | 91色网站| 亚洲综合网址 | 国产成人精品日本亚洲专一区 | 五月天在线播放视频在线 | 亚洲精品资源 | 免费在线播放视频 | 日本free护士videosxxxx动漫 | 午夜影院免费在线观看 | www一区 | 韩国理论片在线观看bd | 中文字幕成人在线 | 免费乱码中文字幕网站 | 国产在线观看第一页 | 成人a一级毛片免费看 | 性―交―乱―色―情 | 免费成人视屏 | 91久久亚洲精品一区二区 | 国产亚洲欧美在线视频 | 好吊妞视频在线观看 | 青青青青在线成人视99 | 吃奶跟添下面特舒服 | 欧美成人aaaa免费高清 | 国产一区二区在线视频播放 | 亚洲国产精品影院 | 波多野结衣久久精品免费播放 | 日韩免费专区 | 免费网站在线看 | 免费午夜视频在线观看 | 成年人在线观看视频网站 | 亚洲综合一区二区不卡 | 中文有码 | 午夜视频网 | 亚洲看片| 欧美激情亚洲精品日韩1区2区 | 久久精品亚洲欧美va | 亚洲国产精品成 | 国内精品麻豆 | 国产成人一区二区三区视频免费 | 亚洲国产片高清在线观看 | 成人a毛片久久免费播放 |