[linux驱动开发--API框架]--platform、gpio、pinctrl
1. 结构体定义和实例化
// 这个结构体样式并不固定,按需增减成员,可以参考内核的其他驱动代码
struct leddev_dev{
dev_t devid; /* 设备号*/
struct cdev cdev; /* cdev*/
struct class *class; /* 类*/
struct device *device; /* 设备*/
int major; /* 主设备号*/
struct device_node *node; /* LED设备节点*/
int led0; /* LED灯GPIO标号*/
}leddev;
/*这个结构体最少也要有这些成员,可以参考内核的驱动代码*/
struct platform_driver led_platform_driver = {
.probe = led_probe,
.driver = {
.name = "leds-platform_gpio",
.owner = THIS_MODULE,
.of_match_table = led_ids,
}
};
2. 注册与卸载配套API
注意:顺序注册,逆序卸载
- 执行
led_platform_driver_init
、led_platform_driver_exit
函数
module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);
- 注册卸载平台驱动
DriverState = platform_driver_register(&led_platform_driver);
platform_driver_unregister(&led_platform_driver);
- 在
/proc/devices/LEDDEV_NAME
下生成名称对应LEDDEV_NAME
的主设备号
alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
unregister_chrdev_region(leddev.devid, LEDDEV_CNT);
cdev_init(&leddev.cdev, &led_fops);
cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
cdev_del(&leddev.cdev);
- 在
/sys/class/LEDDEV_NAME
下创建类
leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
class_destroy(leddev.class);
- 在
/dev/LEDDEV_NAME
下创建设备节点,在/sys/devices/virtual/gpio_lab_led
下创建设备
leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
device_destroy(leddev.class, leddev.devid);
- 试验了一下,现在的内核不需要显式释放
leddev.led0
leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
gpio_direction_output(leddev.led0, 1);
3. 完整代码(仅供参考)
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#define LEDDEV_CNT 1
#define LEDDEV_NAME "gpio_lab_led"
/* leddev设备结构体 */
struct leddev_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
struct device_node *node; /* LED设备节点 */
int led0; /* LED灯GPIO标号 */
};
struct leddev_dev leddev; /* led设备 */
static int led_open(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
return 0;
}
// /* 设备操作函数 */
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
};
/*----------------平台驱动函数集-----------------*/
static int led_probe(struct platform_device *pdv)
{
printk(KERN_EMERG "led driver and device was matched!\r\n");
// 注册的设备ID保存到leddev.devid
// LEDDEV_NAME对应/proc/devices下的名字
alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
leddev.major = MAJOR(leddev.devid);
printk(KERN_EMERG "\tleddev.major = %d\n",leddev.major);
// 绑定操作函数
cdev_init(&leddev.cdev, &led_fops);
// 绑定设备ID
cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
/* 3、创建类 */
leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
if (IS_ERR(leddev.class)) {
return PTR_ERR(leddev.class);
}
/* 4、创建设备 */
leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
if (IS_ERR(leddev.device)) {
return PTR_ERR(leddev.device);
}
leddev.node = of_find_node_by_path("/lab_led");
if(leddev.node == NULL)
{
printk(KERN_EMERG "get lab_led failed! \n");
}
leddev.led0 = of_get_named_gpio(leddev.node, "gpios", 0);
printk("led = %d \n",leddev.led0);
/*设置gpio输出高电平*/
gpio_direction_output(leddev.led0, 1);
return 0;
}
static const struct of_device_id led_ids[] = {
{ .compatible = "gpio_lab_led"},
{ /* sentinel */ }
};
/*定义平台设备结构体*/
struct platform_driver led_platform_driver = {
.probe = led_probe,
.driver = {
.name = "leds-platform_gpio",
.owner = THIS_MODULE,
.of_match_table = led_ids,
}
};
/*
*驱动初始化函数
*/
static int __init led_platform_driver_init(void)
{
int DriverState;
DriverState = platform_driver_register(&led_platform_driver);
printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
return 0;
}
/*
*驱动注销函数
*/
static void __exit led_platform_driver_exit(void)
{
printk(KERN_EMERG "led_test exit!\n");
gpio_direction_output(leddev.led0, 0);
device_destroy(leddev.class, leddev.devid);
class_destroy(leddev.class);
cdev_del(&leddev.cdev); /* 删除cdev */
unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */
platform_driver_unregister(&led_platform_driver);
}
module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);
MODULE_LICENSE("GPL");