9. PWM Use

9.1. Introduction

Firefly-RK3288 development board has 4-way PWM outputs, which are PWM0 ~ PWM3, this chapter mainly describes how to configure PWM.

The PWM driver file:

kernel/drivers/pwm/pwm-rockchip.c

9.2. Data structure

9.2.1. pwm_device structure

struct pwm_device {
    const char      *label;
    unsigned long       flags;
    unsigned int        hwpwm;
    unsigned int        pwm;//pwm channel
    struct pwm_chip     *chip;
    void            *chip_data;
    unsigned int        period; /* in nanoseconds */
};

9.2.2. pwm_chip structure

This structure is a abstract PWM controller.

struct pwm_chip {
    struct device       *dev; //provide PWM device
    struct list_head    list; //internally used node list
    const struct pwm_ops    *ops; //callback function of this PWM controller
    int  base; //number of the first PWM controlled by this device
    unsigned int        npwm; //number of PWMs controlled by this device
    struct pwm_device   *pwms;
    struct pwm_device * (*of_xlate)(struct pwm_chip *pc,const struct of_phandle_args *args);
    unsigned int of_pwm_n_cells;
    bool can_sleep;
};

9.3. Configuration steps

Configuration of PWM mainly includes the following three steps: configure PWM DTS nodes, configure PWM kernel driver, and control PWM device.

9.3.1. Configure PWM DTS node

The following PWM nodes are defined in kernel/arch/arm/boot/dts/rk3288.dtsi, as shown below:

pwm1: pwm@ff680010 {
      compatible = "rockchip,rk-pwm";
      reg = ;
      #pwm-cells = ;
      pinctrl-names = "default";
      pinctrl-0 = ;
      clocks = ;
      clock-names = "pclk_pwm";
      status = "okay";
};

Note: ff680010 is the address of PWM1 register.

In order to use pwm1, add it into kernel/arch/arm/boot/dts/firefly-rk3288.dts:

&pwm1 {
    status = "okay";
};

9.4. Configure PWM kernel driver

PWM driver is located on the file kernel/drivers/pwm/pwm-rockchip.c.

Modify the following codes of this file:

static const struct of_device_id rk_pwm_of_match[] = {
    { .compatible = "rockchip,pwm",       .data = &rk_pwm_data_v1,},
    { .compatible =  "rockchip,rk-pwm",   .data = &rk_pwm_data_v2,},
    { .compatible =  "rockchip,vop-pwm",  .data = &rk_pwm_data_v3,},
    { }
};

Add the compatible = “rockchip,rk-pwm” in the previous step to the above code.

9.5. Control PWM device

The user can use the PWM node generated from the above steps in the other driver file. The specific methods are as follows:

9.5.1. (1) Include the following header file into the device driver files to be controlled by PWM

#include <linux/pwm.h>

This header file mainly includes PWM function interface.

9.5.2. (2) Request for PWM

struct pwm_device *pwm_request(int pwm_id, const char *label);

Function requests for PWM. For example:

struct pwm_device * pwm0 = NULL;
pwm0 = pwm_request(0, “backlight-pwm”);

Parameter pwm_id represents the channel for which PWM is to be requested, label is the label taken by this PWM.

9.5.3. (3) Configure PWM

int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);

Configure duty ratio of PWM, for example:

pwm_config(pwm0, 500000, 1000000);

Parameter pwm represents the pwm_device requested in the previous step. duty_ns represents the activating duration of duty ratio, and its unit is ns. period_ns represents the period of PWM, and its unit is ns.

9.5.4. (4) PWM enabling function

int pwm_enable(struct pwm_device *pwm);

It is used for enabling PWM, for example:

pwm_enable(pwm0);

Parameter pwm represents the pwm_device to be enabled.

Controlling PWM output mainly uses the following interface functions:

struct pwm_device *pwm_request(int pwm_id, const char *label);
  • Function: for requesting pwm

  • Parameter:

    • pwm_id: pwm channel to be requested.

    • label: label taken by the pwm requested.

void pwm_free(struct pwm_device *pwm);
  • Function: for releasing the requested pwm

  • Parameter:

    • pwm: pwm structure to be released

int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
  • Function: for configuring the duty ratio of pwm

  • Parameter:

    • pwm: pwm to be configured

    • duty_ns: activated duration of pwm duty ratio, the unit is ns

    • period_ns: period of pwm duty ratio, the unit is ns

int pwm_enable(struct pwm_device *pwm);
  • Function: enable pwm

  • Parameter:

    • pwm: pwm to be enabled

void pwm_disable(struct pwm_device *pwm); 
  • Function: forbid pwm

  • Parameter:

    • pwm: pwm to be forbidden