海思GPIO和中断操作

中断部分:
1.关于gpio的操作
<1>gpio_request(gpio_num, NULL);  注册 GPIO
<2>设置gpio方向:
对于输入: gpio_direction_input(gpio_num) 
对于输出: gpio_direction_output(gpio_num, gpio_out_val)
<3>查看 GPIO 输入值或设置 GPIO 输出值
gpio_get_value  查看输入值
输出低: gpio_set_value(gpio_num, 0) 
输出高: gpio_set_value(gpio_num, 1);
gpio_free 释放gpio

2.关于gpio中断操作
<1>gpio_request(gpio_num, NULL);   注册 GPIO
<2>gpio_direction_input(gpio_num)  对于要作为中断源的 GPIO 引脚, 方向必须配置为输入
而且这个地方要注意配置为上拉输入,还是下拉输入。
<3>irq_num = gpio_to_irq(gpio_num);  映射操作的 GPIO 编号对应的中断号, 中断号为 gpio_to_irq(gpio_num)的返回值。
<4>request_irq(irq_num, gpio_dev_test_isr, irqflags, "gpio_dev_test",
	&gpio_irq_type))
Irqflags 为需要注册的中断类型, 常用类型有
IRQF_SHARED : 			共享中断;
IRQF_TRIGGER_RISING : 	上升沿触发;
IRQF_TRIGGER_FALLING : 下降沿触发;
IRQF_TRIGGER_HIGH : 	高电平触发;
IRQF_TRIGGER_LOW : 	低电平触发。
为什么会有共享中断呢?
IRQF_SHARED, 因为有时候会有几个设备共用一个soc的gpio去通知soc,那么这时候怎么办?
这时候就要用到共享中断。
那么发生中断的时候,怎么去判断到底是哪个设备有中断通知呢?
在中断申请的过程中有一个参数:gpio_irq_type,是一个 void *类型。不同的设备在申请的时候在这里传
不同的参数,再在gpio_dev_test_isr中去判断是哪个参数就可以了。
例如
设备1int attr = 0;
request_irq(irq_num, gpio_dev_test_isr, irqflags, "gpio_dev_test",
	&attr))
设备2int attr = 1;
request_irq(irq_num, gpio_dev_test_isr, irqflags, "gpio_dev_test",
	&attr))
在中断处理函数:
static irqreturn_t gpio_dev_test_isr(int irqno, void* attr)
{
	if (0 == *((int *)attr))
	{
		//对应设备1需要做的事
	}
	else if (1 == *((int *)attr))
	{
		//对应设备2需要做的事
	}
}
<4>结束时释放注册的中断和 GPIO 编号
free_irq(gpio_to_irq(gpio_num), &gpio_irq_type)
gpio_free(gpio_num);

3.中断是分上半部和下半部的
<1>在中断的上半部,处理紧急的事情
<2>在中断的下半部,可以处理可以延后的事情
在中断的下半部,有三种处理机制:
软中断、tasklet、工作队列,还有内核线程
<3>一般在中断的上半部机会disable中断, 下半部处理完了才会
去enable中断,这样的话,如果中断来的太密集,就会丢掉。
<4>tasklet 使用: 如果推后执行的任务不需要睡眠,那么就选择tasklet
void func(void)
{
}

//定义tasklet并绑定tasklet调度函数
DECLARE_TASKLET(mytasklet, func, 0);

//中断的上半步
static irqreturn_t button_interrupt(int irq, void *dummy)
{
	tasklet_schedule(&mytasklet); //在上半步中进行tasklet调度
	return IRQ_HANDLED;
}

<5>workqueue使用:可以被调度,因此可以睡眠
void func(void)
{
}

//定义workqueue并绑定workqueue调度函数
DECLARE_WORK(mywork, func);


//中断的上半步
static irqreturn_t button_interrupt(int irq, void *dummy)
{
	schedule_work(&mywork);
	return IRQ_HANDLED;
}

你可能感兴趣的:(linux驱动)