您的位置:首页 > 其它

GPIOLIB实现(一)

2016-07-21 11:59 375 查看
驱动开发中最基础的就是控制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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: