Hi3531 GPIO驱动中断示例

goodman 2017-11-15 11:09:58 5017

对于海思的GPIO分组深恶痛绝,而且根据我的实际测试GPIO_RIS寄存器说明还写反了。测试代码用的是边沿触发,电平触发测试了始终有问题,在保持某电平(高或低)中断会一直触发很头疼清除了中断寄存器GPIO_IC也不行!!!!

约定GPIO号,对其分组形式做了一层处理以下是公式:
*gpio = base8+offset*
base:组号 ,offset:偏移
例如:GPIO15_2得到的GPIO号就是15
8+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&#95;LEVEL_HIGH | IRQ_TYPE&#95;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&#95;EDGE&#95;FALLING)) {
        value |= (1<<offset);
        PRINTK("trigger both\n");
    }
    else {
        value &= ~(1<<offset);
        val = readl(GPIO_IEV);
        if( trigger & (IRQ_TYPE&#95;LEVEL_LOW  | IRQ_TYPE&#95;EDGE&#95;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&#95;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&#95;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&#95;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&#95;EDGE&#95;FALLING|IRQF_TRIGGER_RISING);  //设置为单边沿的下降沿出发
        regs_set_gpio_irq_type(GPIO_15_3, IRQ_TYPE&#95;EDGE&#95;FALLING|IRQF_TRIGGER_RISING); //设置为单边沿的下降沿出发
        regs_enable&#95;gpio_irq(GPIO_15_2);      //使能GPIO中断
        regs_enable&#95;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&#95;irq(void)
{
        regs_disable&#95;gpio_irq(GPIO_15_2);
        regs_disable&#95;gpio_irq(GPIO_15_3);
        free&#95;irq(GPIO_IRQ, NULL);
}

static int __init gpio_init(void)
{
    int err;

    if(this_enable&#95;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&#95;irq();
    misc_deregister(dev.misc_dev);  
}

module&#95;init(gpio_init);
module&#95;exit(gpio_exit);

MODULE&#95;AUTHOR("GoodMan<2757364047@qq.com>");
MODULE&#95;LICENSE("Dual BSD/GPL");
MODULE&#95;VERSION("V1.00");
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
goodman
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
关于作者
goodman

goodman

wooshang@126.com

原创18
阅读8.9w
收藏6
点赞23
评论12
打赏用户 0
我要创作
分享技术经验,可获取创作收益
分类专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
goodman
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区