开发板裸机开发需要自己按照数据手册自己计算每个gpio的偏移,以实现相应功能,如上拉,第二功能等。
linux为开发者提供了一套统一的方法,方便开发。
想要使用gpio需要先申请,申请成功才能使用。这些头文件定义在内核文件的”include/linux/gpio.h”中。
//申请io 成功返回0 失败返回错误码
static inline int gpio_request(unsigned gpio, const char *label)
gpio:需要申请的gpio号,一般是gpio的宏定义
label:为申请的gpio取的名字,方便阅读
//释放gpio
static inline void gpio_free(unsigned gpio)
gpio:申请成功的gpio
//检测此gpio口是否有效
static inline bool gpio_is_valid(int number)
//设置为输入
int gpio_direction_input(unsigned gpio);
//设置为输出,并初始化值为value.
int gpio_direction_output(unsigned gpio, int value);
获取/设置gpio值: int gpio_cansleep(unsigned gpio);
a.不可睡眠:
//返回value
gpio_get_value(unsigned gpio);
//设置值
gpio_set_value(unsigned gpio, int value);
b.可睡眠:(对于有些挂载在I2C,SPI总线上的扩展GPIO,读写操作可能会导致睡眠,因此不能在中断函数中使用。使用下面的函数以区别于正常的GPIO)
//输入端口:返回零或非零,可能睡眠
int gpio_get_value_cansleep(unsigned gpio);
//输出端口:可能睡眠
void gpio_set_value_cansleep(unsigned gpio, int value);
批量初始化方法:
//申请:
err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
//释放:
gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
Gpio设置中断:
//首先应该设置此gpio为输入状态,然后获取对应的中断号(或错误码)。返回编号调用:request_irq()和free_irq()。
static inline int gpio_to_irq(unsigned gpio)
//返回gpio编号,再调用gpio_get_value()获取相应的值。(避免使用反向映射,不支持)
static inline int irq_to_gpio(unsigned irq)
GPIO 宏定义文件都是由原厂提供,一般位置在”arch/arm(cpu架构)/mach-exynos(cpu型号)/include/mach/gpio-exynos4.h(具体的文件)”
主要用宏定义了gpio的地址
如:
gpioA的地址为 0xE0031080
使用宏定义成了 GPA 以后直接使用GPA即可
主要是对gpio口的配置操作,如上拉,中断触发条件等。
位置定义在”arch/arm(cpu架构)/plat-samsung(平台)/include/plat/gpio-cfg.h”
//设置上拉、下拉
int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull);
//配置管脚是输入、输出、第二功能
int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
//配置为中断
int s5p_register_gpio_interrupt(int pin);
主要是外部中断的申请与释放
#include
//申请中断
static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
irq:中断号,与平台架构相关;可以通过gpio_to_irq映射
handler:用户中断处理函数;
flags:一个或多个中断标记
IRQF_DISABLED, 用于保证中断不被打断和嵌套
IRQF_SHARED, 申请子中断时,共享中断源
IRQF_SAMPLE_RANDOM, 表示对系统熵有贡献,对系统获取随
机数有好处
devname:中断名字,可以通过 cat /proc/interrupts 查看;
dev_id:在 free_irq 中有用,也用做区分中断处理函数
//中断处理函数
irqreturn_t (*handler)(int, void *, struct pt_regs *)
//设置中断触发方式(外部中断)
int set_irq_type(int irq, int edge);
irq:中断号
edge:外部中断触发方式定义在linux/irq.h
IRQ_TYPE_LEVEL_LOW,
IRQ_TYPE_LEVEL_HIGH,
IRQ_TYPE_EDGE_FALLING,
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_EDGE_BOTH
//释放中断
void free_irq(unsigned int irq, void *dev_id)
irq:中断号,与 request_irq 中的 irq 一致,用于定位 action 链表;
dev_id:用于在 action 链表中找到要卸载的表项;同一个中断的不同中断处理函数必须使用不同的dev_id来区分,这就要求在注册中断共享时参数 dev_id 必须唯一。
//使能中断
void enable_irq(unsigned int irq);
//关闭中断,并等待中断处理完成后返回
void disable_irq(unsigned int irq);
注意:当用户在中断处理函数中使用该函数会形成死锁
//关闭中断,立即返回
void disable_irq_nosync(unsigned int irq);
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEMO_DEBUG
#ifdef DEMO_DEBUG
#define dem_dbg(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
#else
#define dem_dbg(fmt, arg...) printk(KERN_DEBUG fmt, ##arg)
#endif
//中断回调
static irqreturn_t eint9_interrupt(int irq, void *dev_id) {
printk("%s(%d)\n", __FUNCTION__, __LINE__);
return IRQ_HANDLED;
}
static dev_t dev_id;
static unsigned int irq;
static int demo_open (struct inode *pnode, struct file *filp)
{
int ret;
dev_id = MKDEV(imajor(pnode), iminor(pnode));
//申请gpio
ret = gpio_request(EXYNOS4_GPX1(1), "EINT9");
if (ret) {
printk("request EINT9 failed, ret = %d", ret);
return ret;
}
//设置gpio为第二功能引脚 即中断
s3c_gpio_cfgpin(EXYNOS4_GPX1(1), S3C_GPIO_SFN(0xF));
//上拉
s3c_gpio_setpull(EXYNOS4_GPX1(1), S3C_GPIO_PULL_UP);
//释放gpio
gpio_free(EXYNOS4_GPX1(1));
//将GPX1_1映射为中断
irq = gpio_to_irq(EXYNOS4_GPX1(1));
//申请中断
ret = request_irq(irq, eint9_interrupt,
IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "eint9", (void *)&dev_id);
if (ret < 0) {
printk("Request IRQ %d failed, %d\n", IRQ_EINT(9), ret);
goto exit;
}
exit:
free_irq(IRQ_EINT(9), (void *)&dev_id);
return 0;
}
static ssize_t demo_read (struct file *filp, char __user *buf, size_t count, loff_t *offp)
{
return 0;
}
static int demo_release (struct inode *pnode, struct file *filp)
{
printk("==>demo_release\n");
free_irq(irq, (void *)&dev_id);
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = demo_open,
.read = demo_read,
.release = demo_release,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.fops = &fops,
.name = "demo0",
};
static int __init demo_init(void)
{
int res;
dem_dbg("==>demo_init\n");
res = misc_register(&misc);
if(res < 0){
dem_dbg("register misc device failed!\n");
return -EFAULT;
}
return 0;
}
static void __exit demo_exit(void)
{
dem_dbg("==>demo_exit\n");
misc_deregister(&misc);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("Dual BSD/GPL");