I.MX53的gpio.c分析

对于imx53中的gpio操作一直概念不清楚,最近火大,直接把gpio.c注释一下,该代码位于arch\arm\plat-mxc\gpio.c中

对于gpio的读写操作网上有一篇关于imx51的介绍已经很不错了,这里我的重点是gpio的中断,尤其是中断共享

一、mx53/mx51 GPIO 操作原理
(一)GPIO 寄存器
每组GPIO有8个寄存器:
1. DR: Data Register
当GDIR设置为输出时, 写DR的内容用来驱动GPIO的pins,读DR的内容则返
回存储在DR中的值
当GDIR设置为输入时,读DR返回给定IO pin的状态(PSR data),而不是DR
data
2. GDIR: Data Direction Register
控制GPIO pins的方向, 1作为输出,0作为输入,寄存器中的每一位标识一
个特定pad的方向。 仅当相应的pins被设置为GPIO,GDIR才起作用
3. PSR:Pad Sample Register
32-bit的只读寄存器。寄存器中的每一位都存储相应pad的值
4. ICR1, ICR2: 中断触发方式控制寄存器   用于设置中断触发方式
两个32-bit寄存器, 寄存器中每两位控制一条中断线,ICR1控制中断0~15,
ICR2控制中断16~31
00中断是low-level触发
01中断是high-level触发
10中断是rise-edge触发
11中断时fall-edge触发
5. IMR: Interrupt Mask Register   中断使能寄存器 用于控制中断的使能,总共有32位,对应32个中断
32bit register. 每一位是相应中断线的屏蔽位, 0中断被屏蔽,1中断被使

6. ISR: Interrupt Status Register 中断状态寄存器,用于查询对应的32个引脚的哪一位触发的中断,默认没有中断触发时是1,当触发的时候为0
32bit register, 每一位用于指定对应的中断线是否有中断发生,当一个中断
发生,这个寄存器中的相应位被设置
7. EDGE_SEL:Edge Select Register  设置为边缘触发的寄存器,感觉和icr重了,没有必要用了,有点多余,个人观点哈,呵呵
32bit 寄存器,覆盖ICR寄存器的配置,选择edge 作为中断触发的条件

/*

 * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de

 */


#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/sysdev.h>
#include <mach/hardware.h>
#include <asm-generic/bug.h>


static struct mxc_gpio_port *mxc_gpio_ports;
static int gpio_table_size;


#define cpu_is_mx1_mx2() (cpu_is_mx1() || cpu_is_mx2())


#define GPIO_DR (cpu_is_mx1_mx2() ? 0x1c : 0x00)
#define GPIO_GDIR (cpu_is_mx1_mx2() ? 0x00 : 0x04)
#define GPIO_PSR (cpu_is_mx1_mx2() ? 0x24 : 0x08)
#define GPIO_ICR1 (cpu_is_mx1_mx2() ? 0x28 : 0x0C)
#define GPIO_ICR2 (cpu_is_mx1_mx2() ? 0x2C : 0x10)
#define GPIO_IMR (cpu_is_mx1_mx2() ? 0x30 : 0x14)
#define GPIO_ISR (cpu_is_mx1_mx2() ? 0x34 : 0x18)


#define GPIO_INT_LOW_LEV (cpu_is_mx1_mx2() ? 0x3 : 0x0)
#define GPIO_INT_HIGH_LEV (cpu_is_mx1_mx2() ? 0x2 : 0x1)
#define GPIO_INT_RISE_EDGE (cpu_is_mx1_mx2() ? 0x0 : 0x2)
#define GPIO_INT_FALL_EDGE (cpu_is_mx1_mx2() ? 0x1 : 0x3)
#define GPIO_INT_NONE 0x4


/* Note: This driver assumes 32 GPIOs are handled in one register */
//清除gpio口的中断状态寄存器;
static void _clear_gpio_irqstatus(struct mxc_gpio_port *port, u32 index)//清除gpio口的状态
{
__raw_writel(1 << index, port->base + GPIO_ISR);//将相应的位清除,为1是说明没有触发
}
//设置gpio口相应的口的中断使能,index为第port组gpio口的第几个口
static void _set_gpio_irqenable(struct mxc_gpio_port *port, u32 index,
int enable)
{
u32 l;


l = __raw_readl(port->base + GPIO_IMR);//获取当前中断控制寄存器状态
l = (l & (~(1 << index))) | (!!enable << index);//将相应gpio口的imr置位。1使能, (!!enable << index)这句不知道什么意思
__raw_writel(l, port->base + GPIO_IMR);//写入相应的状态到imr
}
//清除中断号对应的状态以接收下一个中断,从而达到响应中断的目的
static void gpio_ack_irq(u32 irq)
{
u32 gpio = irq_to_gpio(irq);//获取当前gpio口的基地址
_clear_gpio_irqstatus(&mxc_gpio_ports[gpio / 32], gpio & 0x1f);//与0x1f与,为了取32位
}
//屏蔽中断号对应的中断
static void gpio_mask_irq(u32 irq)
{
u32 gpio = irq_to_gpio(irq);
_set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 0);
}
//开启中断号对应的中断
static void gpio_unmask_irq(u32 irq)
{
u32 gpio = irq_to_gpio(irq);
_set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1);
}


static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset);
//设置中断响应类型
static int gpio_set_irq_type(u32 irq, u32 type)
{
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值