2025-03-26
在Linux内核中,struct pwm_device
是用于描述和管理PWM(脉冲宽度调制)设备的核心数据结构。它通常定义在include/linux/pwm.h
中,主要作用是为PWM控制器(硬件)和消费者(驱动)之间提供统一的抽象接口。
// test.dts
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
pwm1: timer@44000000 {
#address-celss = <0x1>;
#size-cells = <0x0>;
compatible = "st,stm32-timers";
reg = <0x44000000 0x400>;
clocks = <0xb 0x85>;
resets = <0xb 0x4c49>;
dams = <0xe 0x53 0x400 0x1 0xe 0x54 0x400 0x1>;
dma-name = "rx", "tx";
power-domains = <0x10>;
status = "disabled";
pwm {
compatible = "st,stm32-pwm";
#pwm-cells = <3>;
status = "disabled";
};
};
pwm1_pins_1: pwm1_pins {
status = "okay";
};
pwm1_sleep_pins_1: pwm1_sleep_pins {
status = "okay";
};
fan_pwm {
compatible = "pwm-fan";
status = "okay";
pwm = <&fan_pwm1 0 1000 0>;
};
};
// 覆写原有的设备树节点
&pwm1 {
/delete-property/dmas;
/delete-property/dma-name;
status = "okay";
fan_pwm1: pwm {
compatible = "st,stm32-timer";
status = "okay";
#pwm-cells = <0x3>;
pinctl-names = "default", "sleep", "idle", "active";
pinctl-0 = <&pwm1_pins_1>;
pinctl-1 = <&pwm1_sleep_pins_1>;
};
};
// simple.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#define PLATFORM_DEVICE_BASENAME "my_device"
#define PLATFORM_DEVICE_NAME_PWM "pwm-fan"
static u32 duty_ns; // 占用比
static u32 period_ns; // 周期
static struct pwm_device *pwm;
static int _probe(struct platform_device *device) {
pr_info("platform_driver_probe\n");
pwm = devm_pwm_get(&device->dev, NULL);
if (IS_ERR(pwm)) {
pr_info("devm_of_pwm_get failed\n");
return PTR_ERR(pwm);
}
// 占空比30%
int precent = 30;
duty_ns = precent * 10000;
period_ns = 1000000; // 1毫秒
pwm_config(pwm, duty_ns, period_ns);
pwm_enable(pwm);
return 0;
}
static int _remove(struct platform_device *device) {
pr_info("platform_driver_remove\n");
pwm_disable(pwm);
return 0;
}
// 会与设备树安装的platform_device进行匹配(一般用在嵌入式linux开发中)
struct of_device_id of_node_match_table[] = {
[0] = {.compatible = PLATFORM_DEVICE_NAME_PWM}, [1] = {}, // 空元素代表结束
};
struct platform_driver my_platform_driver = {
.probe = _probe,
.remove = _remove,
// 通过id_table匹配, 实现一个驱动对多个设备
.driver =
{
.name = PLATFORM_DEVICE_BASENAME,
// 设备树的匹配方式
.of_match_table = of_node_match_table,
},
};
static int __init pwm_driver_init(void) {
pr_info("pwm_driver_init\n");
int ret = platform_driver_register(&my_platform_driver);
if (ret < 0) {
pr_err("platform_driver_register_v6 failed\n");
return -1;
}
return 0;
}
static void __exit pwm_driver_exit(void) {
pr_info("pwm_driver_exit\n");
platform_driver_unregister(&my_platform_driver);
}
module_init(pwm_driver_init);
module_exit(pwm_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("heng30");
MODULE_VERSION("v0.0.1");
MODULE_DESCRIPTION("A simple pwm_driver kernel module");
#!/bin/sh
top-dir = $(shell pwd)
kernel-version = $(shell uname -r)
kernel-dir ?= /lib/modules/$(kernel-version)/build
obj-m += simple.o
all: dt driver
driver:
make -C $(kernel-dir) modules M=$(top-dir)
dt:
dtc -@ -I dts -O dtb -o test.dtbo test.dts
clean:
rm -f *.o *.ko *.mod *.mod.c *.order *.symvers *.dtbo
make -C $(kernel-dir) clean m=$(top-dir)