linux驱动-定时器

文章介绍了在Linux环境下,如何使用定时器和GPIO来控制LED设备。通过定义leddev_dev结构体,包含了设备号、cdev、类、设备等信息,并设置了定时器的相关参数。在驱动加载和卸载函数中,进行了设备号注册、设备创建以及GPIO的申请和释放。probe函数中初始化了定时器并设置了回调函数。此外,还提供了ioctl接口用于控制定时器的开启、关闭和设置周期。
摘要由CSDN通过智能技术生成

今天开始学习下linux的定时器。

设备树还是沿用gpio的设备树。定义下led的结构体,这里追加了timeperiod和timer_list。

#define TIMER_CNT 1

#define TIMER_NAME  "timer"

#define CLOSE_CMD (_IO(0XEF, 0x1)) /* 关闭定时器 */

#define OPEN_CMD (_IO(0XEF, 0x2)) /* 打开定时器 */

#define SETPERIOD_CMD (_IO(0XEF, 0x3)) /* 设置定时器周期命令 */





/* leddev设备结构体 */

struct leddev_dev{

	dev_t devid;				/* 设备号	*/

	struct cdev cdev;			/* cdev		*/

	struct class *class;		/* 类 		*/

	struct device *device;		/* 设备		*/

	int major;					/* 主设备号	*/	

	int minor;

	struct device_node *node;	/* LED设备节点 */

	int led0;					/* LED灯GPIO标号 */

	int timeperiod;

	struct timer_list timer;

	spinlock_t lock;

};



struct leddev_dev leddev; 		/* led设备 */

定义出口和入口函数

/*

 * @description	: 驱动模块加载函数

 * @param 		: 无

 * @return 		: 无

 */

static int __init leddriver_init(void)

{

	printk(" driver initial \r\n");

	return platform_driver_register(&led_driver);

}



/*

 * @description	: 驱动模块卸载函数

 * @param 		: 无

 * @return 		: 无

 */

static void __exit leddriver_exit(void)

{

	printk(" driver exit \r\n");

	platform_driver_unregister(&led_driver);

}



module_init(leddriver_init);

module_exit(leddriver_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("jinqijun");

接下来platform的probe的函数。这里追加了3个函数。

    init_timer(&leddev.timer);
    leddev.timer.function = timer_function;    //回调函数
    leddev.timer.data = (unsigned long)&leddev;

static int led_probe(struct platform_device *dev)

{	

	printk("probe match\r\n");

	spin_lock_init(&leddev.lock);

	/* 1、设置设备号 */

	if (leddev.major) {

		leddev.devid = MKDEV(leddev.major, 0);

		register_chrdev_region(leddev.devid, TIMER_CNT, TIMER_NAME);

	} else {

		alloc_chrdev_region(&leddev.devid, 0, TIMER_CNT, TIMER_NAME);

		leddev.major = MAJOR(leddev.devid);

	}



	/* 2、注册设备      */

	cdev_init(&leddev.cdev, &led_fops);

	cdev_add(&leddev.cdev, leddev.devid, TIMER_CNT);



	/* 3、创建类      */

	leddev.class = class_create(THIS_MODULE, TIMER_NAME);

	if (IS_ERR(leddev.class)) {

		return PTR_ERR(leddev.class);

	}



	/* 4、创建设备 */

	leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, TIMER_NAME);

	if (IS_ERR(leddev.device)) {

		return PTR_ERR(leddev.device);

	}



	/* 5、初始化IO */	

	leddev.node = of_find_node_by_path("/jin-gpio-led");

	if (leddev.node == NULL){

		printk("gpio node nost find!\r\n");

		return -EINVAL;

	} 

	//三个参数,设备节点,设备数属性名称,个数

	leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);

	printk("led0 register\r\n");



	if (leddev.led0 < 0) {

		printk("can't get led-gpio\r\n");

		return -EINVAL;

	}



    //使用IO,必须先申请 ,使用of_get_named_gpio获取GPIO的属性,led0给GPIO设置了名字

	gpio_request(leddev.led0, "jin-led0");  

	gpio_direction_output(leddev.led0, 1); /* led0 IO设置为输出,默认高电平	*/



	init_timer(&leddev.timer);

	leddev.timer.function = timer_function;

	leddev.timer.data = (unsigned long)&leddev;

	return 0;

}

卸载函数,这里需要添加del_timer_sync.

static int led_remove(struct platform_device *dev)

{

	gpio_set_value(leddev.led0, 1); 	/* 卸载驱动的时候关闭LED */

	gpio_free(leddev.led0);				/* 释放IO 			*/

	del_timer_sync(&leddev.timer);



	cdev_del(&leddev.cdev);				/*  删除cdev */

	unregister_chrdev_region(leddev.devid, TIMER_CNT); /* 注销设备号 */

	device_destroy(leddev.class, leddev.devid);

	class_destroy(leddev.class);

	printk(" remove \r\n");

	return 0;

}

匹配列表,不需要修改。

/* 匹配列表 */

static const struct of_device_id match_tree[] = {

	{ .compatible = "jin-gpio-led" },

	{ /* Sentinel */ }

};

		

/* platform驱动结构体 */

static struct platform_driver led_driver = {

	.driver		= {

		.name	= "12345",			/* 驱动名字,用于和设备匹配 */

		.of_match_table	= match_tree, /* 设备树匹配表 		 */

	},

	.probe		= led_probe,

	.remove		= led_remove,

};

接下来编写app相关函数,timer_unlocked_ioctl函数里,可以修正定时器的参数。

 timer_function就类似单片机的中断函数,会定时执行。

static int led_open(struct inode *inode, struct file *filp)

{   

	printk(" led_open \r\n");

	filp->private_data = &leddev; /* 设置私有数据  */

	leddev.timeperiod = 1000;

	return 0;

}





static long timer_unlocked_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)

{

	struct leddev_dev *dev = (struct timer_dev *)filp->private_data;

	int timerperiod;

	unsigned long flags;



	switch(cmd){

		case CLOSE_CMD:

		     del_timer_sync(&dev->timer);

			 printk(" close cmd \r\n");

			 break;



	    case OPEN_CMD:

             spin_lock_irqsave(&dev->lock,flags);

			 timerperiod = dev->timeperiod;

			 spin_unlock_irqrestore(&dev->lock,flags);

			 mod_timer(&dev->timer,jiffies + msecs_to_jiffies(timerperiod));

			 printk(" open cmd \r\n");

		     break;



		case SETPERIOD_CMD:

             spin_lock_irqsave(&dev->lock,flags);

			 dev->timeperiod = arg;

			 spin_unlock_irqrestore(&dev->lock, flags);

			 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(arg));

			 printk(" set period cmd \r\n");

		     break;



		default:

		     break;

	}



	return 0 ;

}







/* 设备操作函数 */

static struct file_operations led_fops = {

	.owner = THIS_MODULE,

	.open = led_open,

	.unlocked_ioctl = timer_unlocked_ioctl,

};



void timer_function(unsigned long arg)

{

	struct leddev_dev *dev = (struct leddev_dev *)arg;

	static int sta = 1;

	int timerperiod;

	unsigned long flags;



	sta = !sta;

    gpio_set_value(dev->led0,sta);

    //printk(" time function \r\n");

	spin_lock_irqsave(&dev->lock,flags);

	timerperiod = dev->timeperiod;

	spin_unlock_irqrestore(&dev->lock,flags);

	mod_timer(&dev->timer,jiffies+msecs_to_jiffies(dev->timeperiod));

}

以上为linux的定时器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值