一个常用的gpio驱动

Posted 东皇※太一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个常用的gpio驱动相关的知识,希望对你有一定的参考价值。

分享一个gpio驱动,其中使用了gpio、pinctrl、irq、workqueue、input等知识,代码中有较详细的注释,不时可以来瞅一瞅!

首先设备树中如下配置:

&pio 
	touchsensor_pins_tp_int10: eint@10 
		pins_cmd_dat 
			pins = <MT8163_PIN_32_EINT10__FUNC_GPIO32>;
			slew-rate = <0>;
			bias-disable;
		;
	;
	
	touchsensor_pins_tp_int11: eint@11 
		pins_cmd_dat 
			pins = <MT8163_PIN_43_EINT11__FUNC_GPIO43>;
			slew-rate = <0>;
			bias-disable;
		;
	;
;

&touch 
	interrupt-parent = <&pio>;
	interrupts = <10 IRQ_TYPE_EDGE_FALLING>,
				 <11 IRQ_TYPE_EDGE_FALLING>,		
	eint-debounce = <256>;	
	pinctrl-names = "tp_int10","tp_int11";
	pinctrl-0 = <&touchsensor_pins_tp_int10>;
	pinctrl-1 = <&touchsensor_pins_tp_int11>;
	
	int10_gpio32 = <&pio 32 0>;
	int11_gpio43 = <&pio 43 0>;
	
	status = "okay";
;

源码如下:

#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/string.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/pinctrl/consumer.h>

static struct input_dev *touch_input_dev;

static struct work_struct work;
static struct workqueue_struct *wq;

static struct pinctrl *pin_ctrl;
static struct pinctrl_state *tp_int10, *tp_int11;

static unsigned int int10_gpio32,int11_gpio43;
static unsigned int irq_num10, irq_num11;
static unsigned char touch_event=0;

static void touch_work_handle(struct work_struct *work)

	if(touch_event=='a') 
		printk("work queue handle: aaa event\\n");
	
 	else if(touch_event=='b') 
		printk("work queue handle: bbb event\\n");
	
	touch_event=0;


static int tp_get_gpio_info(struct platform_device *pdev)

	int ret;
	/*如果设备树节点中把pinctrl-names = "default",则以下代码可以不写*/
	/*获取设备对应的pin control state holder*/
	pin_ctrl = devm_pinctrl_get(&pdev->dev);
	if (IS_ERR(pin_ctrl)) 
		ret = PTR_ERR(pin_ctrl);
		dev_err(&pdev->dev, "tp Cannot find touch pin_ctrl!\\n");
		return ret;
	
	/*查找pin control state*/
	tp_int10 = pinctrl_lookup_state(pin_ctrl, "tp_int10");
	if (IS_ERR(tp_int10)) 
		ret = PTR_ERR(tp_int10);
		dev_err(&pdev->dev, "tp Cannot find touch pinctrl default %d!\\n", ret);
	
	tp_int11 = pinctrl_lookup_state(pin_ctrl, "tp_int11");
	if (IS_ERR(tp_int11)) 
		ret = PTR_ERR(tp_int11);
		dev_err(&pdev->dev, "tp Cannot find touch pinctrl default %d!\\n", ret);
	
	/*设置gpio功能, 将获取到的信息直接设置到硬件*/
	pinctrl_select_state(pin_ctrl, tp_int10);
	pinctrl_select_state(pin_ctrl, tp_int11);

	printk("tp_get_gpio_info-----\\n");
	
	return ret;


void func_task_let(unsigned long data)

	printk("key-tasklet-test: this is bottom half\\n");


void func_work_queue(struct work_struct *work)

	printk("key-work-queue-test: this is workqueue bottom half\\n");


DECLARE_WORK(mywork, func_work_queue);
DECLARE_TASKLET(mytasklet, func_task_let, 0);

static irqreturn_t tp_eint_interrupt_handler(int irq, void *dev_id)

	if(irq_num10 == irq) 
	    touch_event='a';
		printk("interrupt:---eint10---\\n");
		/*if (!work_pending(&work)) 
			queue_work(wq, &work);
		*/
		
		schedule_work(&mywork);
	
	else if(irq_num11 == irq) 
		touch_event='b';
		printk("interrupt:---eint11---\\n");
		
		tasklet_schedule(&mytasklet);
	

	return IRQ_HANDLED;


static int touch_probe(struct platform_device *dev)

	int ret, err;
	struct device_node *node = NULL;
	int debounce = 17;//消抖时间设置,单位(ms)

	tp_get_gpio_info(dev);//得到gpio信息
	//从设备树中根据compatible从树根开始寻找节点
	node = of_find_compatible_node(NULL, NULL, "mediatek,touch");
	if (node) 
		//此函数从设备树中根据名称提取gpio口编号
		//会将设备树中类似<&pio 32 0>的属性信息转换为对应的GPIO编号
		int10_gpio32= of_get_named_gpio(node, "int10_gpio32", 0);
		int11_gpio43= of_get_named_gpio(node, "int11_gpio43", 0);
		//标记已有驱动使用了该gpio,此处就没判断返回结果了
		gpio_request(int10_gpio32, "int10_gpio32");
		gpio_request(int11_gpio43, "int11_gpio43");
		//设置gpio消抖时间
		gpio_set_debounce(int10_gpio32, debounce);
		gpio_set_debounce(int11_gpio43, debounce);
		//从设备树interupts属性中提取到对应的中断号
		irq_num10 = irq_of_parse_and_map(node, 2);
		printk("tp_probe_irq = %d\\n", irq_num10);
		//request_irq用于申请激活中断,设置以后可以在/proc/interrupts中看到对应的中断名字
		ret = request_irq(irq_num10, (irq_handler_t) tp_eint_interrupt_handler, \\
							 IRQF_TRIGGER_FALLING, "touchsensor-eint", NULL);
		irq_num11 = irq_of_parse_and_map(node, 3);
		printk("tp_probe_irq = %d\\n", irq_num11);
		ret = request_irq(irq_num11, (irq_handler_t) tp_eint_interrupt_handler, \\
							IRQF_TRIGGER_FALLING, "touchsensor-eint", NULL);
		if (ret > 0) 
			ret = -1;
			printk("tp_probe request_irq IRQ LINE NOT AVAILABLE!ret = %d.",ret);
		
	
	/*********************************************************/
	touch_input_dev = input_allocate_device();	//分配设备,注册设备支持event类型
	__set_bit(EV_SYN, touch_input_dev->evbit);  //设置产生同步事件
	__set_bit(EV_KEY, touch_input_dev->evbit);	//设置产生按键事件
	__set_bit(KEY_VOLUMEUP, touch_input_dev->keybit);//设置产生哪些按键值
	touch_input_dev->name ="TouchSensor";
	err = input_register_device(touch_input_dev);//向input子系统注册input_dev设备
	if (err) 
		printk( "touch register input device failed (%d)\\n", err);
		input_free_device(touch_input_dev);
		return err;
	
	/*********************************************************/
	//create_workqueue创建一个workqueue队列,为系统中的每个CPU都创建一个内核线程
	wq = create_singlethread_workqueue("kworkqueue_iqs");//只创建一个内核线程
	flush_workqueue(wq);//清理指定工作队列中的所有任务
	//work表示要初始化的工作,touch_mcu_worker是工作对应的处理函数
	INIT_WORK(&work, touch_work_handle);

	printk("touch_probe====\\n");
	
	return 0;


#ifdef CONFIG_OF//有设备树的情况下就用这个匹配
static const struct of_device_id TP_of_match[] = 
	.compatible = "mediatek,touch",
	,
;
#endif

static struct platform_driver tp_platform_driver = 
	.probe = touch_probe,
	.driver = 
		   .name = "touch",
		   .owner = THIS_MODULE,
#ifdef CONFIG_OF
		   .of_match_table = TP_of_match,
#endif
	,
;

//触摸按钮:EINT_10 ~ EINT_11
static int __init touchsensor_init(void)
	
	platform_driver_register(&tp_platform_driver);

	printk("touch init finish-------------\\n");
	return  0;


static void __exit touchsensor_exit(void)

	free_irq(irq_num10, NULL);//释放irq_num10中断
	free_irq(irq_num11, NULL);//释放irq_num11中断
	input_unregister_device(touch_input_dev);//注销touch_input_dev
	input_free_device(touch_input_dev); 	 //删除touch_input_dev


module_init(touchsensor_init);
module_exit(touchsensor_exit);

MODULE_AUTHOR("woshishui");
MODULE_DESCRIPTION("touchsensor");
MODULE_LICENSE("GPL");

以上是关于一个常用的gpio驱动的主要内容,如果未能解决你的问题,请参考以下文章

linux驱动 — 常用API

Linux内核驱动之GPIO子系统GPIO的使用

Linux内核驱动之GPIO子系统GPIO的使用

stm32—GPIO

iTOP3399开发板GPIO子系统-应用层控制GPIO

linux中按键控制gpio灯的驱动程序怎么写。(自定义函数,gpio引脚)