GPIOLIB实现(一)
来源:互联网 发布:什么软件马赛克好看 编辑:程序博客网 时间:2024/06/07 08:31
驱动开发中最基础的就是控制GPIO来驱动硬件,我们列举一下常用的API.
int gpio_is_valid(int number);int gpio_request()int gpio_direction_input(unsigned gpio);int gpio_direction_output(unsigned gpio, int value);int gpio_get_value(unsigned gpio);void gpio_set_value(unsigned gpio, int value);int gpio_get_value_cansleep(unsigned gpio);void gpio_set_value_cansleep(unsigned gpio, int value);void gpio_free(unsigned gpio);int gpio_to_irq(unsigned gpio);int irq_to_gpio(unsigned irq);
gpio相关的代码在driver/gpio/gpiolib.c下:
我们先看一下头文件中对于gpio结构的描述:
include/linux/gpio.h
struct gpio_desc { struct gpio_chip *chip; unsigned long flags;#ifdef CONFIG_DEBUG_FS const char *label;#endif};
我们挑一下比较核心的部分看一下
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; //简化的后的主要代码int gpio_direction_output(unsigned gpio, int value){ struct gpio_chip *chip; struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; chip = desc->chip; status = gpio_ensure_requested(desc, gpio); //没申请手动帮助申请为auto status = chip->direction_output(chip, gpio, value); return status;}
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
我们重点关注gpio_desc什么时候被填充
以及ARCH_NR_GPIOS哪里定义
chip->direction_output(chip, gpio, value);
我们看到调用chip中的函数,这个函数在哪里被赋值,问题等同于gpio_desc的问题
总结一下问题:
1.gpio_desc什么时候被填充
2. ARCH_NR_GPIOS哪里定义
问题1: 在代码中我们寻找到了gpio_desc什么时候被填充
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; } 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[id].chip = chip; 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; status = gpiochip_export(chip); if (status) goto fail; return 0;fail: pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); return status;}
这里我们搜遍代码也没发现这个函数被调用,那么肯定是其他地方调用了,我们在arch/arm的板文件中找到了答案。
kernel_imx/arch/arm/plat-mxc/gpio.c
int mxc_gpio_init(struct mxc_gpio_port *port, int cnt){ int i, j; static bool initialed; /* save for local usage */ mxc_gpio_ports = port; gpio_table_size = cnt; 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); irq_set_chip_and_handler(j, &gpio_irq_chip, handle_level_irq); set_irq_flags(j, IRQF_VALID); } /* register gpio chip */ port[i].chip.direction_input = mxc_gpio_direction_input; port[i].chip.direction_output = mxc_gpio_direction_output; 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) 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; return 0;}
顺便我们看看这里比较重要的结构体的格式:
其中的结构体我们研究一下头文件
kernel_imx/arch/arm/plat-mxc/include/mach/gpio.h
struct mxc_gpio_port {
void __iomem *base;
int irq;
int irq_high;
int virtual_irq_start;
struct gpio_chip chip;
u32 both_edges;
spinlock_t lock;
};
接着我们继续找哪里调用了?
kernel_imx/arch/arm/mach-mx6/devices.c
int mx6q_register_gpios(void){ /* 7 ports for Mx6 */ return mxc_gpio_init(mxc_gpio_ports, 7); } 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-1", .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-2", .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-3", .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-4", .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-5", .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-6", .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 }, };
kernel_imx/arch/arm/mach-mx6/irq.c
void mx6_init_irq(void){ void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR); struct irq_desc *desc; unsigned int i; /* start offset if private timer irq id, which is 29. * ID table: * Global timer, PPI -> ID27 * A legacy nFIQ, PPI -> ID28 * Private timer, PPI -> ID29 * Watchdog timers, PPI -> ID30 * A legacy nIRQ, PPI -> ID31 */ gic_init(0, 29, IO_ADDRESS(IC_DISTRIBUTOR_BASE_ADDR), IO_ADDRESS(IC_INTERFACES_BASE_ADDR)); if (enable_wait_mode) { /* Mask the always pending interrupts - HW bug. */ __raw_writel(0x00400000, gpc_base + 0x0c); __raw_writel(0x20000000, gpc_base + 0x10); } for (i = MXC_INT_START; i <= MXC_INT_END; i++) { desc = irq_to_desc(i); desc->irq_data.chip->irq_set_wake = mx6_gic_irq_set_wake; } /***********这里**************/ mx6q_register_gpios();#ifdef CONFIG_CPU_FREQ_GOV_INTERACTIVE for (i = 0; i < ARRAY_SIZE(mxc_irq_tuner); i++) cpufreq_gov_irq_tuner_register(mxc_irq_tuner[i]);#endif#ifdef CONFIG_PCI_MSI imx_msi_init();#endif}
最后:板文件中定义
/* * initialize __mach_desc_MX6Q_SABRESD data structure. */MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board") /* Maintainer: Freescale Semiconductor, Inc. */ .boot_params = MX6_PHYS_OFFSET + 0x100, .fixup = fixup_mxc_board, .map_io = mx6_map_io, .init_irq = mx6_init_irq, .init_machine = mx6_sabresd_board_init, .timer = &mx6_sabresd_timer, .reserve = mx6q_sabresd_reserve,MACHINE_END
在kernel启动时候
kernel_imx/init/main.c —>arch/arm/kernel/setup.c
start_kernel() —> setup_arch(&command_line)
后面会获取宏中定义的结构相关的内容,在合适的时候去调用。
问题2:
ARCH_NR_GPIOS在哪里定义?
在板级头文件中没有发现定义,默认的定义在:
kernel_imx/include/asm-generic/gpio.h 下
另外static inline bool gpio_is_valid(int number)的实现也在。
#ifndef ARCH_NR_GPIOS
# define ARCH_NR_GPIOS 256
#endif
看来是8*32=256板文件也就没有定义这个值了,其他平台的板文件都能搜索到定义
头文件包含关系
linux/gpio.h ===>
asm/gpio.h===>kernel_imx/arch/arm/include/asm/gpio.h
mach/gpio.h—>
plat-mxc/include/mach/gpio.h —->asm-generic/gpio.h
- GPIOLIB实现(一)
- Linux 4.x 之Gpio分析(一)Gpiolib库1
- Linux GPIO 驱动(基于GPIOLIB)
- linux驱动(七)gpiolib库详解
- gpiolib文档
- gpiolib文档
- linux内核gpiolib文档
- gpiolib管理gpio过程
- linux内核gpiolib文档
- Linux内核gpiolib文档
- Linux中GPIOlib使用方法
- Linux中GPIOlib使用方法
- gpiolib管理gpio过程
- gpiolib管理gpio过程
- linux内核gpiolib文档
- gpiolib管理gpio过程
- gpiolib及gpio操作
- linux内核gpiolib
- 【学习】对于AndroidStudio 中 Local History还原文件的理解
- (Plugin with id com.android.application not found)问题解决
- Android各种动画效果ScaleAnimation,AlphaAnimation,TranslateAnimation,RotateAnimation(文章结尾有代码)
- Eclipse去除js(JavaScript)验证错误
- OpenResty学习笔记(十一) nginx做负载均衡
- GPIOLIB实现(一)
- __declspec(dllexport)、__declspec(dllimport)详解
- 移动页面HTML5自适应手机屏幕宽度
- 基于HTML5+WebSocket+JAVA的棋牌游戏开发,从入门到放弃(二)
- 百练 02 滑雪
- 大话设计模式06----装饰模式
- php_lang_ref:classes and objects >> object interface
- jQuery.Callbacks之demo
- Android使用FAAC进行AAC编码详解必看以及注意事项