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