最近在fsl平台上进行移植,需要将某些gpio配置成普通的gpio功能(fsl平台的gpio支持多个功能),便写了简单的杂项设备,来调试gpio口。
使用时,只需安装gpio驱动,可实现下列三项功能
设置拉高某gpio,echo "io:w:108:1" >/dev/gpio_debug
设置拉低某gpio,echo "io:w:108:0" >/dev/gpio_debug
读取某gpio电平,echo "io:r:108" >/dev/gpio_debug
将某个gpio设置成中断功能,并检测中断,echo "io:q:108" >/dev/gpio_debug
#include
#include
#include
#include
#include
#include
#include
#include
#include
//echo "io:w:108:1" >/dev/gpio_debug
//echo "io:r:108" >/dev/gpio_debug
//echo "io:q:108" >/dev/gpio_debug
#define DEVICE_NAME "gpio_debug"
#define GPIO_DBG "[GPIO_DBG]"
#define GPIO_INF(format, args...) pr_info(GPIO_DBG "%s,%d" format, __FUNCTION__,__LINE__, ##args)
int irq_state=0;
unsigned int irq;
struct mutex gpio_mutex;
char *buf[20];
int get_gpio_port(char *p)
{
int gpio_num=-1;
int ret=-1;
gpio_num=simple_strtol(p,0,0);
if((gpio_num<1))
{
return -EINVAL;
GPIO_INF("unknown command\n");
}
ret=gpio_request(gpio_num,"debug_gpio");
if(ret<0)
{
GPIO_INF("request gpio %d err!err code=%d\n",gpio_num,ret);
gpio_free(gpio_num);
ret=gpio_request(gpio_num,"debug_gpio");
if(ret<0)
{
GPIO_INF("try request gpio %d egain err!\n",gpio_num);
return -EAGAIN;
}
GPIO_INF("request gpio%d again ok!\n",gpio_num);
}
return gpio_num;
}
irqreturn_t irq_handler(int irq, void *dev_id)
{
GPIO_INF("%s\n",__FUNCTION__);
irq_state=1;
return IRQ_HANDLED;
}
int analysis_cmd(char buffer[])
{
int i=0;
int ret;
int gpio_num=-1;
int gpio_value=-1;
char *buf[10];
while((buf[i++] = strsep(&buffer, ":")) != NULL);
if(strncmp((buf[0]),"io",2)==0)
{
if(strncmp(buf[1],"r",1)==0)
{
gpio_num=get_gpio_port(buf[2]);
gpio_direction_input(gpio_num);
gpio_value=gpio_get_value(gpio_num);
GPIO_INF("get gpio %d value %d.\n",gpio_num,gpio_value);
gpio_free(gpio_num);
}
if(strncmp(buf[1],"w",1)==0)
{
gpio_num=get_gpio_port(buf[2]);
gpio_value=simple_strtol(buf[3],0,0);
gpio_direction_output(gpio_num,gpio_value);
GPIO_INF("set gpio %d vlue %d.\n",gpio_num,gpio_value);
gpio_free(gpio_num);
}
if(strncmp(buf[1],"q",1)==0)
{
if(irq_state==1)
{
free_irq(irq,NULL);
irq_state=0;
}
gpio_num=get_gpio_port(buf[2]);
irq=gpio_to_irq(gpio_num);
if(irq<0)
{
GPIO_INF("gpio %d to request err!",gpio_num);
return -1;
}
GPIO_INF("gpio to irq %d ok,irq num=%d ok!\n",gpio_num,irq);
ret=request_irq(irq,irq_handler,IRQF_TRIGGER_RISING ,"irq_test",(void *)buf);
if(ret<0)
{
GPIO_INF("request_irq %d err!err code is %d!\n",gpio_num,ret);
return -1;
}
GPIO_INF("request irq %d ok!",gpio_num);
}
}
return 0;
}
static int gpio_open(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t gpio_write(struct file *file,const char __user *buffer, size_t size, loff_t *offet)
{
int ret;
char buf[100];
mutex_lock(&gpio_mutex);
if(copy_from_user(buf,buffer,size)<0)
{
mutex_unlock(&gpio_mutex);
return -EFAULT;
}
ret=analysis_cmd(buf);
mutex_unlock(&gpio_mutex);
return size;
}
static struct file_operations gpio_dev_fops={
.owner = THIS_MODULE,
.open = gpio_open,
.write = gpio_write,
};
static struct miscdevice gpio_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &gpio_dev_fops,
};
static int __init debug_init(void)
{
int ret;
mutex_init(&gpio_mutex);
ret = misc_register(&gpio_dev);
if(ret<0)
GPIO_INF("misc_register err!\n");
else
GPIO_INF("misc_register successful!\n");
return ret;
}
static void __exit debug_exit(void)
{
misc_deregister(&gpio_dev);
}
module_init(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("WWW");