Message ID | 20220216045620.1716537-1-bjorn.andersson@linaro.org |
---|---|
State | Not Applicable, archived |
Headers | show |
Series | [v12,1/2] dt-bindings: leds: Add Qualcomm Light Pulse Generator binding | expand |
Hi Bjorn, On Mittwoch, 16. Februar 2022 05:56:20 CET Bjorn Andersson wrote: > The Light Pulse Generator (LPG) is a PWM-block found in a wide range of > PMICs from Qualcomm. These PMICs typically comes with 1-8 LPG instances, > with their output being routed to various other components, such as > current sinks or GPIOs. > > Each LPG instance can operate on fixed parameters or based on a shared > lookup-table, altering the duty cycle over time. This provides the means > for hardware assisted transitions of LED brightness. > > A typical use case for the fixed parameter mode is to drive a PWM > backlight control signal, the driver therefor allows each LPG instance > to be exposed to the kernel either through the LED framework or the PWM > framework. > > A typical use case for the LED configuration is to drive RGB LEDs in > smartphones etc, for which the driver supports multiple channels to be > ganged up to a MULTICOLOR LED. In this configuration the pattern > generators will be synchronized, to allow for multi-color patterns. > > The idea of modelling this as a LED driver ontop of a PWM driver was > considered, but setting the properties related to patterns does not fit > in the PWM API. Similarly the idea of just duplicating the lower bits in > a PWM and LED driver separately was considered, but this would not allow > the PWM channels and LEDs to be configured on a per-board basis. The > driver implements the more complex LED interface, and provides a PWM > interface on the side of that, in the same driver. > > Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Works great on pm8941 / msm8974-fairphone-fp2! Tested-by: Luca Weiss <luca@z3ntu.xyz> Regards Luca > --- > > Changes since v11: > - Extended commit message to cover decision to put pwm_chip in the LED > driver - Added Documentation, in particular for the hw_pattern format > - Added a lock to synchronize requests from LED and PWM frameworks > - Turned out that the 9bit selector differs per channel in some PMICs, so > replaced bitmask in lpg_data with lookup based on QPNP SUBTYPE > - Fixed kerneldoc for the struct device pointer in struct lpg > - Rewrote conditional in lut_free() to make it easier to read > - Corrected and deduplicated max_period expression in lpg_calc_freq() > - Extended nom/dom to numerator/denominator in lpg_calc_freq() > - Replaced 1 << 9 with LPG_RESOLUTION in one more place in lpg_calc_freq() > - Use FIELD_PREP() in lpg_apply_freq() as masks was introduced for reading > the same in get_state() > - Cleaned up the pattern format, to allow specifying both low and high pause > with and without pingpong mode. > - Only update frequency and pwm_value if PWM channel is enabled in > lpg_pwm_apply - Make lpg_pwm_get_state() read the hardware state, in order > to pick up e.g. bootloader backlight configuration > - Use devm_bitmap_zalloc() to allocate the lut_bitmap > - Use dev_err_probe() in lpg_probe() > - Extended Kconfig help text to mention module name and satisfy checkpatch > > Documentation/leds/leds-qcom-lpg.rst | 76 ++ > drivers/leds/Kconfig | 3 + > drivers/leds/Makefile | 3 + > drivers/leds/rgb/Kconfig | 18 + > drivers/leds/rgb/Makefile | 3 + > drivers/leds/rgb/leds-qcom-lpg.c | 1401 ++++++++++++++++++++++++++ > 6 files changed, 1504 insertions(+) > create mode 100644 Documentation/leds/leds-qcom-lpg.rst > create mode 100644 drivers/leds/rgb/Kconfig > create mode 100644 drivers/leds/rgb/Makefile > create mode 100644 drivers/leds/rgb/leds-qcom-lpg.c
Hi, On Tue, Feb 15, 2022 at 8:54 PM Bjorn Andersson <bjorn.andersson@linaro.org> wrote: > > +static int lpg_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, > + const struct pwm_state *state) > +{ > + struct lpg *lpg = container_of(chip, struct lpg, pwm); > + struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; > + int ret; > + > + if (state->polarity != PWM_POLARITY_NORMAL) > + return -EINVAL; > + > + mutex_lock(&lpg->lock); > + > + if (state->enabled) { > + ret = lpg_calc_freq(chan, state->period); > + if (ret < 0) > + goto out_unlock; > + > + lpg_calc_duty(chan, state->duty_cycle); > + } > + chan->enabled = state->enabled; > + > + lpg_apply(chan); > + > + triled_set(lpg, chan->triled_mask, chan->enabled ? chan->triled_mask : 0); > + > +out_unlock: > + mutex_unlock(&lpg->lock); > + > + return ret; > +} My compiler (correctly) yelled that `ret` is returned uninitialized if `state->enabled` is false. I initialized `ret` to 0 and the problem went away. I assume that the patch will need to spin to fix that unless everything else looks great and a maintainer wants to fix that when applying. With that fix, I was able to use Bjorn's patch along with Satya's patches adding pm8350c support (removing the now defunct "pwm_9bit_mask" property) to make the PWM on my board work. Thus, once the error my compiler complained about is fixed I'm happy with my `Tested-by` being added. For now I haven't actually reviewed the code here, but if folks feel like it needs an extra pair of eyes then please yell and I'll find some time to do it. -Doug
On Fri 18 Feb 08:10 PST 2022, Doug Anderson wrote: > Hi, > > On Tue, Feb 15, 2022 at 8:54 PM Bjorn Andersson > <bjorn.andersson@linaro.org> wrote: > > > > +static int lpg_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, > > + const struct pwm_state *state) > > +{ > > + struct lpg *lpg = container_of(chip, struct lpg, pwm); > > + struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; > > + int ret; > > + > > + if (state->polarity != PWM_POLARITY_NORMAL) > > + return -EINVAL; > > + > > + mutex_lock(&lpg->lock); > > + > > + if (state->enabled) { > > + ret = lpg_calc_freq(chan, state->period); > > + if (ret < 0) > > + goto out_unlock; > > + > > + lpg_calc_duty(chan, state->duty_cycle); > > + } > > + chan->enabled = state->enabled; > > + > > + lpg_apply(chan); > > + > > + triled_set(lpg, chan->triled_mask, chan->enabled ? chan->triled_mask : 0); > > + > > +out_unlock: > > + mutex_unlock(&lpg->lock); > > + > > + return ret; > > +} > > My compiler (correctly) yelled that `ret` is returned uninitialized if > `state->enabled` is false. You're absolutely correct. I am however not able to figure out how to get my compiler (aarc64 gcc 11.2.0) to give me a warning about this. If anyone have any suggestions I'd be very happy. > I initialized `ret` to 0 and the problem > went away. I assume that the patch will need to spin to fix that > unless everything else looks great and a maintainer wants to fix that > when applying. > > With that fix, I was able to use Bjorn's patch along with Satya's > patches adding pm8350c support (removing the now defunct > "pwm_9bit_mask" property) to make the PWM on my board work. Thus, once > the error my compiler complained about is fixed I'm happy with my > `Tested-by` being added. > Thanks! I will initialize ret and send out v13 including your T-b. Regards, Bjorn > For now I haven't actually reviewed the code here, but if folks feel > like it needs an extra pair of eyes then please yell and I'll find > some time to do it. > > -Doug
diff --git a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml new file mode 100644 index 000000000000..336bd8e10efd --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml @@ -0,0 +1,173 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/leds-qcom-lpg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Light Pulse Generator + +maintainers: + - Bjorn Andersson <bjorn.andersson@linaro.org> + +description: > + The Qualcomm Light Pulse Generator consists of three different hardware blocks; + a ramp generator with lookup table, the light pulse generator and a three + channel current sink. These blocks are found in a wide range of Qualcomm PMICs. + +properties: + compatible: + enum: + - qcom,pm8150b-lpg + - qcom,pm8150l-lpg + - qcom,pm8916-pwm + - qcom,pm8941-lpg + - qcom,pm8994-lpg + - qcom,pmc8180c-lpg + - qcom,pmi8994-lpg + - qcom,pmi8998-lpg + + "#pwm-cells": + const: 2 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + qcom,power-source: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + power-source used to drive the output, as defined in the datasheet. + Should be specified if the TRILED block is present + enum: [0, 1, 3] + + qcom,dtest: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + description: > + A list of integer pairs, where each pair represent the dtest line the + particular channel should be connected to and the flags denoting how the + value should be outputed, as defined in the datasheet. The number of + pairs should be the same as the number of channels. + items: + items: + - description: dtest line to attach + - description: flags for the attachment + + multi-led: + type: object + $ref: leds-class-multicolor.yaml# + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^led@[0-9a-f]$": + type: object + $ref: common.yaml# + +patternProperties: + "^led@[0-9a-f]$": + type: object + $ref: common.yaml# + + properties: + reg: true + + required: + - reg + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include <dt-bindings/leds/common.h> + + led-controller { + compatible = "qcom,pmi8994-lpg"; + + #address-cells = <1>; + #size-cells = <0>; + + qcom,power-source = <1>; + + qcom,dtest = <0 0>, + <0 0>, + <0 0>, + <4 1>; + + led@1 { + reg = <1>; + color = <LED_COLOR_ID_GREEN>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <1>; + }; + + led@2 { + reg = <2>; + color = <LED_COLOR_ID_GREEN>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <0>; + default-state = "on"; + }; + + led@3 { + reg = <3>; + color = <LED_COLOR_ID_GREEN>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <2>; + }; + + led@4 { + reg = <4>; + color = <LED_COLOR_ID_GREEN>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <3>; + }; + }; + - | + #include <dt-bindings/leds/common.h> + + led-controller { + compatible = "qcom,pmi8994-lpg"; + + #address-cells = <1>; + #size-cells = <0>; + + qcom,power-source = <1>; + + multi-led { + color = <LED_COLOR_ID_RGB>; + function = LED_FUNCTION_STATUS; + + #address-cells = <1>; + #size-cells = <0>; + + led@1 { + reg = <1>; + color = <LED_COLOR_ID_RED>; + }; + + led@2 { + reg = <2>; + color = <LED_COLOR_ID_GREEN>; + }; + + led@3 { + reg = <3>; + color = <LED_COLOR_ID_BLUE>; + }; + }; + }; + - | + pwm-controller { + compatible = "qcom,pm8916-pwm"; + #pwm-cells = <2>; + }; +...