1 pwm子系统框架#

用户态:基于sysfs操作pwm
内核态分为:
1 | pwm core:pwm_chip的添加删除,pwm_class类pwm_chip/pwm_device的sysfs创建。 |
1.1 源码结构#
1 | drivers/pwm/ |

我已经编译进vmlinux了,可以看到built-in.o。Makefile如下:

Kconfig如下,我的内核.config配置选中了PWM和PWM_IMX,因此编译进了内核镜像。


1.2 数据结构#
1.2.1 pwm_chip#
是对一个pwm控制器的抽象。
1 | struct pwm_chip { |
1.2.2 pwm_ops#
pwm控制器的操作接口。
1 | struct pwm_ops { |
1.2.3 pwm_state#
pwm_state就是控制占空比控制转速,亮度参数。
1 | struct pwm_state { |
1.3 API#
api声明见linux\include\linux\pwm.h,实现linux\drivers\pwm\core.c
1.3.1 pwmchip_add#
向pwm子系统注册一个pwm_chip。
int pwmchip_add(struct pwm_chip *chip);
1 | pwmchip_add |

1.3.2 pwmchip_remove#
int pwmchip_remove(struct pwm_chip *chip);
删除一个pwm_chip。

1.3.3 pwm_request#
请求 PWM。
struct pwm_device *pwm_request(int pwm, const char *label)


可以看到就是调用具体pwm示例的request函数。
1.3.4 pwm_free#
释放 PWM。
void pwm_free(struct pwm_device *pwm)

1.3.5 pwm_config#
配置 PWM 周期和占空比,操作具体pwm实例。
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)

1.3.6 pwm_set_polarity#
设置 PWM 极性。
int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)

1.3.6 pwm_enable#

1.3.7 pwm_disable#

从1.3.3到1.3.7本质都是调用pwm_ops。
2 pwm驱动实例#
I.MX6ULL 有 8 路 PWM 控制器。这 8 路 PWM 都属于I.MX6ULL 的 AIPS-1域,但是在设备树imx6ull.dtsi中 分为了两部分,PWM1~PWM4 在一起,PWM5~PWM8 在一起。以pwm3为例:
2.1 dts描述#
打开imx6ull.dtsi:可以看到pwm3的描述:
1 | pwm3: pwm@02088000 { |
关 于I.MX6ULL的PWM dts节点描述参考对应的绑定文档 : Documentation/devicetree/bindings/pwm/ imx-pwm.txt
GPIO1_IO04 这里作为PWM3的输出引脚,所以我们需要在设备树里面添加 GPIO1_IO04 的引脚信息以及PWM3控制器对应的节点信息:
打开 imx6ull-alientek-emmc.dts, 添加iomux配置信息:
1 | pinctrl_pwm3: pwm3grp { |
1 | &pwm3 { |
2.2 使能PWM驱动#

从.config中已经使能了,但是为了学习, 我们还是需要知道怎么使能。

1 | -> Device Drivers |
2.3 PWM 背光设置#
linux 内核里面关于 backlight(背光)的绑定文档,路径为 Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt,此文档描述了如何创建 backlight 节点来使用linux内核自带的pwm背光驱动。
1 | compatible:内容必须为“pwm-backlight”,通过这个可以匹配到内核自带的 PWM 背光驱 |
1 | backlight { |
2.4 驱动源码分析#
2.4.1 probe过程#
2.4.1.1 imx_chip#

定义了imx_chip,包装了pwm_chip结构。

probe时,先分配内存,从dts获取per, ipg等时钟信息,设置pwm的ops为imx_pwm_ops。最后pwmchip_add注册进pwm子系统。注意这里有一个of_id->data,对应如下:可以看到有v1,v2两2版本,到时候会被ops中的函数调用。

同理,驱动卸载最后调用pwmchip_remove注销pwm。

2.4.2 imx_pwm_ops#

2.4.2.1 imx_pwm_config#
配置 PWM 周期和占空比。根据dts描述(”imx27-pwm“)我们使用的是v2。



PWMv2会有4 word的采样fifo, 为了避免采样FIFO溢出,当pwm关闭时,对所有采样FIFO进行软件复位。当pwm使能后处于工作中,要等待完整的 PWM 周期以保证pwm空闲。
然后设置PWM 周期period_cycles,和占空比duty_cycles。
最后调用writel写入寄存器。

2.4.2.2 imx_pwm_enable#
控制MX3_PWMCR寄存器,使能关闭开关。


2.4.2.3 imx_pwm_disable#

3 基于pwm sysfs测试#
alpha开发板 JP2 排针上的 GPIO_4(GPIO1_IO04)引脚连接到 示波器上。等下看pwm信号效果。
可以看到一共8 路 PWM 控制器:

我们使用的pwm3,对应出 pwmchip2, 导出chip2通道的0设备文件:
1 | echo 0 > /sys/class/pwm/pwmchip2/export |
执行完成会在pwmchip2 目录下生成一个名为“pwm0”的子目录:

1 | echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable #使能pwm3 |

总结:
1 | 导出chip1通道的0设备文件:echo 0 > /sys/class/pwm/pwmchip1/export |