Search code examples
linux-kernelraspberry-pilinux-device-driverkernel-module

rpi - pwm_get() - how to use static lookup tables or device-tree


I have a Raspberry Pi 3B with two motors on pwmchip0 (pwm0/pwm1). I successfully controlled the pwm-chip through sysfs, but now I want to put it inside a kernel module.

I saw <linux/pwm.h> and would like to use pwm_get(),pwm_put() and pwm_config(). I found this post and also dug through the examples on LXR, but it didn't quite help me. I am very new to device-trees and kernel programming in general. I am failing to request the pwm_device (ERR=1) but I can't figure out the problem.

  • What do I have to specify for consumer_id?
  • Do I even have to modify the device tree or add a static lookup table?
    • And if so how?

I have created a device tree overlay, but thant didn't work :/

/dts-v1/;
/include/ "bcm283x.dtsi"
/ {
        compatible = "brcm,bcm2708";
        motor-left-pwm {
                compatible = "motor-left";
                pwms = <&pwm 0 1000000 0>;
                pinctrl-names = "default";
        };
};

I tried adding a static lookup table:

static struct pwm_lookup crc_pwm_lookup[] = {
    PWM_LOOKUP("pwmchip0", 0, "0000:00:02.0", "pwm_left", 0>
    PWM_LOOKUP("pwmchip0", 1, "0000:00:02.0", "pwm_right", >
};

pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));

But ended up with this:

WARNING: "pwm_add_table" [/home/josh/drivers/motor/motor.ko] undefined!

insmod: ERROR: could not insert module /motor.ko: Unknown symbol in module

I read somewhere that means I cannot call this function :/


Solution

  • Yesss! Yesterday night I figured it out!

    I guess I simply didn't understand the device tree and overlays at all. But I worked out this, with help of the pwm-2chan.dts:

    /dts-v1/;
    /plugin/;
    / {
            fragment@0 {
                    target = <&soc>;
                    __overlay__ {
                    motorpwm {
                            compatible = "motor";
                            pwms = <&pwm 0 1000000>;
                            pinctrl-names = "default";
                            pinctrl-0 = <&pwm0_gpio18>;
                    };
                    };
            };
    
            fragment@1 {
                    target = <&pwm>;
                    frag1: __overlay__ {
                            status = "okay";
                    };
            };
    };
    

    Then your driver will be probed:

    static int my_probe(struct platform_device *pdev)
    {
        printk("Probed");
        printk("Requesting PWM");
        pwm_left = pwm_get(&pdev->dev, NULL);
        if (IS_ERR(pwm_left)){
            printk("Requesting PWM failed %d", ERR_CAST(pwm_left));
            return -EIO;
        }
        printk("Requested PWM");
        return 0;
    }
    
    static int my_remove(struct platform_device *dev)
    {
        printk("Removed");
        return 0;
    }
    
    
    static struct of_device_id my_match_table[] = {
         {
                 .compatible = "motor",
         },
         {},
    };
    MODULE_DEVICE_TABLE(of, my_match_table);
    
    static struct platform_driver my_platform_driver = {
        .probe = my_probe,
        .remove = my_remove,
        .driver = {
            .name = "motor",
            .owner = THIS_MODULE,
            .of_match_table = of_match_ptr(my_match_table),
        },
    };