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;
}