自己动手写Linux驱动代码

Posted Wu_Being

tags:

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

相关代码修改 git status

wucb0122@wucb0122-ubuntu14:~/my_project/kernel-4.4$ 
wucb0122@wucb0122-ubuntu14:~/my_project/kernel-4.4$ git status
HEAD detached at 388a8ce
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   arch/arm/boot/dts/proj_xxx/chipxxx.dtsi
	modified:   drivers/misc/Makefile

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	arch/arm/boot/dts/proj_xxx/chipxxx.dtsi_bak
	drivers/misc/ts_square_wave.c
	drivers/misc/ts_test.c

no changes added to commit (use "git add" and/or "git commit -a")
  1. 修改编译配制
wucb0122@wucb0122-ubuntu14:~/my_project/kernel-4.4$ git diff drivers/misc/Makefile
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f26ac5c..6ea2403 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_QPNP_MISC)       += qpnp-misc.o
 obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o
 
 obj-$(CONFIG_BOARD_ID_DETECTION)       +=board_id_detect.o
+obj-y                           += ts_square_wave.o
  1. 配制相关gpio设备树信息(61号gpio)
wucb0122@wucb0122-ubuntu14:~/my_project/kernel-4.4$ git diff arch/arm/boot/dts/proj_xxx/chipxxx.dtsi 
diff --git a/arch/arm/boot/dts/proj_xxx/chipxxx.dtsi b/arch/arm/boot/dts/proj_xxx/chipxxx.dtsi
index 9934d37..803f9ce 100644
--- a/arch/arm/boot/dts/proj_xxx/chipxxx.dtsi
+++ b/arch/arm/boot/dts/proj_xxx/chipxxx.dtsi
@@ -2509,6 +2509,17 @@
 
+
+       ts-square_wave  
+               compatible = "ts,square_wave";  
+               ts_square_wave,gpio= <&tlmm 61 0>;  
+               status = "okay";  
+       ;  
 ;
 
 #include "chipxxx-ion.dtsi"
wucb0122@wucb0122-ubuntu14:~/my_project/kernel-4.4$ 
wucb0122@wucb0122-ubuntu14:~/my_project/kernel-4.4$ 

  1. 驱动代码 ts_square_wave.c
#include <linux/kernel.h>  
#include <linux/init.h>  
#include <linux/module.h>   
#include <linux/delay.h>  
#include <linux/gpio.h> 
#include <linux/interrupt.h> 
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/pm_wakeup.h>
#include <linux/workqueue.h>

#ifdef CONFIG_OF  
#include <linux/of.h>  
#include <linux/of_gpio.h>  
#include <linux/of_platform.h>  
#endif  

#define GPIO_LOW 0  
#define GPIO_HIGH 1  

struct dev_data
	int irq;
	int gpio;
	struct work_struct ts_work;
	struct workqueue_struct *ts_workqueue;
	struct wakeup_source *ws;
;

static struct dev_data * ts_dev_data;

static int is_charging(void)//充电状态的检测
	return 1;


static int is_powerfull(void)//检测电池电量
	return 0;


static int feature_accessory_func(void)//空函数
	return 0;


irqreturn_t interrupt_handler(int irq, void *dev_id)
	printk("ts: enter %s......\\n", __func__);
	if (is_charging())
		//__pm_stay_awake(ws);//如果正在充电,保持唤醒
		if (is_powerfull())
			gpio_set_value(ts_dev_data->gpio, GPIO_HIGH);
		else  //如果电池电量不足100%释放方波
			schedule_work(&ts_dev_data->ts_work);
		
	else
		//__pm_relax(ws);//如果不是充电,就释放wakeup_source 	
		feature_accessory_func();
		gpio_set_value(ts_dev_data->gpio, GPIO_LOW);
		
	return IRQ_HANDLED;


//  工作队列处理函数  释放方波
static void work_handler(struct work_struct *work)  
  

	printk("ts: enter %s .......\\n", __func__);
	disable_irq(ts_dev_data->irq);
	free_irq(ts_dev_data->irq, NULL);
	if (is_charging())
		if (is_powerfull())
			gpio_set_value(ts_dev_data->gpio, GPIO_HIGH);
		else  //如果电池电量不足100%释放方波
			msleep(500);
			gpio_direction_output(ts_dev_data->gpio, GPIO_HIGH);
			msleep(500);
			gpio_direction_output(ts_dev_data->gpio, GPIO_LOW);
			schedule_work(&ts_dev_data->ts_work);
		
	else
		//__pm_relax(ws);//如果不是充电,就释放wakeup_source
		gpio_set_value(ts_dev_data->gpio, GPIO_LOW);
	

  

static int ts_square_wave_probe(struct platform_device *pdev)  
  
	int ret = -1;  
	struct device_node *ts_node = pdev->dev.of_node;  

	printk("ts: %s-%d: enter\\n", __FUNCTION__, __LINE__);  

	// 分配空间,并从设备树获取值(对应设备树 ts_square_wave,gpio= <&tlmm 61 0>; )
	ts_dev_data = kmalloc(sizeof(struct dev_data), GFP_KERNEL);
	ts_dev_data->gpio = of_get_named_gpio_flags(ts_node, "ts_square_wave,gpio", 0, NULL);

	printk("ts: we have get the gpio number gpio = %d\\n", ts_dev_data->gpio);
	if (!gpio_is_valid(ts_dev_data->gpio))  
		printk("ts: invalid gpio : %d\\n", ts_dev_data->gpio);  
		return -1;  
	
	
	// 设置该脚要gpio,并命名为"ts_square_wave_gpio"
	ret = gpio_request(ts_dev_data->gpio, "ts_square_wave_gpio");  
	if (ret != 0)   
		gpio_free(ts_dev_data->gpio);  
		printk("ts: invalid gpio : %d\\n", ts_dev_data->gpio);
		return -EIO;  
	  
	
	// 设置gpio为中断脚,并设置中断,中断处理函数interrupt_handler,中断名"ts_square_wave_irq"
	ts_dev_data->irq = gpio_to_irq(ts_dev_data->gpio);
	printk("ts: we have get the irq number irq = %d\\n", ts_dev_data->gpio);
	ret = request_irq(ts_dev_data->irq, interrupt_handler, IRQF_TRIGGER_RISING, "ts_square_wave_irq", NULL);

	// 注册 wakeup_source
	ts_dev_data->ws = wakeup_source_register("ts_square_wave_lock");
	
	//__pm_stay_awake(ts_dev_data->ws); //申请wakeup_source
	//__pm_relax(ts_dev_data->ws); //释放wakeup_source

	// 创建工作队列
	ts_dev_data->ts_workqueue = create_singlethread_workqueue("ts_square_wave_queue");  
	if (ts_dev_data->ts_workqueue)  
	  
		//  初始化work_struct类型的变量(主要是指定处理函数 work_handler)  
		INIT_WORK(&ts_dev_data->ts_work, work_handler);  
		//schedule_work(&ts_dev_data->ts_work);
	  

	return 0;  //return Ok  
  

static int ts_square_wave_remove(struct platform_device *pdev)  
   
	return 0;  
  

#ifdef CONFIG_OF  
static const struct of_device_id of_ts_square_wave_match[] =   
	 .compatible = "ts,square_wave" ,   // 对应设备树 compatible = "ts,square_wave";  
	 /* Sentinel */   
;  
#endif  

static struct platform_driver ts_square_wave_driver =   
	.probe      = ts_square_wave_probe,  
	.remove     = ts_square_wave_remove,  
	.driver     =   
		.name   = "ts_square_wave",  
		.owner  = THIS_MODULE,  
#ifdef CONFIG_OF  
		.of_match_table = of_ts_square_wave_match,  
#endif  
	,  

;  

static int __init ts_init(void)  
  
	printk(KERN_INFO "ts: ts_init: enter %s.\\n", __FUNCTION__);  
	return platform_driver_register(&ts_square_wave_driver);  
	return 0;  
  

static void __exit ts_exit(void)  
  
	platform_driver_unregister(&ts_square_wave_driver);  
	printk("ts: ts_exit: ts_square_wave_driver.\\n");  
  

subsys_initcall(ts_init);  
module_exit(ts_exit);  

MODULE_AUTHOR("WuChengbing");  
MODULE_DESCRIPTION("Output square wave by detecting is_charging and no is_powerfull.");  
MODULE_LICENSE("GPL");  

  1. 调试获取函数实现接口
    cat d/wakeup_sources
    cat proc/interrupts
    cat sys/bus/platform/driver

Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!
《自己动手写Linux驱动代码》:
https://blog.csdn.net/u014134180/article/details/80602593

以上是关于自己动手写Linux驱动代码的主要内容,如果未能解决你的问题,请参考以下文章

自己动手写最简单的Android驱动---LED驱动的编写

8.4 Android灯光系统_源码分析_电池灯

在 Linux 上检查连接的蓝牙设备的电池电量

android 自定义View绘制电池电量(电池内带数字显示)

sh Linux Mint Cinnamon:在电池电量不足时显示通知

在android中自动更新电池电量