Message ID | 20230725193423.25047-1-quic_amelende@quicinc.com |
---|---|
Headers | show |
Series | Add support for LUT PPG | expand |
On 25/07/2023 21:34, Anjelique Melendez wrote: > Add binding for the Qualcomm Programmable Boot Sequencer device. > > Signed-off-by: Anjelique Melendez <quic_amelende@quicinc.com> > --- > .../bindings/soc/qcom/qcom-pbs.yaml | 40 +++++++++++++++++++ > 1 file changed, 40 insertions(+) > create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml Again not tested. Also, you missed comments. :( This is a friendly reminder during the review process. It seems my previous comments were not fully addressed. Maybe my feedback got lost between the quotes, maybe you just forgot to apply it. Please go back to the previous discussion and either implement all requested changes or keep discussing them. Thank you. Best regards, Krzysztof
On 25.07.2023 21:34, Anjelique Melendez wrote: > Add the Qualcomm PBS (Programmable Boot Sequencer) driver. The QCOM PBS > driver supports configuring software PBS trigger events through PBS RAM > on Qualcomm Technologies, Inc (QTI) PMICs. > > Signed-off-by: Anjelique Melendez <quic_amelende@quicinc.com> > --- [...] > + > + u32 base; > +}; > + > +static int qcom_pbs_read(struct pbs_dev *pbs, u32 address, u8 *val) > +{ > + int ret; > + > + address += pbs->base; Any reason not to just keep the base address in struct pbs_dev and use normal regmap r/w helpers? [...] > + > +static int qcom_pbs_wait_for_ack(struct pbs_dev *pbs, u8 bit_pos) > +{ > + u16 retries = 2000, delay = 1000; > + int ret; > + u8 val; > + > + while (retries--) { > + ret = qcom_pbs_read(pbs, PBS_CLIENT_SCRATCH2, &val); > + if (ret < 0) > + return ret; > + > + if (val == 0xFF) { This should be a constant, not a magic value > + /* PBS error - clear SCRATCH2 register */ > + ret = qcom_pbs_write(pbs, PBS_CLIENT_SCRATCH2, 0); > + if (ret < 0) > + return ret; > + > + dev_err(pbs->dev, "NACK from PBS for bit %u\n", bit_pos); > + return -EINVAL; > + } > + > + if (val & BIT(bit_pos)) { > + dev_dbg(pbs->dev, "PBS sequence for bit %u executed!\n", bit_pos); > + break; > + } > + > + usleep_range(delay, delay + 100); So worst case scenario this will wait for over 2 seconds? > + } > + > + if (!retries) { > + dev_err(pbs->dev, "Timeout for PBS ACK/NACK for bit %u\n", bit_pos); > + return -ETIMEDOUT; > + } > + > + return 0; return 0 instead of break above? > +} > + > +/** > + * qcom_pbs_trigger_event() - Trigger the PBS RAM sequence > + * @pbs: Pointer to PBS device > + * @bitmap: bitmap > + * > + * This function is used to trigger the PBS RAM sequence to be > + * executed by the client driver. > + * > + * The PBS trigger sequence involves > + * 1. setting the PBS sequence bit in PBS_CLIENT_SCRATCH1 > + * 2. Initiating the SW PBS trigger > + * 3. Checking the equivalent bit in PBS_CLIENT_SCRATCH2 for the > + * completion of the sequence. > + * 4. If PBS_CLIENT_SCRATCH2 == 0xFF, the PBS sequence failed to execute > + * > + * Returns: 0 on success, < 0 on failure > + */ > +int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap) > +{ > + u8 val, mask; > + u16 bit_pos; > + int ret; > + > + if (!bitmap) { > + dev_err(pbs->dev, "Invalid bitmap passed by client\n"); > + return -EINVAL; > + } > + > + if (IS_ERR_OR_NULL(pbs)) > + return -EINVAL; > + > + mutex_lock(&pbs->lock); > + ret = qcom_pbs_read(pbs, PBS_CLIENT_SCRATCH2, &val); > + if (ret < 0) > + goto out; > + > + if (val == 0xFF) { > + /* PBS error - clear SCRATCH2 register */ > + ret = qcom_pbs_write(pbs, PBS_CLIENT_SCRATCH2, 0); > + if (ret < 0) > + goto out; > + } > + > + for (bit_pos = 0; bit_pos < 8; bit_pos++) { > + if (bitmap & BIT(bit_pos)) { > + /* > + * Clear the PBS sequence bit position in > + * PBS_CLIENT_SCRATCH2 mask register. > + */ Don't think the "in the X register" parts are useful. > + ret = qcom_pbs_masked_write(pbs, PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0); > + if (ret < 0) > + goto error; > + > + /* > + * Set the PBS sequence bit position in > + * PBS_CLIENT_SCRATCH1 register. > + */ > + val = mask = BIT(bit_pos); You're using mask/val for half the function calls.. Stick with one approach. [...] > +struct pbs_dev *get_pbs_client_device(struct device *dev) > +{ > + struct device_node *pbs_dev_node; > + struct platform_device *pdev; > + struct pbs_dev *pbs; > + > + pbs_dev_node = of_parse_phandle(dev->of_node, "qcom,pbs", 0); > + if (!pbs_dev_node) { > + dev_err(dev, "Missing qcom,pbs property\n"); > + return ERR_PTR(-ENODEV); > + } > + > + pdev = of_find_device_by_node(pbs_dev_node); > + if (!pdev) { > + dev_err(dev, "Unable to find PBS dev_node\n"); > + pbs = ERR_PTR(-EPROBE_DEFER); > + goto out; > + } > + > + pbs = platform_get_drvdata(pdev); > + if (!pbs) { This check seems unnecessary, the PBS driver would have had to fail probing if set_drvdata never got called. Konrad
On 7/26/2023 12:53 AM, Krzysztof Kozlowski wrote: > On 25/07/2023 21:34, Anjelique Melendez wrote: >> Add binding for the Qualcomm Programmable Boot Sequencer device. >> >> Signed-off-by: Anjelique Melendez <quic_amelende@quicinc.com> >> --- >> .../bindings/soc/qcom/qcom-pbs.yaml | 40 +++++++++++++++++++ >> 1 file changed, 40 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml > > > Again not tested. > > Also, you missed comments. :( > > This is a friendly reminder during the review process. > > It seems my previous comments were not fully addressed. Maybe my > feedback got lost between the quotes, maybe you just forgot to apply it. > Please go back to the previous discussion and either implement all > requested changes or keep discussing them. > > Thank you. > > > Best regards, > Krzysztof > Hi Krzysztof, Sorry about the testing, found that my dt_binding_checker was out dated and that is why it has not been picking up those dt_binding errors :/ I went back to take a look at the original comments I missed and just wanted to list them for a quick double check. 1. Rename binding to be qcom,pbs so that it matches compatible 2. Include Soc specific compatibles i.e. compatible: items: - enum: - qcom,pmi632-pbs - const: qcom,pbs 3. Fix the example node Thanks, Anjelique
On 7/25/2023 12:34 PM, Anjelique Melendez wrote: > +out: > + mutex_unlock(&pbs->lock); > + > + return ret; > +} > +EXPORT_SYMBOL(qcom_pbs_trigger_event); EXPORT_SYMBOL_GPL only please.
On Wed, Jul 26, 2023 at 05:36:08PM +0200, Konrad Dybcio wrote: > On 25.07.2023 21:34, Anjelique Melendez wrote: > > +struct pbs_dev *get_pbs_client_device(struct device *dev) > > +{ > > + struct device_node *pbs_dev_node; > > + struct platform_device *pdev; > > + struct pbs_dev *pbs; > > + > > + pbs_dev_node = of_parse_phandle(dev->of_node, "qcom,pbs", 0); > > + if (!pbs_dev_node) { > > + dev_err(dev, "Missing qcom,pbs property\n"); > > + return ERR_PTR(-ENODEV); > > + } > > + > > + pdev = of_find_device_by_node(pbs_dev_node); > > + if (!pdev) { > > + dev_err(dev, "Unable to find PBS dev_node\n"); > > + pbs = ERR_PTR(-EPROBE_DEFER); > > + goto out; > > + } > > + > > + pbs = platform_get_drvdata(pdev); > > + if (!pbs) { > This check seems unnecessary, the PBS driver would have had to fail > probing if set_drvdata never got called. > That's not necessarily the case, the platform_device will exist before the probe function has been invoked. So checking this sounds appropriate. But if we have a valid link, but no drvdata, perhaps it would be more appropriate to return -EPROBE_DEFER? Regards, Bjorn
On 7/26/2023 8:36 AM, Konrad Dybcio wrote: > On 25.07.2023 21:34, Anjelique Melendez wrote: >> Add the Qualcomm PBS (Programmable Boot Sequencer) driver. The QCOM PBS >> driver supports configuring software PBS trigger events through PBS RAM >> on Qualcomm Technologies, Inc (QTI) PMICs. >> >> Signed-off-by: Anjelique Melendez <quic_amelende@quicinc.com> >> --- > [...] > >> + >> + u32 base; >> +}; >> + >> +static int qcom_pbs_read(struct pbs_dev *pbs, u32 address, u8 *val) >> +{ >> + int ret; >> + >> + address += pbs->base; > Any reason not to just keep the base address in struct pbs_dev and use > normal regmap r/w helpers? > > [...] We created the qcom_pbs read/write helpers to limit code duplication when printing error messages. I am ok with calling regmap_bulk_read/write() and regmap_update_bits() in code instead of these helpers but wondering how everyone would feel with the error messages either being duplicated or if error messages should just be removed? qcom_pbs_read() is called twice, qcom_pbs_write() is called twice(), and qcom_pbs_masked_write() is called 6 times. > >> + >> +static int qcom_pbs_wait_for_ack(struct pbs_dev *pbs, u8 bit_pos) >> +{ >> + u16 retries = 2000, delay = 1000; >> + int ret; >> + u8 val; >> + >> + while (retries--) { >> + ret = qcom_pbs_read(pbs, PBS_CLIENT_SCRATCH2, &val); >> + if (ret < 0) >> + return ret; >> + >> + if (val == 0xFF) { > This should be a constant, not a magic value ack > >> + /* PBS error - clear SCRATCH2 register */ >> + ret = qcom_pbs_write(pbs, PBS_CLIENT_SCRATCH2, 0); >> + if (ret < 0) >> + return ret; >> + >> + dev_err(pbs->dev, "NACK from PBS for bit %u\n", bit_pos); >> + return -EINVAL; >> + } >> + >> + if (val & BIT(bit_pos)) { >> + dev_dbg(pbs->dev, "PBS sequence for bit %u executed!\n", bit_pos); >> + break; >> + } >> + >> + usleep_range(delay, delay + 100); > So worst case scenario this will wait for over 2 seconds? Yes, worst case scenario will result in waiting for 2.2 seconds > >> + } >> + >> + if (!retries) { >> + dev_err(pbs->dev, "Timeout for PBS ACK/NACK for bit %u\n", bit_pos); >> + return -ETIMEDOUT; >> + } >> + >> + return 0; > return 0 instead of break above? ack > >> +} >> + >> +/** >> + * qcom_pbs_trigger_event() - Trigger the PBS RAM sequence >> + * @pbs: Pointer to PBS device >> + * @bitmap: bitmap >> + * >> + * This function is used to trigger the PBS RAM sequence to be >> + * executed by the client driver. >> + * >> + * The PBS trigger sequence involves >> + * 1. setting the PBS sequence bit in PBS_CLIENT_SCRATCH1 >> + * 2. Initiating the SW PBS trigger >> + * 3. Checking the equivalent bit in PBS_CLIENT_SCRATCH2 for the >> + * completion of the sequence. >> + * 4. If PBS_CLIENT_SCRATCH2 == 0xFF, the PBS sequence failed to execute >> + * >> + * Returns: 0 on success, < 0 on failure >> + */ >> +int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap) >> +{ >> + u8 val, mask; >> + u16 bit_pos; >> + int ret; >> + >> + if (!bitmap) { >> + dev_err(pbs->dev, "Invalid bitmap passed by client\n"); >> + return -EINVAL; >> + } >> + >> + if (IS_ERR_OR_NULL(pbs)) >> + return -EINVAL; >> + >> + mutex_lock(&pbs->lock); >> + ret = qcom_pbs_read(pbs, PBS_CLIENT_SCRATCH2, &val); >> + if (ret < 0) >> + goto out; >> + >> + if (val == 0xFF) { >> + /* PBS error - clear SCRATCH2 register */ >> + ret = qcom_pbs_write(pbs, PBS_CLIENT_SCRATCH2, 0); >> + if (ret < 0) >> + goto out; >> + } >> + >> + for (bit_pos = 0; bit_pos < 8; bit_pos++) { >> + if (bitmap & BIT(bit_pos)) { >> + /* >> + * Clear the PBS sequence bit position in >> + * PBS_CLIENT_SCRATCH2 mask register. >> + */ > Don't think the "in the X register" parts are useful. ack > >> + ret = qcom_pbs_masked_write(pbs, PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0); >> + if (ret < 0) >> + goto error; >> + >> + /* >> + * Set the PBS sequence bit position in >> + * PBS_CLIENT_SCRATCH1 register. >> + */ >> + val = mask = BIT(bit_pos); > You're using mask/val for half the function calls.. > Stick with one approach. ack > > [...] > >> +struct pbs_dev *get_pbs_client_device(struct device *dev) >> +{ >> + struct device_node *pbs_dev_node; >> + struct platform_device *pdev; >> + struct pbs_dev *pbs; >> + >> + pbs_dev_node = of_parse_phandle(dev->of_node, "qcom,pbs", 0); >> + if (!pbs_dev_node) { >> + dev_err(dev, "Missing qcom,pbs property\n"); >> + return ERR_PTR(-ENODEV); >> + } >> + >> + pdev = of_find_device_by_node(pbs_dev_node); >> + if (!pdev) { >> + dev_err(dev, "Unable to find PBS dev_node\n"); >> + pbs = ERR_PTR(-EPROBE_DEFER); >> + goto out; >> + } >> + >> + pbs = platform_get_drvdata(pdev); >> + if (!pbs) { > This check seems unnecessary, the PBS driver would have had to fail > probing if set_drvdata never got called. > > Konrad
On 8/2/2023 5:25 PM, Rob Herring wrote: > On Tue, Jul 25, 2023 at 12:34:18PM -0700, Anjelique Melendez wrote: >> + - if: >> + properties: >> + compatible: >> + contains: >> + enum: >> + - qcom,pm8350c-pw >> + - qcom,pm8550-pwm >> + then: >> + properties: >> + nvmem: >> + minItems: 2 >> + nvmem-names: >> + items: >> + - const: lpg_chan_sdam >> + - const: lut_sdam > > This can go into the main section and then here you just say > 'minItems: 2'. And similar for the 1st if/then. > ACK >> + required: >> + - nvmem >> + - nvmem-names > > Looks like these are always required. These are only required for the compatibles properties that do not have lut peripherals. Right now this is is only for qcom,pmi632-lpg, qcom,pm8350c-pwm and qcom,pm8550-pwm.
In certain PMICs, LUT pattern and LPG configuration can be stored in SDAM modules instead of LUT peripheral. This feature is called PPG. This change series adds support for PPG. Thanks! Changes since v1: - Patch 1/7 - Fix dt_binding_check errors - Update binding description - Path 2/7 - Fix dt_binding_check errors - Update per variant constraints - Update nvmem description - Patch 3/7 - Update get_pbs_client_device() - Drop use of printk - Remove unused function Tested-by: Luca Weiss <luca.weiss@fairphone.com> # sdm632-fairphone-fp3 (pmi632) Anjelique Melendez (7): dt-bindings: soc: qcom: Add qcom-pbs bindings dt-bindings: leds: leds-qcom-lpg: Add support for LPG PPG soc: qcom: add QCOM PBS driver leds: rgb: leds-qcom-lpg: Add support for PPG through single SDAM leds: rgb: leds-qcom-lpg: Update PMI632 lpg_data to support PPG leds: rgb: leds-qcom-lpg: Support two-nvmem PPG Scheme leds: rgb: Update PM8350C lpg_data to support two-nvmem PPG Scheme .../bindings/leds/leds-qcom-lpg.yaml | 92 +++- .../bindings/soc/qcom/qcom-pbs.yaml | 40 ++ drivers/leds/rgb/leds-qcom-lpg.c | 395 ++++++++++++++++-- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qcom-pbs.c | 302 +++++++++++++ include/linux/soc/qcom/qcom-pbs.h | 30 ++ 7 files changed, 836 insertions(+), 33 deletions(-) create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml create mode 100644 drivers/soc/qcom/qcom-pbs.c create mode 100644 include/linux/soc/qcom/qcom-pbs.h