platform总线框架+LED设备驱动框架简单模板

内核版本:4.14.0
基于设备树、GPIO子系统

#include <linux/module.h>   
#include <linux/of_gpio.h> 
#include <linux/platform_device.h>
#include <linux/leds.h>

#define DEVICE_CNT		1				/* Number of device id */
#define DEVICE_NAME		"led"		/* Device name */
#define COMPAT_PROPT	"xxx,led"	/* Compatible property of the device matched with this driver. */

/* Device information structure. */
struct led_info { 
	struct led_classdev led_cdev;		/* Led device */ 
	int gpio_id;
};

/* 
 * @description :	Initialize the device.
 * @param -pdev:	Pointer to platform device.
 * @return :		0: Successful; Others: Failed.
 */
static int led_init(struct platform_device *pdev) 
{ 
	int ret;
	const char *str;
	struct led_info *p_led_info  = platform_get_drvdata(pdev);
	
	/* Get gpio id. */
	p_led_info->gpio_id = of_get_named_gpio(pdev->dev.of_node, DEVICE_NAME"-gpio", 0);
	if (!gpio_is_valid(p_led_info->gpio_id))
	{
		dev_err(&pdev->dev, "Failed to get gpio id!"); 
		return -EINVAL;
	}
	
	printk(KERN_INFO "%s: gpio id = %d\n", DEVICE_NAME, p_led_info->gpio_id);
	
	/* 
	 * Request the use of GPIO from the gpio subsystem. 
	 * Equivalent to gpio_request(), it is also used to request GPIO resources (pins) from the
	 * system. However, the function has the devm_ prefix, which means that it is a version of the function
	 * that includes device resource management. Therefore, when using it, the struct device pointer of the
     * device needs to be specified, and there is no need to manually release GPIO when uninstalling the driver.
	 */
	ret = devm_gpio_request(&pdev->dev, p_led_info->gpio_id, DEVICE_NAME"-GPIO");
	if (ret)
	{
		dev_err(&pdev->dev, "Failed to request GPIO!");
		return ret;
	}
	
	/* Set GPIO as output mode and default value. */
	ret = of_property_read_string(pdev->dev.of_node, "default-state", &str);
	if (!ret)
	{
		if (strcmp(str, "on"))
			gpio_direction_output(p_led_info->gpio_id, 0);
		else
			gpio_direction_output(p_led_info->gpio_id, 1);
	}
	else
		gpio_direction_output(p_led_info->gpio_id, 0);
	
	return 0;
}

/* 
 * @description :		Set up brightness of the led, can not be blocked.
 * @param -p_led_cdev :	Pointer to struct led_classdev.
 * @param -brightness : Brightness value.
 * @return :			None.
 */
static void led_brightness_set(struct led_classdev *p_led_cdev, enum led_brightness brightness)
{
	/* Get the address of the structure through the address of its member variable */
	struct led_info *p_led_info = container_of(p_led_cdev, struct led_info, led_cdev);
	
	if (brightness == LED_ON)
		gpio_set_value(p_led_info>gpio_id, 1);
	else
		gpio_set_value(p_led_info->gpio_id, 0);
}

/* 
 * @description :		Set up brightness of the led, can be blocked.
 * @param -p_led_cdev :	Pointer to struct led_classdev.
 * @param -brightness : Brightness value.
 * @return :			0.
 */
static int led_brightness_set_blocking(struct led_classdev *p_led_cdev, enum led_brightness brightness)
{
	led_brightness_set(p_led_cdev, brightness);
	
	return 0;
}

/* 
 * @description :	Probe function of the platform, it will be executed when the 
 * 					platform driver and platform device matching successfully.
 * @param -pdev :	Pointer to platform device.
 * @return :		0: Successful; Others: Failed.
 */
static int led_probe(struct platform_device *pdev)
{
	int ret;
	struct led_info *p_led_info;
	
	dev_info(&pdev->dev, "Driver and device matched successfully!\n");
	
	/* Allocate memory for struct led_info */
	p_led_info = devm_kzalloc(&pdev->dev, sizeof(struct led_info), GFP_KERNEL);
	if (!p_led_info)
		return -ENOMEM;
	
	/* Store the led_info pointer in pdev->dev.driver_data for later use */
	platform_set_drvdata(pdev, p_led_info);
	
	/* Led init */
	ret = led_init(pdev);
	if (ret)
		return ret;

	/* Init the led_cdev */
	p_led_info->led_cdev.name = DEVICE_NAME;
	p_led_info->led_cdev.brightness = LED_OFF;		//Set the default brightness
	p_led_info->led_cdev.max_brightness = LED_FULL;
	/* Bind the LED brightness setting function that cannot block */
	p_led_info->led_cdev.brightness_set = led_brightness_set;	
	/* Bind the LED brightness setting function that can block */
	p_led_info->led_cdev.brightness_set_blocking = led_brightness_set_blocking;
	
	/* Register LED device */
	return led_classdev_register(&pdev->dev, &p_led_info->led_cdev); 
} 

/* 
 * @description :	Release some resources. This function will be executed when the platform
 *					driver module is unloaded.
 * @param :			None.
 * @return :		0: Successful; Others: Failed.
 */
static int led_remove(struct platform_device *pdev) 
{ 
	/* Get the led_info pointer which is stored in pdev->dev.driver_data before */
	struct led_info *p_led_info = platform_get_drvdata(pdev);
	
	/* Unregister the LED device */
	led_classdev_unregister(&p_led_info->led_cdev);
	
	dev_info(&pdev->dev, "Driver has been removed!\n"); 

	return 0;
} 

/* Match table */
static const struct of_device_id led_of_match[] = {
	{.compatible = COMPAT_PROPT},
	{/* Sentinel */}
};

/* 
 * Declare device matching table. Note that this macro is generally used to dynamically 
 * load and unload drivers for hot-pluggable devices such as USB devices.
 */
MODULE_DEVICE_TABLE(of, device_of_match); 

/* Platform driver struct */
static struct platform_driver led_driver = {
	.driver = {
		.name = DEVICE_NAME,				//Drive name, used to match device who has the same name.
		.of_match_table = led_of_match,	//Used to match the device tree who has the same compatible property.
	},
	.probe = led_probe,					//probe function
	.remove = led_remove,				//remove function
};

/*
 * Register or unregister platform driver,
 * and Register the entry and exit functions of the Module.
 */
module_platform_driver(led_driver);

/* 
 *  Author, driver information and LICENSE.
 */ 
MODULE_AUTHOR("蒋楼丶");
MODULE_DESCRIPTION(DEVICE_NAME" Driver Based on LED Driver Framework"); 
MODULE_LICENSE("GPL");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值