背景
-
海思的硬件复位RSTN复位后无法启动,目前确定不了问题出在哪里
-
另一方案:通过内核捕获gpio的中断后将整个系统复位,即软复位
基本代码框架
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/reboot.h>
struct st_gpio_int {
int int_irq;//中断号
int int_pin;//中断寄存器
int int_num;//中断编号
char *int_name;//中断名称
};
#define ARRY_SIZE(A) (sizeof(A)/sizeof(A[0]))
#define GPIO_INT_READ _IOR('L', 0x03, char [4])
#define HI3531D_GPIO23_0 93
#define REG_WRITE(addr, value) ((*(volatile unsigned int *)(addr)) = (value))
#define REG_READ(Addr) (*(volatile unsigned int *)(Addr))
#define GPIO_23_BASE 0x122C0000
#define GPIO_23_DIR IO_ADDRESS(GPIO_23_BASE + 0x400)//GPIO 方向控制寄存器
#define GPIO_23_IS IO_ADDRESS(GPIO_23_BASE + 0x404)//GPIO 中断触发寄存器
#define GPIO_23_IEV IO_ADDRESS(GPIO_23_BASE + 0x40C)//GPIO 触发中断条件寄存器
#define GPIO_23_IC IO_ADDRESS(GPIO_23_BASE + 0x41C)//GPIO 中断清除寄存器
#define GPIO_23_IE IO_ADDRESS(GPIO_23_BASE + 0x410)//GPIO 中断屏蔽寄存器
#define GPIO_23_RIS IO_ADDRESS(GPIO_23_BASE + 0x414)//GPIO 原始中断状态寄存器
static const struct st_gpio_int gpio_reboot[] = {
{HI3531D_GPIO23_0, 23, 0,"GPIO23_0_INT"},
};
static void hi3531d_pin_cfg(void)
{
unsigned char regvalue;
//GPIO23_0
/*配置作为普通输入 in=0 out=1 */
regvalue = REG_READ(GPIO_23_DIR);
regvalue &= ~(1<<0);
REG_WRITE(GPIO_23_DIR, regvalue);
/*GPIO4_7 管脚中断配置*/
regvalue = REG_READ(GPIO_23_IS);/*is=0 边沿触发中断 is=1 电平触发*/
regvalue |= (1<<0);
REG_WRITE(GPIO_23_IS, regvalue);
regvalue = REG_READ(GPIO_23_IEV);/*iev=1 上升沿触发,高电平触发中断 iev=0 下降沿触发,低电平触发中断*/
regvalue &= ~(1<<0);
REG_WRITE(GPIO_23_IEV, regvalue);
regvalue = REG_READ(GPIO_23_IC);/*ic清除中断*/
regvalue = 0xff;
REG_WRITE(GPIO_23_IC, regvalue);
regvalue = REG_READ(GPIO_23_IE);/*ie不屏蔽中断*/
regvalue |= (1<<0);
REG_WRITE(GPIO_23_IE, regvalue);
}
/*
* Describe: gpio23_0 irq function
*/
static irqreturn_t gpio_reboot_eint(int irq, void *dev_id)
{
unsigned char regvalue;
if( HI3531D_GPIO23_0 == irq)
{
regvalue = 0xff;
REG_WRITE(GPIO_23_IC, regvalue);/*ic清除中断*/
kernel_restart(NULL); //重启
}
return IRQ_HANDLED;
}
static int __init irq_init(void)
{
int ret = -1;
hi3531d_pin_cfg();
ret = request_irq(gpio_reboot[0].int_irq, gpio_reboot_eint, IRQF_SHARED , //这里为共享中断
gpio_reboot[0].int_name, (void *)&gpio_reboot);
if(ret)
{
printk("requtest EINT_%d(%s) failed:%d
", gpio_reboot[0].int_irq, gpio_reboot[0].int_name, ret);
goto err_gpio_request;
}
printk("success
");
return 0;
err_gpio_request:
return ret;
}
static void __exit irq_exit(void)
{
free_irq(gpio_reboot[0].int_irq, (void *)&gpio_reboot);
}
module_init(irq_init);
module_exit(irq_exit);
MODULE_LICENSE("GPL");
MODULE_VERSION("v1.0");
问题
-
中断申请标志位问题:
-
申请中断时,使用request_irq,第三个参数为触发的方式,最初用的是IRQF_SHARED | IRQF_TRIGGER_HIGH 的标志位,出现以下问题:
genirq: Setting trigger mode 8 for irq 93 failed (gic_set_type+0x0/0x90)
-
猜想:应该是同组的其他GPIO也申请中断,并且申请的中断触发情况不同,在海思3531d中,GPIO20 - GPIO23共享一个中断号93
-
解决方案:中断申请标志改为 IRQF_SHARED
-
-
内核重启指令
-
应用层直接使用system函数,而内核层没有相关函数,使用的是kernel_restart
#include <linux/reboot.h> kernel_restart(NULL);
-