技术专栏
Hi3531 GPIO驱动中断示例
对于海思的GPIO分组深恶痛绝,而且根据我的实际测试GPIO_RIS寄存器说明还写反了。测试代码用的是边沿触发,电平触发测试了始终有问题,在保持某电平(高或低)中断会一直触发很头疼清除了中断寄存器GPIO_IC也不行!!!!
约定GPIO号,对其分组形式做了一层处理以下是公式:
*gpio = base8+offset*
base:组号 ,offset:偏移
例如:GPIO15_2得到的GPIO号就是158+2=122
测试代码如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqreturn.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#define DEBUG
#ifdef DEBUG
# define PRINTK(fmt, arg...) printk(fmt, ##arg)
#else
# define PRINTK(fmt, arg...) do {} while(0)
#endif
#define GPIO_15_BASE 0x20240000 //for GPIO15
#define GPIO_DATA(o) IO_ADDRESS(GPIO_15_BASE + (1<<(o+2)))
#define GPIO_DIR IO_ADDRESS(GPIO_15_BASE + 0x400)
#define GPIO_IS IO_ADDRESS(GPIO_15_BASE + 0x404)
#define GPIO_IBE IO_ADDRESS(GPIO_15_BASE + 0x408)
#define GPIO_IEV IO_ADDRESS(GPIO_15_BASE + 0x40C)
#define GPIO_IE IO_ADDRESS(GPIO_15_BASE + 0x410)
#define GPIO_RIS IO_ADDRESS(GPIO_15_BASE + 0x414)
#define GPIO_MIS IO_ADDRESS(GPIO_15_BASE + 0x418)
#define GPIO_IC IO_ADDRESS(GPIO_15_BASE + 0x41C)
#define GPIO_AFSEL IO_ADDRESS(GPIO_15_BASE + 0x420)
#define GPIO_15_2 122
#define GPIO_15_3 123
#define GPIO_IRQ 116
struct gpc_dev {
spinlock_t lock;
struct miscdevice *misc_dev;
};
struct miscdevice this_misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = "higpio",
.nodename = "higpio"
};
struct gpc_dev dev =
{
.misc_dev = &this_misc,
};
static int gpio_offset(int gpio, int *offset)
{
if(offset)
*offset = gpio%8;
return 0;
}
static int get_value(int gpio)
{
int offset;
if(gpio_offset(gpio, &offset) !=0)
return -1;
return readl(GPIO_DATA(offset)) & (1<<offset)? 1 : 0;
}
static int gpio_input(int gpio)
{
u32 value;
int offset;
if(gpio_offset(gpio, &offset) !=0)
return -1;
spin_lock(&dev.lock);
value = readl(GPIO_DIR);
value &= ~(1<<offset);
writel(value, GPIO_DIR);
spin_unlock(&dev.lock);
return 0;
}
static int regs_set_gpio_irq_type(int gpio, unsigned int trigger)
{
u32 value, val;
unsigned long flags;
int offset;
if(gpio_offset(gpio, &offset) !=0 )
return -1;
spin_lock_irqsave(&dev.lock,flags);
value = readl(GPIO_IS);
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
value |= (1<<offset);
PRINTK("trigger is level\n");
}
else {
value &= ~(1<<offset);
PRINTK("trigger is edge\n");
}
writel(value, GPIO_IS);
value = readl(GPIO_IBE);
if ((trigger & IRQF_TRIGGER_RISING) && (trigger & IRQ_TYPE_EDGE_FALLING)) {
value |= (1<<offset);
PRINTK("trigger both\n");
}
else {
value &= ~(1<<offset);
val = readl(GPIO_IEV);
if( trigger & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
val &= ~(1<<offset);
else
val |= (1<<offset);
writel(val, GPIO_IEV);
}
writel(value, GPIO_IBE);
spin_unlock_irqrestore(&dev.lock, flags);
return 0;
}
static int regs_enable_gpio_irq(int gpio)
{
u32 value;
unsigned long flags;
int offset;
if(gpio_offset(gpio, &offset) !=0 )
return-1;
spin_lock_irqsave(&dev.lock,flags);
writel(0xff, GPIO_IC);
value = readl(GPIO_IE);
value |= (1<<offset);
writel(value, GPIO_IE);
spin_unlock_irqrestore(&dev.lock, flags);
return 0;
}
static void regs_clean_gpio_irq(int gpio)
{
int offset;
u32 value;
if(gpio_offset(gpio, &offset) !=0 )
return ;
value = readl(GPIO_IC);
value |=(1<<offset);
writel(value, GPIO_IC);
}
static void regs_disable_gpio_irq(int gpio)
{
u32 value;
unsigned long flags;
int offset;
if(gpio_offset(gpio, &offset) !=0 )
return;
spin_lock_irqsave(&dev.lock,flags);
value = readl(GPIO_IE);
value &= ~(1<<offset);
writel(value, GPIO_IE);
spin_unlock_irqrestore(&dev.lock, flags);
}
static irqreturn_t this_irq_handler(int irq, void* dev_id)
{
u32 value;
int i, gpio=120;
value = readl(GPIO_RIS);
PRINTK(KERN_NOTICE "gpio:irq=%d, value=%xn",irq, value);
for(i=0; i<8; i++) {
if(value & 0x1){
gpio += i;
break;
}
else {
value=value>>1;
}
}
PRINTK(KERN_NOTICE "gpio:gpio=%d\n",gpio);
regs_clean_gpio_irq(gpio);
return IRQ_HANDLED;
}
static int this_enable_irq(void)
{
int err = 0;
gpio_input(GPIO_15_2); //设置GPIO_15_2为输入
gpio_input(GPIO_15_3);
regs_set_gpio_irq_type(GPIO_15_2, IRQ_TYPE_EDGE_FALLING|IRQF_TRIGGER_RISING); //设置为单边沿的下降沿出发
regs_set_gpio_irq_type(GPIO_15_3, IRQ_TYPE_EDGE_FALLING|IRQF_TRIGGER_RISING); //设置为单边沿的下降沿出发
regs_enable_gpio_irq(GPIO_15_2); //使能GPIO中断
regs_enable_gpio_irq(GPIO_15_3); //使能GPIO中断
err = request_irq(GPIO_IRQ, this_irq_handler, 0, "higpio", NULL);
if (err != 0) {
PRINTK(KERN_ERR "gpc: failed to request irq, err: %d\n", err);
err = -EBUSY;
}
return err;
}
static void this_disable_irq(void)
{
regs_disable_gpio_irq(GPIO_15_2);
regs_disable_gpio_irq(GPIO_15_3);
free_irq(GPIO_IRQ, NULL);
}
static int __init gpio_init(void)
{
int err;
if(this_enable_irq() !=0)
return -EBUSY;
spin_lock_init(&dev.lock);
err = misc_register(dev.misc_dev);
return err;
}
static void __exit gpio_exit(void)
{
this_disable_irq();
misc_deregister(dev.misc_dev);
}
module_init(gpio_init);
module_exit(gpio_exit);
MODULE_AUTHOR("GoodMan<2757364047@qq.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("V1.00");
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包
点赞
收藏
评论
打赏
- 分享
- 举报
评论
0个
手气红包
暂无数据
相关专栏
-
浏览量:3326次2020-03-26 15:59:03
-
浏览量:826次2023-06-21 10:50:13
-
2020-03-26 16:00:14
-
2018-06-18 22:47:22
-
浏览量:6054次2020-03-18 10:41:44
-
浏览量:2491次2020-08-30 09:43:41
-
浏览量:2936次2020-09-04 14:07:48
-
浏览量:8437次2020-09-05 15:06:28
-
浏览量:4725次2020-08-30 09:01:15
-
浏览量:1994次2020-03-25 19:37:35
-
浏览量:6953次2020-03-18 14:32:08
-
浏览量:3103次2020-07-29 10:00:03
-
浏览量:3082次2017-11-22 19:41:21
-
浏览量:3761次2020-08-06 20:14:59
-
浏览量:448次2024-08-27 10:56:56
-
浏览量:3912次2020-08-31 08:41:19
-
浏览量:4320次2021-09-13 13:44:04
-
浏览量:4266次2018-12-25 20:34:34
-
浏览量:3392次2021-10-16 13:48:22
置顶时间设置
结束时间
删除原因
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
打赏作者
goodman
您的支持将鼓励我继续创作!
打赏金额:
¥1
¥5
¥10
¥50
¥100
支付方式:
微信支付
打赏成功!
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
审核成功
发布时间设置
发布时间:
请选择发布时间设置
是否关联周任务-专栏模块
审核失败
失败原因
请选择失败原因
备注
请输入备注