How to enable PWM output on Dragonboard 410c (Pin MPP4)


#1

If someone need, here are instruction how to handle PWM output on (MPP4 pin, LS_EXP_GPIO_F) on Dragonboard. This works under latest official Android version (vLA.BR.1.2.7-01010-8x16.0-4).

Here is example how to set up PWM output with 75kHz frequency, 6-bit PWM, with 50% duty ratio:

cd /sys/kernel/debug/spmi/spmi-0
echo “0x0001BC41” > address
echo “10” > count
echo “0x03” “0x02” “0x00” “0x20” “0x00” “0x80” “0x01” > data_raw

echo “0x0000A340” > address
echo “0x18” > data_raw

For reference check:
PM8916 Hardware Register Description - Section 71 - PWM_SLICE and Section 36 MPP4.
Below I described register bit values as guideline:

PWM_PWM_SIZE_CLK: 0 = 6-bit PWM
PWM_FREQ_CLK_SELECT: 11 = 19.2 MHz
PWM_FREQ_PRE_DIVIDE: 00 = 1
PWM_FREQ_EXPONENT: 002 = 2

PWM frequency is set according to the flowing equation:
PWM_FREQ = PWM_FREQ_CLK_SELECT / (2^PWM_SIZE * 2^PWM_FREQ_EXPONENT * PWM_FREQ_PRE_DIVIDE) = 19.2e6/(2^62^21)=75kHz

Following bits should be set in order to work:
EN_GLITCH_REMOVAL: 0x0: GLITCH_REMOVE_DIS
PWM_PWM_VALUE_LSB: 0x00 ÷ 0x3F Use this register to change PWM width (0 ÷ 100 %)
PWM_ENABLE_CONTROL: 0x1: PWM_ENABLE
SYNC_PWM Write 0x01 to this register - will update the PWM value. You need to writre 0x01 each time you change PWM_PWM_VALUE!

MPP4_MODE_CTL - MODE: 0x1: DIGITAL_OUTPUT
MPP4_MODE_CTL - EN_AND_SOURCE_SEL: 1000 = DTEST1


#2

An alternative approach is to apply the latest patches posted on LKML for the LPG/PWM driver. This gives a slightly more user friendly interface, although I have not attempted to apply them onto the Android kernel…

The patches can be found here:

https://patchwork.kernel.org/patch/10058879/
https://patchwork.kernel.org/patch/10058887/
https://patchwork.kernel.org/patch/10058881/

The last patch includes an example of the DT node.

Regards,
Bjorn


#3

I’m confused about the muxing. How should the muxing be configured ?

As far as I understand leds-qcom-lpg.txt is schould be something like:

&pm8916_mpps {
pinctrl-names = “default”;
pinctrl-0 = <&lpwm_backlight>;

        pwm_backlight: pm8916_mpp4 {
    	pinconf {
    		pins = "mpp4";
    		function = "digital";
    		output-low;
    		power-source = <PM8916_MPP_L5>;	// 1.8V
            dtest = ???
        };
    };
 };

&spmi_bus {
	pm8916@1 {
		pm8916_pwm: pwm {
			compatible = "qcom,pm8916-pwm";
                        qcom,dtest = ???
    		#pwm-cells = <2>;
    	};
    };
};

There is further a MPP GPIO configuration for MPP1 - MPP4:

	pm8916_mpps: mpps@a000 {
		compatible = "qcom,pm8916-mpp";
		reg = <0xa000>;
		gpio-controller;
		#gpio-cells = <2>;
		interrupts = <0 0xa0 0 IRQ_TYPE_NONE>,
			     <0 0xa1 0 IRQ_TYPE_NONE>,
			     <0 0xa2 0 IRQ_TYPE_NONE>,
			     <0 0xa3 0 IRQ_TYPE_NONE>;
	};

My questions:

  1. What exactly is dtest? How does the routing sink/source work?
  2. What has to be configured in pm8916_mpps and in pm8916_pwm, both seem to have a dtest parameter.
  3. The MPP block configures and registers all 4 pins as GPIO. If I use MPP4 as PWM, should MPP4 be removed with MPP1 - MPP3 keeping the GPIO functionality? Or should I rather remove the GPIO configuration?
  4. Is just MPP4 available for PWM function?

My datasheet seems to be incomplete. There is no explanation about that DTEST stuff. Further I did not have any specification about the registers PWM_DTEST_REG(x) that seems to make that config.

More specific:

LPG/PWM driver:

I need morde background about this function:

static void lpg_apply_dtest(struct lpg_channel *chan)
{
	struct lpg *lpg = chan->lpg;

	if (!chan->dtest_line)
		return;

	regmap_write(lpg->map, chan->base + PWM_SEC_ACCESS_REG, 0xa5);
	regmap_write(lpg->map, chan->base + PWM_DTEST_REG(chan->dtest_line),
		     chan->dtest_value);
}

This seems to be the output cndiguration of the PWM unit.

Does this mean:

qcom, dtest = <1 0> // leds-qcom-lpg.txt: ... and the second
	                           // configures how the value should be outputed ...

for pn8916 to route the PWM output via DTEST1 to MPP4 ?

Further, Irvin wrote:

MPP4_MODE_CTL - EN_AND_SOURCE_SEL: 1000 = DTEST1

Does this mean

qcom,dtest = <1>

for MPP4 pin in the MPP pinconf driver?

If not, what else?

I found this in the old 3.18 PWM driver (https://source.codeaurora.org/quic/la/kernel/msm-3.18/tree/drivers/pwm/pwm-qpnp.c?h=LA.BR.5.6):

/* PWM DTEST */
#define QPNP_PWM_DTEST_LINE_MAX 2
#define QPNP_PWM_DTEST_OUTPUT_MAX 2
#define QPNP_PWM_DTEST_OUTPUT_MASK 0x03

So, dtest_line seems to be 1 or 2 and dtest_config 0 … 2.

@bamse @irvin Can you help?

Best regards
-Carsten

Update:

Got it working by myself (current 4.9.x kernel):

arch/arm64/boot/dts/qcom/pm8916.dtsi (settings untouched):

    ....
	pm8916_mpps: mpps@a000 {
		compatible = "qcom,pm8916-mpp";
		reg = <0xa000>;
		gpio-controller;
		#gpio-cells = <2>;
		interrupts = <0 0xa0 0 IRQ_TYPE_NONE>,
			     <0 0xa1 0 IRQ_TYPE_NONE>,
			     <0 0xa2 0 IRQ_TYPE_NONE>,
			     <0 0xa3 0 IRQ_TYPE_NONE>;
	};
   ....

arch/arm64/boot/dts/qcom/apq8016-myboard-pmic-pins.dtsi:

&pm8916_mpps {
pinctrl-names = “default”;
pinctrl-0 = <&pwm_backlight>;

pwm_backlight: pm8916_mpp4 {
	pinconf {
		pins = "mpp4";
		function = "digital"; // see 96boards issue #3732
		qcom,dtest = <1>; // see 96boards issue #3732
		output-low;
		power-source = <PM8916_MPP_L5>;	// 1.8V
	};
};

pm8916_mpps_leds: pm8916_mpps_leds {
	pinconf {
		pins = "mpp2", "mpp3";
		function = "digital";
		output-low;
	};
};

};

....
&spmi_bus {
    pm8916@1 {
	    pm8916_pwm: pwm {
		    compatible = "qcom,pm8916-pwm";
		    qcom,dtest = <1 1>; // see 96boards issue #3732
		    #pwm-cells = <2>;
	    };
    };
};

Best regards
-Carsten


#6

Glad to see that you got it working Carsten.

DTEST is a set of lines internal to the pmic that can be used to route outputs of blocks to some inputs of other blocks. In this particular case the PWM signal is available on DTEST 1 and the mpp should be configured to use this line as control signal.

As such it should be possible (and I think I tested this) to route this signal to the other mpps (and multiple mpps at the same time).

Regards,
Bjorn