打印
[i.MX]

关于request_irq函数的问题

[复制链接]
8127|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xlb7679|  楼主 | 2014-12-23 18:22 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
我相想自己实现e9的红外接收驱动,imx6在申请中断的时候  request_irq(int  irq_no,……)函数,问题一:这里的irq_no可不可以静态的分配?(就是比如我要用98号中断,直接给传98给irq_no,可是返回值ret一直是 -22 ,可是我看了cat /proc/interrupts,98号是未使用的),假如要用gpio_to_irq(unsigned gpio)函数来获取,问题二:参数怎么填?这个参数unsigned gpio也是在iomux-mx6q.h中找宏定义吗?真心求解答

相关帖子

沙发
FSL_TICS_Rita| | 2014-12-24 11:12 | 只看该作者
楼主你好, 请问你这里使用的是哪块板子呢?BSP版本使用的是哪个?

使用特权

评论回复
板凳
aprogramer| | 2014-12-24 16:14 | 只看该作者
pinmux settings: MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20

#define MX6S_GPT4_NFC_IRQ   IMX_GPIO_NR(5, 20)

  gpio_request(MX6S_GPT4_NFC_IRQ, "pn544-irq");
  gpio_direction_input(MX6S_GPT4_NFC_IRQ);

  irq_no = gpio_to_irq(MX6S_GPT4_NFC_IRQ);

Done.

使用特权

评论回复
地板
xlb7679|  楼主 | 2014-12-27 08:14 | 只看该作者
FSL_TICS_Rita 发表于 2014-12-24 11:12
楼主你好, 请问你这里使用的是哪块板子呢?BSP版本使用的是哪个?

谢谢回答,板子是E9   bsp版本怎么看?内核版本是3.0.35,

使用特权

评论回复
5
xlb7679|  楼主 | 2014-12-27 08:51 | 只看该作者
aprogramer 发表于 2014-12-24 16:14
pinmux settings: MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20

#define MX6S_GPT4_NFC_IRQ   IMX_GPIO_NR(5, 20)

谢谢aprogramer的耐心回答,我先说一下我开始的思路,
一、通过看原理图,我知道红外的输入口是gpio_6,然后我找到芯片手册的chapter.35,的IOMUXC_SW_MUX_CTL_PAD_GPIO_6,将其配置在为101,也就是ALT5(原话:101 ALT5 — Select mux mode: ALT5 mux port: GPIO[6] of instance: gpio1. )
二、通过chapter.27  我知道gpio共有7组,根据上面的alt5,我找到GPIO1_DR、GPIO1_GDIR、GPIO1_ICR1、GPIO1_ICR2,GPIO1_IMR通过这几个寄存器的配置,将红外管脚设为输入、相应的GPIO[6]的中断屏蔽使能
三、通过chapter.3  我找到gpio1[0-15]的硬件中断号是98.所以我在request_irq函数的第一个参数直接传了98,

我想知道我的步骤哪里出了问题,后来通过看/proc/interrupts文件,我发现内核有将红外静态编译进去,而且分配的中断号还是262号,这个262数字我是完全不理解(我查了些资料,好像都是说interrupts文件里的中断号就是硬件中断号,这个262是怎么来的?),我修改内核Kconfig文件,把原有的红外驱动去掉,给自己的request_irq()函数传262号,居然就成功了

我也知道你们这样通过宏操作来设置会简单,但是我只看懂了一个IOMUX_PAD(……)宏,像MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20这些管教的宏怎么找出来的我真心不知道,一个个.h去跟踪?
所以我还是先最用原始的地址来进行操做
(写的有点多,以前有用过s5pc210,也写过一些简单的驱动,不过是跟着老师一步步做的,感觉理解不是很深刻,想继续深入,望费心指点)

使用特权

评论回复
6
xlb7679|  楼主 | 2014-12-27 08:58 | 只看该作者
aprogramer 发表于 2014-12-24 16:14
pinmux settings: MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20

#define MX6S_GPT4_NFC_IRQ   IMX_GPIO_NR(5, 20)

能否说下
MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20
MX6S_GPT4_NFC_IRQ   
这两个宏是怎么定位的?

使用特权

评论回复
7
aprogramer| | 2014-12-27 09:51 | 只看该作者
本帖最后由 aprogramer 于 2014-12-27 09:57 编辑

没那么复杂,fsl做的思路是挺简单的。对于你的板子的pinmux的配置,你可以这样, 首先,要知道你的AP这端使用的pin的名字是什么。
知道之后,就好说了,假设你将其用做GPIO,ok,我说下做法, 举例:

static iomux_v3_cfg_t mx6s_gpt4_pads[] = {

  。。。。。

    /* NFC */
    MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20,  /* NFC_IRQ, input to AP */

     。。。。
}
其中的 CSI0_DATA_EN,就是 pin的名字,在pin assignment 那一chapter中有。 GPIO_5_20, 就是将这个pin用作GPIO功能。
MX6DL_PAD_ 这个是一个统一的前缀,依赖于你的 imx6 quad, dual, duallite, solo, sololite 而不同。
这个宏
MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20

kernel_imx\arch\arm\plat-mxc\include\mach\iomux-mx6dl.h
诸如还有:
kernel_imx\arch\arm\plat-mxc\include\mach\iomux-mx6q.h
kernel_imx\arch\arm\plat-mxc\include\mach\iomux-mx6sl.h

ok,然后,系统有一个函数,int mxc_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count)

使用                mxc_iomux_v3_setup_multiple_pads(mx6s_gpt4_pads,
                        ARRAY_SIZE(mx6s_gpt4_pads));
结合你上面定义的数组,就可以让你的pinmux配置生效。
至此,你的所有能 复用的pin的定义在你这个板子上就完毕了,当然你也可能,在做一个模块的时候,独立配置这些pinmux,随你。
我是在board-xxx.c的 board_init 入口,统一做的 ,就是调用 mxc_iomux_v3_setup_multiple_pads 这个函数,你上面定义的pinmux的那个数组作为参数。

而对于

#define MX6S_GPT4_NFC_IRQ   IMX_GPIO_NR(5, 20)

就很好说了,IMX 的 GPIO有很多bank,每个bank又有很多GPIO pin, 所以 IMX_GPIO_NR 的目的是将 bank,gpio这一pair 数据 转换为 一个逻辑上线性的对应关系。

而在知道了这个 线性的 数值之后, 就可以 利用 gpio_to_irq 这个macro 将 线性的gpio pin,转换为对应的 gpio irq。

kernel_imx\arch\arm\plat-mxc\include\mach\irqs.h 有
/*
* SoCs with TZIC interrupt controller have 128 IRQs, those with AVIC have 64
*/
#ifdef CONFIG_MXC_TZIC
#define MXC_INTERNAL_IRQS        128
#elif defined CONFIG_ARM_GIC
/* assuem 256 is enough for GIC */
#define MXC_INTERNAL_IRQS        256   《《《《========= here
#else
#define MXC_INTERNAL_IRQS        64
#endif

#define MXC_GPIO_IRQ_START        MXC_INTERNAL_IRQS

kernel_imx\arch\arm\plat-mxc\include\mach\gpio.h 有

/* There's a off-by-one betweem the gpio bank number and the gpiochip */
/* range e.g. GPIO_1_5 is gpio 5 under linux */
#define IMX_GPIO_NR(bank, nr)                (((bank) - 1) * 32 + (nr))

/* use gpiolib dispatchers */
#define gpio_get_value                __gpio_get_value
#define gpio_set_value                __gpio_set_value
#define gpio_cansleep                __gpio_cansleep

#define gpio_to_irq(gpio)        (MXC_GPIO_IRQ_START + (gpio))
#define irq_to_gpio(irq)        ((irq) - MXC_GPIO_IRQ_START)

综上, 你就可以知道,怎么配置你的红外的 gpio intr了。

Now, clear?

使用特权

评论回复
8
xlb7679|  楼主 | 2014-12-27 11:07 | 只看该作者
aprogramer 发表于 2014-12-27 09:51
没那么复杂,fsl做的思路是挺简单的。对于你的板子的pinmux的配置,你可以这样, 首先,要知道你的AP这端使 ...

嗯,谢谢如此详细的讲解,我知道我这个怎么弄了。
(这是熟悉一个平台操作接口后的方法,就是这是fsl的做法,我的做法应该是不管任何平台都是通用的,只是我卡在了中断号这里,原来我的第三步irq_no还得加上你说的MXC_GPIO_IRQ_START的偏移量,终归到底,我还是不了解最底层的操作流程,再次感谢!!)

使用特权

评论回复
9
aprogramer| | 2014-12-27 11:09 | 只看该作者
没事,记得结贴。

使用特权

评论回复
10
xlb7679|  楼主 | 2014-12-27 11:10 | 只看该作者
aprogramer 发表于 2014-12-27 11:09
没事,记得结贴。

嗯,第一次发帖,一时不知道怎么结贴,已经结了!

使用特权

评论回复
11
lqland| | 2014-12-28 11:48 | 只看该作者
aprogramer 发表于 2014-12-27 09:51
没那么复杂,fsl做的思路是挺简单的。对于你的板子的pinmux的配置,你可以这样, 首先,要知道你的AP这端使 ...

顶你!

使用特权

评论回复
12
elecintop| | 2014-12-28 17:10 | 只看该作者
:)

使用特权

评论回复
13
xlb7679|  楼主 | 2014-12-29 14:14 | 只看该作者
下面是我的红外实现代码:(我还是直接用的我自己之前的方法)
==============================================================
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>  //struct file_operations{}
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/semaphore.h>
#include <linux/sched.h>
#include <linux/gpio.h>
#include <asm/ioctl.h>
#include <asm/io.h>
#include <asm/uaccess.h>

#define IOMUXC_SW_MUX_CTL_PAD_GPIO_6 0x020E0230                   //IOMUXC_SW_MUX_CTL_PAD_GPIO_6的GPIO模式属于GPIO1
#define GPIO_1_ADDR_BASE         0x0209C000                                         //GPIO1的基地址
#define GPIO_1_GDIR                 (GPIO_1_ADDR_BASE + 0x4)        //控制input = 0、output = 1
#define GPIO_1_ICR1                        (GPIO_1_ADDR_BASE + 0xc)        //中断0-15
#define GPIO_1_IMR                        (GPIO_1_ADDR_BASE + 0x14)        //中断屏蔽位

MODULE_LICENSE ("GPL");

int irda_major = 255;
int irda_minor = 11;

struct cdev cdev;
int irda_val = 0;

struct irda_reg_t{
        unsigned int *iomux_sw_mux_ctl_pad_gpio_6;
        unsigned int *gpio_1_gdir;
        unsigned int *gpio_1_icr1;
        unsigned int *gpio_1_imr;
};
struct irda_reg_t irda_reg;

static int irda_open(struct inode *inode, struct file *fp)
{
        printk(KERN_INFO "Hi, the irda opened!!\n");

        return 0;
}

static int irda_release(struct inode *inode, struct file *fp)
{
        printk(KERN_INFO "Goodbye, the irda_fops closed!!\n");

        return 0;
}

ssize_t irda_read(struct file *fp, char *buff, size_t count, loff_t *offp)
{
        if( copy_to_user(buff, &irda_val, sizeof(int)))
                return -EFAULT;

        irda_val = 0;

        return sizeof(int);
}

struct file_operations irda_fops = {
        .owner = THIS_MODULE,
        .open = irda_open,
        .release = irda_release,
        .read = irda_read,
};

static void char_reg_setup_cdev(void)
{
        int error;
        dev_t devno;
        devno = MKDEV(irda_major, irda_minor);

        cdev_init(&cdev, &irda_fops);
        cdev.owner = THIS_MODULE;
        error = cdev_add(&cdev, devno, 1);
        if(error)
                printk(KERN_NOTICE "Error %d adding char_reg_setup_cdev\n", error);
}

irqreturn_t irda_handler(int irqno, void *dev_id)
{
        irda_val = 1;

        return IRQ_HANDLED;
}

int irda_request_irq(void)
{
        int ret;

        ret = request_irq(262, irda_handler, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "IrDA", NULL);
        if(ret < 0){
                printk(KERN_INFO "Error: request_irq!! ret = %d\n", ret);
                return ret;
        }
        printk(KERN_INFO "request 262 interrupt success!!\n");

        return 0;
}

void register_init(void)
{
        printk(KERN_INFO "register_init ****************\n");
        irda_reg.iomux_sw_mux_ctl_pad_gpio_6 = (unsigned int *)ioremap(IOMUXC_SW_MUX_CTL_PAD_GPIO_6, 4);
        irda_reg.gpio_1_gdir = (unsigned int *)ioremap(GPIO_1_GDIR, 4);
        irda_reg.gpio_1_icr1 = (unsigned int *)ioremap(GPIO_1_ICR1, 4);
        irda_reg.gpio_1_imr = (unsigned int *)ioremap(GPIO_1_IMR, 4);

        printk(KERN_INFO "1 = 0x%x\n", *irda_reg.iomux_sw_mux_ctl_pad_gpio_6);
        printk(KERN_INFO "2 = 0x%x\n", *irda_reg.gpio_1_gdir);
        printk(KERN_INFO "3 = 0x%x\n", *irda_reg.gpio_1_icr1);
        printk(KERN_INFO "4 = 0x%x\n", *irda_reg.gpio_1_imr);

        writel( 0x5, irda_reg.iomux_sw_mux_ctl_pad_gpio_6);  //ALT5;
        writel( 0, irda_reg.gpio_1_gdir);  //0 = input
        writel( 0x00003000, irda_reg.gpio_1_icr1);  //irq_1_6, falling-edge
        writel( 0x40, irda_reg.gpio_1_imr);  //enable interrupt 0
}

static int __init my_irda_init(void)
{
        int result;
        dev_t devno;
        devno = MKDEV(irda_major, irda_minor);

        result = register_chrdev_region(devno , 1, "IrDA");
        if( result < 0){
                printk (KERN_INFO "IrDA : can't get irda_major number %d\n", irda_major);
                return result;
        }
        char_reg_setup_cdev();        //注册字符设备
        irda_request_irq();                //注册中断
        register_init();

        return 0;
}

static void __exit my_irda_exit(void)
{
        dev_t devno;
        devno = MKDEV(irda_major, irda_minor);

        free_irq(262, NULL);
        iounmap(irda_reg.iomux_sw_mux_ctl_pad_gpio_6);
        iounmap(irda_reg.gpio_1_gdir);
        iounmap(irda_reg.gpio_1_icr1);
        iounmap(irda_reg.gpio_1_imr);

        unregister_chrdev_region(devno, 1);

        printk(KERN_INFO "IrDA driver cleaned up!!\n");
}

module_init(my_irda_init);
module_exit(my_irda_exit);
=========================================================================
执行insmod irda_drv.ko;dmesg -c   的显示结果(可以看到262号中断有申请成功,并且四个寄存器的内存分配的地址)

执行我的测试程序,结果如下(循环打印buff = 0,当中断发生打印buff = 1,并退出)

到这里可以看出,我要的功能是有实现的(下降沿触发中断,这里我随便找了一个遥控器来触发条件)。
但是还有隐藏的问题,当我
rmmod irda_drv
再一次
insmod irda_drv.ko时,这时4个寄存器分配的虚拟地址如下,

再运行我的测试程序,就出问题了:

这个应该是虚拟地址分配出了问题导致冲突了?我在驱动里有调用iounmap来释放内存,为什么会出现这种情况呢,迷茫中……

使用特权

评论回复
14
xlb7679|  楼主 | 2014-12-29 14:16 | 只看该作者

使用特权

评论回复
15
xlb7679|  楼主 | 2014-12-29 14:45 | 只看该作者
犯了个很2的错误,printk打了寄存器里的值!
这个是第一次insmod的地址

第二次insmod


无标题.png (6.26 KB )

无标题.png

使用特权

评论回复
16
aprogramer| | 2014-12-29 21:03 | 只看该作者
你的意思是 在 rmmod 中 iounmap 的 后面位置, 你用 printk 打印了?
那是不太恰当。

使用特权

评论回复
17
xlb7679|  楼主 | 2014-12-30 08:06 | 只看该作者
aprogramer 发表于 2014-12-29 21:03
你的意思是 在 rmmod 中 iounmap 的 后面位置, 你用 printk 打印了?
那是不太恰当。
...

我是在模块初始化中,初始化寄存器的时候调的printk,也就是ioremap的时候调的,主要是我不明白,为什么第一遍加载驱动然后运行测试程序没问题,而第二遍才出内存冲突的错误。申请中断和初始化寄存器不都是在xxx_init中完成的,等于是在insmod的时候就分配完虚拟地址了,为什么等我运行测试程序open设备才出错……这样的问题真的不知道从哪着手……

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

37

帖子

0

粉丝