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

1 0