pwm驱动一般由芯片厂商编写.他的驱动编写和使用方法和GPIO高度相似.例如一个芯片1到多个多个GPIO控制器,和0到多个pwm控制器,一个gpio控制器在代码里对应一个stuct gpiochip,同样一个pwm控制器在代码里对饮搞一个 struct pwmchip. 并且使用方法也很相似.后面可以看到.
PWM驱动分为pwm驱动和pwm设备pwm驱动由厂商提供位于:drivers/pwm/xxx.c目录下
一 pwm驱动
pwm驱动由厂商提供位于:drivers/pwm/xxx.c目录下
在设备树里的节点:
pwm3: pwm@02088000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x02088000 0x4000>;
interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM3>,
<&clks IMX6UL_CLK_PWM3>;
clock-names = "ipg", "per";
#pwm-cells = <2>;
status = "disabled";
};
pwm4: pwm@0208c000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x0208c000 0x4000>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM4>,
<&clks IMX6UL_CLK_PWM4>;
clock-names = "ipg", "per";
#pwm-cells = <2>;
status = "disabled";
};
这里配置了时钟,如果要用pwm 还要添加引脚
&pwm3 {
pinctrl-names = "default";
pinctrl-0 = <&xxxxxx>;
status = "okay";
}
源码了GPIO的类似,
debugfs接口
和GPIO一样,注册了debugfs文件系统的接口可以通过如下命令查看调试信息:
debugfs查看pwm信息
cat /sys/kernel/debug/pwm
cat /d/pwm
sysfs接口
驱动注册pwm设备也提供了sysfs的接口, 并且可以像导出gpio一样通过这些接口控制pwm如下:
sysfs查看pwm信息并手动设置PWM
/sys/class/pwm 目录看到注册的pwmchip
导出一个通道
/sys/class/pwm/pwmchip0 # echo 0 > export
这里导出pwmchip0的通道0, 执行成功后可以看到当前目录下的pwm0文件.
pwmchip0支持多少个通道可以通过 cat npwm 查看.
使能pwm
echo 1 > pwm0/enable
设置pwm通道的周期,单位ns
/sys/class/pwm/pwmchip0 # echo 5000000 > pwm0/period
设置pwm 高电平持续时间.单位ns
/sys/class/pwm/pwmchip0 # echo 2000000 > pwm0/duty_cycle
capture //电平捕获,用于捕获脉冲的宽度,这个很少用到.
duty_cycle //设置占空比(高电平时间),单位ns "5000" 高电平5000ns
enable //开关控制 "0" "1"
period //周期, 同 duty_cycle
polarity //极性,"normal",或 "inversed"
power
uevent
应用层直接访问pwm
参考:
https://www.cnblogs.com/wmate/p/14266140.html
https://blog.csdn.net/qq_37858386/article/details/115174952
二, 如何添加和使用pwm
使用方式和GPIO类似,仅仅是API不同.
设备树节点添加
如下是一个节点:
pwm_backlight: sprd_backlight {
compatible = "pwm-backlight";
pwms = <&pwm1 2 40000 0>;
pwm-names = "backlight";
pwms = <&pwm1 2 40000 0>;
"pwm", 名字必须是pwms
&pwm1, 指定pwm所在的pwmchip
2, 指定PWM在pwmchip中通道编号.
40000, 一般表示pwm的周期,单位ns
0, 制定极性, 一般是0即可,也可设置PWM_POLARITY_INVERTED 表示极性翻转
pwm-names = "backlight";
pwm-names 可有可无, 如果一个节点只用了一个pwm设备,则可以不用编写pwm-names属性, 驱动中使用pwm_get(&dev->dev, NULL); 即可获得PWM设备.
如果一个节点使用了多个设备,或者要应用层直接使用pwm设备则可以加上名字例如:
一个可选的属性 "pwm-names" 可能包含一系列字符串,用于标记 "pwms" 属性中列出的每个 PWM 设备。如果没有提供 "pwm-names" 属性,则使用用户节点的名称作为备用。
backlight {
compatible = "some-vendor,some-backlight";
pwms = <&pwm0 1 1000000 0>, <&pwm1 2 2000000 0>;
pwm-names = "backlight-dim", "backlight-brightness";
// 其他属性...
};
驱动中可以使用pwm_get(&dev->dev,backlight-dim)指定获取哪个pwm设备.
驱动中调用pwm
pwm = pwm_get(&dev->dev, NULL); //从节点获取pwm设备, 获取完成后就可以使用了
pwm_put();//释放申请的pwm设备.
/*
* struct pwm_state - state of a PWM channel
* @period: PWM period (in nanoseconds)
* @duty_cycle: PWM duty cycle (in nanoseconds)
* @polarity: PWM polarity
* @enabled: PWM enabled status
*/
struct pwm_state {
unsigned int period;
unsigned int duty_cycle;
enum pwm_polarity polarity;
bool enabled;
};
/*修改pwm*/
struct pwm_state state;
int error;
pwm_get_state(beeper->pwm, &state);
state.enabled = true;
state.period = period;
/*协助设置占空比.这里设置了周期,使用该函数设置 50占空比情况下高电平时间*/
pwm_set_relative_duty_cycle(&state, 50, 100);
/*执行修改.*/
error = pwm_apply_state(beeper->pwm, &state);
总结: 可以把PWM类比成一个gpio, 操作方法几乎相同,找到对应的API即可.