技术专栏
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个
手气红包

相关专栏
-
浏览量:556次2020-03-26 15:59:03
-
2020-03-26 16:00:14
-
2018-06-18 22:47:22
-
浏览量:570次2020-08-06 20:14:59
-
浏览量:662次2020-03-18 10:41:44
-
浏览量:1290次2018-12-25 20:34:34
-
浏览量:287次2020-03-25 19:37:35
-
浏览量:1154次2018-02-06 10:43:46
-
浏览量:462次2020-03-18 14:32:08
-
浏览量:479次2020-07-29 10:00:03
-
2020-07-29 18:32:39
-
浏览量:1532次2017-11-22 19:41:21
-
浏览量:628次2020-08-04 15:11:02
-
浏览量:523次2019-12-05 17:50:07
-
浏览量:534次2020-07-27 15:26:51
-
浏览量:403次2020-07-24 10:45:35
-
2019-04-10 21:45:38
-
浏览量:840次2020-03-11 13:56:02
-
浏览量:522次2020-07-10 16:39:36
置顶时间设置
结束时间
删除原因
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
打赏作者

GoodMan
您的支持将鼓励我继续创作!
打赏金额:
¥1

¥5

¥10

¥50

¥100

¥0.1

支付方式:

举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
审核成功
发布时间设置
发布时间:
请选择发布时间设置
是否关联周任务-专栏模块
审核失败
失败原因
请选择失败原因
备注
请输入备注