# PWM输出 ## PWM驱动 dtsi: 增加PWM0,1的引脚 ~~~ pwm0_pins: pwm0 { pins = "PB4"; function = "pwm0"; }; pwm1_pins: pwm1 { pins = "PB5"; function = "pwm1"; }; ~~~ ~~~ pwm: pwm@01c21400 { compatible = "allwinner,sun7i-a20-pwm"; //这里选a20是因为v3s和a20一样有两路pwm reg = <0x01c21400 0xC>; clocks = <&osc24M>; #pwm-cells = <3>; status = "okay"; }; ~~~ dts中使能PWM: ~~~ &pwm { pinctrl-names = "default"; pinctrl-0 = <&pwm0_pins>, <&pwm1_pins>; status = "okay"; }; ~~~ sysfs里使能: ~~~ echo 0 > /sys/class/pwm/pwmchip0/export echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable echo 1 > /sys/class/pwm/pwmchip0/export echo 1000000 > /sys/class/pwm/pwmchip0/pwm1/period echo 200000 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle echo 1 > /sys/class/pwm/pwmchip0/pwm1/enable //注意一定要配置好参数后再使能,否则会报参数错误 ~~~ polarity:接受normal或inversed两个参数. period:表示pwm波的周期(单位:纳秒); duty_cycle:在normal模式下,表示一个周期内高电平持续的时间(单位:纳秒),所以duty_cycle <= period;在reversed模式下,表示一个周期中低电平持续的时间(单位:纳秒); enable:向其中写入1表示启动pwm,写入0,表示关闭pwm; 注意V3S的PWM由24M分频而来,无法生成太高频的pwm。 ## PWM驱动分析 PWM驱动在drivers/pwm/pwm-sun4i.c中。 插入驱动: ~~~ static int sun4i_pwm_probe(struct platform_device *pdev) { struct sun4i_pwm_chip *pwm; struct resource *res; int ret; const struct of_device_id *match; match = of_match_device(sun4i_pwm_dt_ids, &pdev->dev); //在设备树中查找节点 pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); if (!pwm) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pwm->base = devm_ioremap_resource(&pdev->dev, res); //申请寄存器的内存空间 if (IS_ERR(pwm->base)) return PTR_ERR(pwm->base); pwm->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pwm->clk)) return PTR_ERR(pwm->clk); pwm->data = match->data; pwm->chip.dev = &pdev->dev; pwm->chip.ops = &sun4i_pwm_ops; pwm->chip.base = -1; pwm->chip.npwm = pwm->data->npwm; pwm->chip.of_xlate = of_pwm_xlate_with_flags; pwm->chip.of_pwm_n_cells = 3; spin_lock_init(&pwm->ctrl_lock); ret = pwmchip_add(&pwm->chip); //在/sys/class/pwm/下创建pwmchip0X if (ret < 0) { dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); return ret; } platform_set_drvdata(pdev, pwm); return 0; } ~~~