Message ID | 20230621185949.2068-1-quic_amelende@quicinc.com |
---|---|
Headers | show |
Series | Add support for LUT PPG | expand |
On 21/06/2023 20:59, 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 | 41 +++++++++++++++++++ > 1 file changed, 41 insertions(+) > create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml Except missing testing... few more comments: > > diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml > new file mode 100644 > index 000000000000..0a89c334f95c > --- /dev/null > +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml Filename matching compatibles, so qcom,pbs > @@ -0,0 +1,41 @@ > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/soc/qcom/qcom-pbs.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: Qualcomm Technologies, Inc. PBS Qualcomm PBS foo bar a bit more than just one word. E.g. expand PBS acronym > + > +maintainers: > + - Anjelique Melendez <quic_amelende@quicinc.com> > + > +description: | > + Qualcomm PBS (programmable boot sequencer) supports triggering sequences > + for clients upon request. I don't understand what's this. What is "triggering sequences"? What sequences? > + > +properties: > + compatible: > + const: qcom,pbs Missing SoC specific comaptibles. > + > + reg: > + description: | > + Base address of the PBS peripheral. Drop description, it's obvious. > + maxItems: 1 > + Binding looks very incomplete... > +required: > + - compatible > + - reg > + > +additionalProperties: false > + > +examples: > + - | > + pmic { > + #address-cells = <1>; > + #size-cells = <0>; > + > + qcom,pbs@7400 { That's not a proper node name. Do you see anywhere such node? Please, do not work on downstream code, but on mainline. > + compatible = "qcom,pbs"; > + reg = <0x7400>; > + }; > + }; Best regards, Krzysztof
On 21/06/2023 20:59, 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> > --- > drivers/soc/qcom/Kconfig | 9 + > drivers/soc/qcom/Makefile | 1 + > drivers/soc/qcom/qcom-pbs.c | 343 ++++++++++++++++++++++++++++++ > include/linux/soc/qcom/qcom-pbs.h | 36 ++++ > 4 files changed, 389 insertions(+) > create mode 100644 drivers/soc/qcom/qcom-pbs.c > create mode 100644 include/linux/soc/qcom/qcom-pbs.h > > diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig > index a491718f8064..226b668f4690 100644 > --- a/drivers/soc/qcom/Kconfig > +++ b/drivers/soc/qcom/Kconfig > @@ -260,6 +260,15 @@ config QCOM_APR > used by audio driver to configure QDSP6 > ASM, ADM and AFE modules. > > +config QCOM_PBS > + tristate "PBS trigger support for Qualcomm PMIC" > + depends on SPMI > + help > + This driver supports configuring software programmable boot sequencer (PBS) > + trigger event through PBS RAM on Qualcomm Technologies, Inc. PMICs. > + This module provides the APIs to the client drivers that wants to send the > + PBS trigger event to the PBS RAM. > + > config QCOM_ICC_BWMON > tristate "QCOM Interconnect Bandwidth Monitor driver" > depends on ARCH_QCOM || COMPILE_TEST > diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile > index 0f43a88b4894..4e154af3877a 100644 > --- a/drivers/soc/qcom/Makefile > +++ b/drivers/soc/qcom/Makefile > @@ -31,5 +31,6 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o > obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o > obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o > obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o > +obj-$(CONFIG_QCOM_PBS) += qcom-pbs.o > obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o > obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE) += ice.o > diff --git a/drivers/soc/qcom/qcom-pbs.c b/drivers/soc/qcom/qcom-pbs.c > new file mode 100644 > index 000000000000..4a2bb7ff8031 > --- /dev/null > +++ b/drivers/soc/qcom/qcom-pbs.c > @@ -0,0 +1,343 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#define pr_fmt(fmt) "PBS: %s: " fmt, __func__ > + > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/platform_device.h> > +#include <linux/regmap.h> > +#include <linux/spmi.h> > +#include <linux/soc/qcom/qcom-pbs.h> > + > +#define PBS_CLIENT_TRIG_CTL 0x42 > +#define PBS_CLIENT_SW_TRIG_BIT BIT(7) > +#define PBS_CLIENT_SCRATCH1 0x50 > +#define PBS_CLIENT_SCRATCH2 0x51 > + > +static LIST_HEAD(pbs_dev_list); > +static DEFINE_MUTEX(pbs_list_lock); No file-scope variables. Drop both. You don't even need it. > + > +struct pbs_dev { > + struct device *dev; > + struct device_node *dev_node; > + struct regmap *regmap; > + struct mutex lock; > + struct list_head link; > + > + u32 base; > +}; > + > +static int qcom_pbs_read(struct pbs_dev *pbs, u32 address, u8 *val) > +{ > + int ret; > + > + address += pbs->base; > + ret = regmap_bulk_read(pbs->regmap, address, val, 1); > + if (ret) > + pr_err("Failed to read address=%#x sid=%#x ret=%d\n", dev_err > + address, to_spmi_device(pbs->dev->parent)->usid, ret); > + > + return ret; > +} > + > +static int qcom_pbs_write(struct pbs_dev *pbs, u16 address, u8 val) > +{ > + int ret; > + > + address += pbs->base; > + ret = regmap_bulk_write(pbs->regmap, address, &val, 1); > + if (ret < 0) > + pr_err("Failed to write address=%#x sid=%#x ret=%d\n", > + address, to_spmi_device(pbs->dev->parent)->usid, ret); > + else > + pr_debug("Wrote %#x to addr %#x\n", val, address); No, there is regmap debug for this. Drop such debug statements from the driver. Actually the error print is also wrong, IMO. > + > + return ret; > +} > + > +static int qcom_pbs_masked_write(struct pbs_dev *pbs, u16 address, u8 mask, u8 val) > +{ > + int ret; > + > + address += pbs->base; > + ret = regmap_update_bits(pbs->regmap, address, mask, val); > + if (ret < 0) > + pr_err("Failed to write address=%#x ret=%d\n", address, ret); > + else > + pr_debug("Wrote %#x to addr %#x\n", val, address); Drop > + > + return ret; > +} > + > +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) { > + /* PBS error - clear SCRATCH2 register */ > + ret = qcom_pbs_write(pbs, PBS_CLIENT_SCRATCH2, 0); > + if (ret < 0) > + return ret; > + > + pr_err("NACK from PBS for bit %u\n", bit_pos); > + return -EINVAL; > + } > + > + if (val & BIT(bit_pos)) { > + pr_debug("PBS sequence for bit %u executed!\n", bit_pos); dev_dbg > + break; > + } > + > + usleep_range(delay, delay + 100); > + } > + > + if (!retries) { > + pr_err("Timeout for PBS ACK/NACK for bit %u\n", bit_pos); dev_err > + return -ETIMEDOUT; > + } > + > + return 0; > +} > + > +/** > + * qcom_pbs_trigger_single_event() - Trigger PBS sequence without using bitmap. > + * @pbs: Pointer to PBS device > + * > + * This function is used to trigger the PBS that is hooked on the > + * SW_TRIGGER directly in PBS client. > + * > + * Return: 0 on success, < 0 on failure > + */ > +int qcom_pbs_trigger_single_event(struct pbs_dev *pbs) > +{ > + int ret = 0; > + > + if (IS_ERR_OR_NULL(pbs)) > + return -EINVAL; > + > + mutex_lock(&pbs->lock); > + ret = qcom_pbs_masked_write(pbs, PBS_CLIENT_TRIG_CTL, PBS_CLIENT_SW_TRIG_BIT, > + PBS_CLIENT_SW_TRIG_BIT); > + if (ret < 0) > + pr_err("Failed to write register %x ret=%d\n", PBS_CLIENT_TRIG_CTL, ret); dev_* everywhere > + mutex_unlock(&pbs->lock); > + > + return ret; > +} > +EXPORT_SYMBOL(qcom_pbs_trigger_single_event); > + ... > +/** > + * get_pbs_client_device() - Get the PBS device used by client > + * @dev: Client device > + * > + * This function is used to get the PBS device that is being > + * used by the client. > + * > + * Returns: pbs_dev on success, ERR_PTR on failure > + */ > +struct pbs_dev *get_pbs_client_device(struct device *dev) > +{ > + struct device_node *pbs_dev_node; > + struct pbs_dev *pbs; > + > + pbs_dev_node = of_parse_phandle(dev->of_node, "qcom,pbs-client", 0); > + if (!pbs_dev_node) { > + pr_err("Missing qcom,pbs-client property\n"); > + return ERR_PTR(-ENODEV); > + } > + > + mutex_lock(&pbs_list_lock); > + list_for_each_entry(pbs, &pbs_dev_list, link) { It does not make sense. You have the reference to the device, so you have the pbs (via container_of). Don't add some global-list-lookup-functions. Look for example at Abel Vesa's ICE patchset. > + if (pbs_dev_node == pbs->dev_node) { > + of_node_put(pbs_dev_node); > + mutex_unlock(&pbs_list_lock); > + return pbs; > + } > + } > + mutex_unlock(&pbs_list_lock); Where is device_link handling? > + > + pr_debug("Unable to find PBS dev_node\n"); > + of_node_put(pbs_dev_node); > + return ERR_PTR(-EPROBE_DEFER); > +} > +EXPORT_SYMBOL(get_pbs_client_device); > + > +static int qcom_pbs_probe(struct platform_device *pdev) > +{ > + struct pbs_dev *pbs; > + u32 val; > + int ret; > + > + pbs = devm_kzalloc(&pdev->dev, sizeof(*pbs), GFP_KERNEL); > + if (!pbs) > + return -ENOMEM; > + > + pbs->dev = &pdev->dev; > + pbs->dev_node = pdev->dev.of_node; Why do you need to store it? > + pbs->regmap = dev_get_regmap(pbs->dev->parent, NULL); > + if (!pbs->regmap) { > + dev_err(pbs->dev, "Couldn't get parent's regmap\n"); > + return -EINVAL; > + } > + > + ret = device_property_read_u32(pbs->dev, "reg", &val); > + if (ret < 0) { > + dev_err(pbs->dev, "Couldn't find reg, ret = %d\n", ret); > + return ret; > + } > + > + pbs->base = val; > + mutex_init(&pbs->lock); > + > + platform_set_drvdata(pdev, pbs); > + > + mutex_lock(&pbs_list_lock); > + list_add(&pbs->link, &pbs_dev_list); > + mutex_unlock(&pbs_list_lock); > + > + return 0; > +} > + > +static int qcom_pbs_remove(struct platform_device *pdev) > +{ > + struct pbs_dev *pbs = platform_get_drvdata(pdev); > + > + mutex_lock(&pbs_list_lock); > + list_del(&pbs->link); > + mutex_unlock(&pbs_list_lock); > + > + return 0; > +} > + > +static const struct of_device_id qcom_pbs_match_table[] = { > + { .compatible = "qcom,pbs" }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, qcom_pbs_match_table); > + > +static struct platform_driver qcom_pbs_driver = { > + .driver = { > + .name = "qcom-pbs", > + .of_match_table = qcom_pbs_match_table, > + }, > + .probe = qcom_pbs_probe, > + .remove = qcom_pbs_remove, > +}; > +module_platform_driver(qcom_pbs_driver) > + > +MODULE_DESCRIPTION("QCOM PBS DRIVER"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:qcom-pbs"); Drop alias. Not needed. If you need it, you have missing ID table. > diff --git a/include/linux/soc/qcom/qcom-pbs.h b/include/linux/soc/qcom/qcom-pbs.h > new file mode 100644 > index 000000000000..4b065951686a > --- /dev/null Best regards, Krzysztof
Hi Anjelique, On Wed Jun 21, 2023 at 8:59 PM CEST, Anjelique Melendez wrote: > 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! Thanks for sending this series! I've tested this on SDM632 Fairphone 3 and everything appears to work fine with setting the pattern. Using fbcli from feedbackd[0] the pattern shows up correctly. The only thing missing really is the addition of the pbs node and adding the nvmem/nvmem-names & qcom,pbs-client to the lpg node in pmi632.dtsi - something like the patch below. Are you planning to include this in the next revision? Otherwise I can also send a patch for the pmi632.dtsi after this series has landed. Tested-by: Luca Weiss <luca.weiss@fairphone.com> # sdm632-fairphone-fp3 (pmi632) [0] https://source.puri.sm/Librem5/feedbackd Regards Luca diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index add206dee01d2e..92ddb7ac6bf311 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -127,6 +127,11 @@ status = "disabled"; }; + pmi632_pbs_client3: qcom,pbs@7400 { // TODO: generic node name + compatible = "qcom,pbs"; + reg = <0x7400>; + }; + pmi632_sdam_7: nvram@b600 { compatible = "qcom,spmi-sdam"; reg = <0xb600>; @@ -155,6 +160,10 @@ pmi632_lpg: pwm { compatible = "qcom,pmi632-lpg"; + nvmem = <&pmi632_sdam_7>; + nvmem-names = "lpg_chan_sdam"; + qcom,pbs-client = <&pmi632_pbs_client3>; + #address-cells = <1>; #size-cells = <0>; #pwm-cells = <2>; > > Anjelique Melendez (7): > dt-bindings: soc: qcom: Add qcom-pbs bindings > dt-bindings: leds: leds-qcom-lpg: Add support for LUT through NVMEM > devices > soc: qcom: add QCOM PBS driver > leds: rgb: leds-qcom-lpg: Add support for LUT pattern 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 | 85 ++++ > .../bindings/soc/qcom/qcom-pbs.yaml | 41 ++ > drivers/leds/rgb/leds-qcom-lpg.c | 393 ++++++++++++++++-- > drivers/soc/qcom/Kconfig | 9 + > drivers/soc/qcom/Makefile | 1 + > drivers/soc/qcom/qcom-pbs.c | 343 +++++++++++++++ > include/linux/soc/qcom/qcom-pbs.h | 36 ++ > 7 files changed, 877 insertions(+), 31 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
On Wed, Jun 21, 2023 at 11:59:45AM -0700, 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 | 41 +++++++++++++++++++ > 1 file changed, 41 insertions(+) > create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml > > diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml > new file mode 100644 > index 000000000000..0a89c334f95c > --- /dev/null > +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml > @@ -0,0 +1,41 @@ > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/soc/qcom/qcom-pbs.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: Qualcomm Technologies, Inc. PBS > + > +maintainers: > + - Anjelique Melendez <quic_amelende@quicinc.com> > + > +description: | > + Qualcomm PBS (programmable boot sequencer) supports triggering sequences > + for clients upon request. > + > +properties: > + compatible: > + const: qcom,pbs > + > + reg: > + description: | > + Base address of the PBS peripheral. > + maxItems: 1 > + > +required: > + - compatible > + - reg > + > +additionalProperties: false > + > +examples: > + - | > + pmic { > + #address-cells = <1>; > + #size-cells = <0>; > + > + qcom,pbs@7400 { > + compatible = "qcom,pbs"; > + reg = <0x7400>; > + }; Why do you need a child node for this? Is there more than 1 instance in a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. Rob
On 6/24/2023 2:42 AM, Krzysztof Kozlowski wrote: > On 21/06/2023 20:59, Anjelique Melendez wrote: >> Update leds-qcom-lpg bindings to support LUT patterns through NVMEM >> devices. >> >> Signed-off-by: Anjelique Melendez <quic_amelende@quicinc.com> >> --- >> .../bindings/leds/leds-qcom-lpg.yaml | 85 +++++++++++++++++++ >> 1 file changed, 85 insertions(+) >> >> diff --git a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml >> index e6f1999cb22f..c9d53820bf83 100644 >> --- a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml >> +++ b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml >> @@ -63,6 +63,31 @@ properties: >> - description: dtest line to attach >> - description: flags for the attachment >> >> + nvmem: >> + description: > >> + Phandle(s) of the nvmem device(s) to access the LUT stored in the SDAM module(s). > > It's the first time in this binding the "LUT" appears. Drop redundant > parts like "Phandle(s) of ...." and describe what do you expect there > and why the hardware needs it. LUT is a "lookup table"(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml?h=v6.4#n14) and in this case holds pattern data i.e LUT patterns. Currently, qcom,pm660l-lpg, qcom,pm8150b-lpg, qcom,pm8150l-lpg, qcom,pm8941-lpg, qcom,pm8994-lpg, qcom,pmc8180c-lpg, qcom,pmi8994-lpg, and qcom,pmi8998-lpg all have an a specific LUT peripheral (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/leds/rgb/leds-qcom-lpg.c?h=v6.4-rc7#n1382) and this is already being handled in leds-qcom-lpg. What is new with this patch set is that instead of having a LUT peripheral, some PMICs use nvmem to hold LUT pattern and other lpg per channel data. The use of nvmems to store LUT pattern and lpg data is called PPG. You can either have a single nvmem PPG (a single nvmem device that holds LUT pattern and lpg per channel data) or two-nvmem PPG(1 nvmem for LUT pattern and 1 nvmem for lpg per channel data) I can update the descritpion for the entire binding to mention PPG and LUT so this is more clear. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml?h=v6.4#n12 >> + This property is required only when LUT mode is supported and the LUT pattern is >> + stored in SDAM modules instead of a LUT module. >> + minItems: 1 >> + maxItems: 2 >> + >> + nvmem-names: >> + description: > >> + The nvmem device name(s) for the SDAM module(s) where the LUT pattern data is stored. >> + This property is required only when LUT mode is supported with SDAM module instead of >> + LUT module. >> + minItems: 1 >> + items: >> + - const: lpg_chan_sdam >> + - const: lut_sdam >> + >> + qcom,pbs-client: >> + $ref: /schemas/types.yaml#/definitions/phandle >> + description: > >> + Phandle of the PBS client used for sending the PBS trigger. This property is > > > You need to explain what is PBS and what this property is doing. > > Phandle of PBS client? This is the PBS client! It does not make sense. Ack > > > >> + required when LUT mode is supported and the LUT pattern is stored in a single >> + SDAM module instead of a LUT module. > > Which devices support LUT? Why this is not constrained per variant? When you say constrained per variant, are you looking for something more like this? i.e. allOf: - if: properties: compatible: contains: const: qcom,pmi632-lpg then: properties: nvmem: maxItems: 1 nvmem-names: items: - const: lpg_chan_sdam required: - nvmem - qcom,pbs-client - if: properties: compatible: contains: const: qcom,pm8350c-pwm then: properties: nvmem: maxItems: 2 nvmem-names: items: - const: lpg_chan_sdam - const: lut_sdam required: - nvmem > >> + >> multi-led: >> type: object >> $ref: leds-class-multicolor.yaml# >> @@ -191,4 +216,64 @@ examples: >> compatible = "qcom,pm8916-pwm"; >> #pwm-cells = <2>; >> }; >> + - | >> + #include <dt-bindings/leds/common.h> >> + >> + led-controller { >> + compatible = "qcom,pm8350c-pwm"; >> + #address-cells = <1>; >> + #size-cells = <0>; >> + #pwm-cells = <2>; >> + nvmem-names = "lpg_chan_sdam" , "lut_sdam"; > > Fix your whitespaces. Ack > >> + nvmem = <&pmk8550_sdam_21 &pmk8550_sdam_22>; > > Two entries, not one> > Anyway, adding one property does not justify new example. Integrate it > into existing one. So we actually cannot integrate these properties into existing examples. The current examples are for PMICs that use LUT peripherals (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/leds/rgb/leds-qcom-lpg.c?h=v6.4#n1417). This patch series is adding support for PMICs that do not have a LUT peripheral and instead store LUT patterns and LPG configurations in either 1 or 2 NVMEM(s). > >> + >> + led@1 { >> + reg = <1>; >> + color = <LED_COLOR_ID_RED>; >> + label = "red"; >> + }; >> + >> + led@2 { >> + reg = <2>; >> + color = <LED_COLOR_ID_GREEN>; >> + label = "green"; >> + }; >> + >> + led@3 { >> + reg = <3>; >> + color = <LED_COLOR_ID_BLUE>; >> + label = "blue"; >> + }; >> + }; >> + - | >> + #include <dt-bindings/leds/common.h> >> + >> + led-controller { >> + compatible = "qcom,pmi632-lpg"; >> + #address-cells = <1>; >> + #size-cells = <0>; >> + #pwm-cells = <2>; >> + nvmem-names = "lpg_chan_sdam"; >> + nvmem = <&pmi632_sdam7>; >> + qcom,pbs-client = <&pmi632_pbs_client3>; > > One more example? Why? > > Why do you have here only one NVMEM cell? Aren't you missing constraints > in the binding?The use of the qcom,pbs-client is only used when we have a PMIC device that has a single PPG NVMEM, which is why this was not included in the above 2 nvmem PPG example. I see how these two PPG examples are repetitive so I am ok with getting rid of one of them but I do think we should have at least one PPG example. > > Best regards, > Krzysztof > Thanks, Anjelique
On 6/24/2023 2:55 AM, Krzysztof Kozlowski wrote: > On 21/06/2023 20:59, 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> >> --- >> drivers/soc/qcom/Kconfig | 9 + >> drivers/soc/qcom/Makefile | 1 + >> drivers/soc/qcom/qcom-pbs.c | 343 ++++++++++++++++++++++++++++++ >> include/linux/soc/qcom/qcom-pbs.h | 36 ++++ >> 4 files changed, 389 insertions(+) >> create mode 100644 drivers/soc/qcom/qcom-pbs.c >> create mode 100644 include/linux/soc/qcom/qcom-pbs.h >> >> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig >> index a491718f8064..226b668f4690 100644 >> --- a/drivers/soc/qcom/Kconfig >> +++ b/drivers/soc/qcom/Kconfig >> @@ -260,6 +260,15 @@ config QCOM_APR >> used by audio driver to configure QDSP6 >> ASM, ADM and AFE modules. >> >> +config QCOM_PBS >> + tristate "PBS trigger support for Qualcomm PMIC" >> + depends on SPMI >> + help >> + This driver supports configuring software programmable boot sequencer (PBS) >> + trigger event through PBS RAM on Qualcomm Technologies, Inc. PMICs. >> + This module provides the APIs to the client drivers that wants to send the >> + PBS trigger event to the PBS RAM. >> + >> config QCOM_ICC_BWMON >> tristate "QCOM Interconnect Bandwidth Monitor driver" >> depends on ARCH_QCOM || COMPILE_TEST >> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile >> index 0f43a88b4894..4e154af3877a 100644 >> --- a/drivers/soc/qcom/Makefile >> +++ b/drivers/soc/qcom/Makefile >> @@ -31,5 +31,6 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o >> obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o >> obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o >> obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o >> +obj-$(CONFIG_QCOM_PBS) += qcom-pbs.o >> obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o >> obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE) += ice.o >> diff --git a/drivers/soc/qcom/qcom-pbs.c b/drivers/soc/qcom/qcom-pbs.c >> new file mode 100644 >> index 000000000000..4a2bb7ff8031 >> --- /dev/null >> +++ b/drivers/soc/qcom/qcom-pbs.c >> @@ -0,0 +1,343 @@ >> +// SPDX-License-Identifier: GPL-2.0-only >> +/* >> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. >> + */ >> + >> +#define pr_fmt(fmt) "PBS: %s: " fmt, __func__ >> + >> +#include <linux/delay.h> >> +#include <linux/err.h> >> +#include <linux/module.h> >> +#include <linux/of.h> >> +#include <linux/platform_device.h> >> +#include <linux/regmap.h> >> +#include <linux/spmi.h> >> +#include <linux/soc/qcom/qcom-pbs.h> >> + >> +#define PBS_CLIENT_TRIG_CTL 0x42 >> +#define PBS_CLIENT_SW_TRIG_BIT BIT(7) >> +#define PBS_CLIENT_SCRATCH1 0x50 >> +#define PBS_CLIENT_SCRATCH2 0x51 >> + >> +static LIST_HEAD(pbs_dev_list); >> +static DEFINE_MUTEX(pbs_list_lock); > > No file-scope variables. Drop both. You don't even need it. Ack > >> + >> +struct pbs_dev { >> + struct device *dev; >> + struct device_node *dev_node; >> + struct regmap *regmap; >> + struct mutex lock; >> + struct list_head link; >> + >> + u32 base; >> +}; >> + >> +static int qcom_pbs_read(struct pbs_dev *pbs, u32 address, u8 *val) >> +{ >> + int ret; >> + >> + address += pbs->base; >> + ret = regmap_bulk_read(pbs->regmap, address, val, 1); >> + if (ret) >> + pr_err("Failed to read address=%#x sid=%#x ret=%d\n", > > dev_err Ack > >> + address, to_spmi_device(pbs->dev->parent)->usid, ret); >> + >> + return ret; >> +} >> + >> +static int qcom_pbs_write(struct pbs_dev *pbs, u16 address, u8 val) >> +{ >> + int ret; >> + >> + address += pbs->base; >> + ret = regmap_bulk_write(pbs->regmap, address, &val, 1); >> + if (ret < 0) >> + pr_err("Failed to write address=%#x sid=%#x ret=%d\n", >> + address, to_spmi_device(pbs->dev->parent)->usid, ret); >> + else >> + pr_debug("Wrote %#x to addr %#x\n", val, address); > > No, there is regmap debug for this. Drop such debug statements from the > driver. Ack > > Actually the error print is also wrong, IMO> >> + >> + return ret; >> +} >> + >> +static int qcom_pbs_masked_write(struct pbs_dev *pbs, u16 address, u8 mask, u8 val) >> +{ >> + int ret; >> + >> + address += pbs->base; >> + ret = regmap_update_bits(pbs->regmap, address, mask, val); >> + if (ret < 0) >> + pr_err("Failed to write address=%#x ret=%d\n", address, ret); >> + else >> + pr_debug("Wrote %#x to addr %#x\n", val, address); > > Drop Ack > >> + >> + return ret; >> +} >> + >> +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) { >> + /* PBS error - clear SCRATCH2 register */ >> + ret = qcom_pbs_write(pbs, PBS_CLIENT_SCRATCH2, 0); >> + if (ret < 0) >> + return ret; >> + >> + pr_err("NACK from PBS for bit %u\n", bit_pos); >> + return -EINVAL; >> + } >> + >> + if (val & BIT(bit_pos)) { >> + pr_debug("PBS sequence for bit %u executed!\n", bit_pos); > > dev_dbg Ack > >> + break; >> + } >> + >> + usleep_range(delay, delay + 100); >> + } >> + >> + if (!retries) { >> + pr_err("Timeout for PBS ACK/NACK for bit %u\n", bit_pos); > > dev_err Ack >> + return -ETIMEDOUT; >> + } >> + >> + return 0; >> +} >> + >> +/** >> + * qcom_pbs_trigger_single_event() - Trigger PBS sequence without using bitmap. >> + * @pbs: Pointer to PBS device >> + * >> + * This function is used to trigger the PBS that is hooked on the >> + * SW_TRIGGER directly in PBS client. >> + * >> + * Return: 0 on success, < 0 on failure >> + */ >> +int qcom_pbs_trigger_single_event(struct pbs_dev *pbs) >> +{ >> + int ret = 0; >> + >> + if (IS_ERR_OR_NULL(pbs)) >> + return -EINVAL; >> + >> + mutex_lock(&pbs->lock); >> + ret = qcom_pbs_masked_write(pbs, PBS_CLIENT_TRIG_CTL, PBS_CLIENT_SW_TRIG_BIT, >> + PBS_CLIENT_SW_TRIG_BIT); >> + if (ret < 0) >> + pr_err("Failed to write register %x ret=%d\n", PBS_CLIENT_TRIG_CTL, ret); > > dev_* everywhere Ack > >> + mutex_unlock(&pbs->lock); >> + >> + return ret; >> +} >> +EXPORT_SYMBOL(qcom_pbs_trigger_single_event); >> + > > ... qcom_pbs_trigger_single_event() is used in our downstream haptics driver, will remove for now and add it back when haptics driver get upstreamed > >> +/** >> + * get_pbs_client_device() - Get the PBS device used by client >> + * @dev: Client device >> + * >> + * This function is used to get the PBS device that is being >> + * used by the client. >> + * >> + * Returns: pbs_dev on success, ERR_PTR on failure >> + */ >> +struct pbs_dev *get_pbs_client_device(struct device *dev) >> +{ >> + struct device_node *pbs_dev_node; >> + struct pbs_dev *pbs; >> + >> + pbs_dev_node = of_parse_phandle(dev->of_node, "qcom,pbs-client", 0); >> + if (!pbs_dev_node) { >> + pr_err("Missing qcom,pbs-client property\n"); >> + return ERR_PTR(-ENODEV); >> + } >> + >> + mutex_lock(&pbs_list_lock); >> + list_for_each_entry(pbs, &pbs_dev_list, link) { > > It does not make sense. You have the reference to the device, so you > have the pbs (via container_of). Don't add some > global-list-lookup-functions. > > Look for example at Abel Vesa's ICE patchset. > >> + if (pbs_dev_node == pbs->dev_node) { >> + of_node_put(pbs_dev_node); >> + mutex_unlock(&pbs_list_lock); >> + return pbs; >> + } >> + } >> + mutex_unlock(&pbs_list_lock); > > Where is device_link handling? Thank you for pointing me to Abel's ICE patchset! Will be updating patch to use container_of as well as having device_link_add(). > >> + >> + pr_debug("Unable to find PBS dev_node\n"); >> + of_node_put(pbs_dev_node); >> + return ERR_PTR(-EPROBE_DEFER); >> +} >> +EXPORT_SYMBOL(get_pbs_client_device); >> + >> +static int qcom_pbs_probe(struct platform_device *pdev) >> +{ >> + struct pbs_dev *pbs; >> + u32 val; >> + int ret; >> + >> + pbs = devm_kzalloc(&pdev->dev, sizeof(*pbs), GFP_KERNEL); >> + if (!pbs) >> + return -ENOMEM; >> + >> + pbs->dev = &pdev->dev; >> + pbs->dev_node = pdev->dev.of_node; > > Why do you need to store it? Ack - removing storing dev_node > >> + pbs->regmap = dev_get_regmap(pbs->dev->parent, NULL); >> + if (!pbs->regmap) { >> + dev_err(pbs->dev, "Couldn't get parent's regmap\n"); >> + return -EINVAL; >> + } >> + >> + ret = device_property_read_u32(pbs->dev, "reg", &val); >> + if (ret < 0) { >> + dev_err(pbs->dev, "Couldn't find reg, ret = %d\n", ret); >> + return ret; >> + } >> + >> + pbs->base = val; >> + mutex_init(&pbs->lock); >> + >> + platform_set_drvdata(pdev, pbs); >> + >> + mutex_lock(&pbs_list_lock); >> + list_add(&pbs->link, &pbs_dev_list); >> + mutex_unlock(&pbs_list_lock); >> + >> + return 0; >> +} >> + >> +static int qcom_pbs_remove(struct platform_device *pdev) >> +{ >> + struct pbs_dev *pbs = platform_get_drvdata(pdev); >> + >> + mutex_lock(&pbs_list_lock); >> + list_del(&pbs->link); >> + mutex_unlock(&pbs_list_lock); >> + >> + return 0; >> +} >> + >> +static const struct of_device_id qcom_pbs_match_table[] = { >> + { .compatible = "qcom,pbs" }, >> + {} >> +}; >> +MODULE_DEVICE_TABLE(of, qcom_pbs_match_table); >> + >> +static struct platform_driver qcom_pbs_driver = { >> + .driver = { >> + .name = "qcom-pbs", >> + .of_match_table = qcom_pbs_match_table, >> + }, >> + .probe = qcom_pbs_probe, >> + .remove = qcom_pbs_remove, >> +}; >> +module_platform_driver(qcom_pbs_driver) >> + >> +MODULE_DESCRIPTION("QCOM PBS DRIVER"); >> +MODULE_LICENSE("GPL"); >> +MODULE_ALIAS("platform:qcom-pbs"); > > Drop alias. Not needed. If you need it, you have missing ID table. Ack > >> diff --git a/include/linux/soc/qcom/qcom-pbs.h b/include/linux/soc/qcom/qcom-pbs.h >> new file mode 100644 >> index 000000000000..4b065951686a >> --- /dev/null > > > > Best regards, > Krzysztof > Thanks, Anjelque
On 6/26/2023 6:58 AM, Rob Herring wrote: > On Wed, Jun 21, 2023 at 11:59:45AM -0700, 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 | 41 +++++++++++++++++++ >> 1 file changed, 41 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >> >> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >> new file mode 100644 >> index 000000000000..0a89c334f95c >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >> @@ -0,0 +1,41 @@ >> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) >> +%YAML 1.2 >> +--- >> +$id: http://devicetree.org/schemas/soc/qcom/qcom-pbs.yaml# >> +$schema: http://devicetree.org/meta-schemas/core.yaml# >> + >> +title: Qualcomm Technologies, Inc. PBS >> + >> +maintainers: >> + - Anjelique Melendez <quic_amelende@quicinc.com> >> + >> +description: | >> + Qualcomm PBS (programmable boot sequencer) supports triggering sequences >> + for clients upon request. >> + >> +properties: >> + compatible: >> + const: qcom,pbs >> + >> + reg: >> + description: | >> + Base address of the PBS peripheral. >> + maxItems: 1 >> + >> +required: >> + - compatible >> + - reg >> + >> +additionalProperties: false >> + >> +examples: >> + - | >> + pmic { >> + #address-cells = <1>; >> + #size-cells = <0>; >> + >> + qcom,pbs@7400 { >> + compatible = "qcom,pbs"; >> + reg = <0x7400>; >> + }; > > Why do you need a child node for this? Is there more than 1 instance in > a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. > We currently have another downstream driver (which is planned to get upstreamed) which also needs a handle to a pbs device in order to properly trigger events. > Rob
On 29/06/2023 04:19, Anjelique Melendez wrote: > > > On 6/26/2023 6:58 AM, Rob Herring wrote: >> On Wed, Jun 21, 2023 at 11:59:45AM -0700, 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 | 41 +++++++++++++++++++ >>> 1 file changed, 41 insertions(+) >>> create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>> >>> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>> new file mode 100644 >>> index 000000000000..0a89c334f95c >>> --- /dev/null >>> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>> @@ -0,0 +1,41 @@ >>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) >>> +%YAML 1.2 >>> +--- >>> +$id: http://devicetree.org/schemas/soc/qcom/qcom-pbs.yaml# >>> +$schema: http://devicetree.org/meta-schemas/core.yaml# >>> + >>> +title: Qualcomm Technologies, Inc. PBS >>> + >>> +maintainers: >>> + - Anjelique Melendez <quic_amelende@quicinc.com> >>> + >>> +description: | >>> + Qualcomm PBS (programmable boot sequencer) supports triggering sequences >>> + for clients upon request. >>> + >>> +properties: >>> + compatible: >>> + const: qcom,pbs >>> + >>> + reg: >>> + description: | >>> + Base address of the PBS peripheral. >>> + maxItems: 1 >>> + >>> +required: >>> + - compatible >>> + - reg >>> + >>> +additionalProperties: false >>> + >>> +examples: >>> + - | >>> + pmic { >>> + #address-cells = <1>; >>> + #size-cells = <0>; >>> + >>> + qcom,pbs@7400 { >>> + compatible = "qcom,pbs"; >>> + reg = <0x7400>; >>> + }; >> >> Why do you need a child node for this? Is there more than 1 instance in >> a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. >> > > We currently have another downstream driver (which is planned to get upstreamed) > which also needs a handle to a pbs device in order to properly trigger events. Does it have to be a separate driver? Or is it a part of the LPG driver, just being artificially split away? > >> Rob > > >
On 6/29/2023 1:45 AM, Dmitry Baryshkov wrote: > On 29/06/2023 04:19, Anjelique Melendez wrote: >> >> >> On 6/26/2023 6:58 AM, Rob Herring wrote: >>> On Wed, Jun 21, 2023 at 11:59:45AM -0700, 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 | 41 +++++++++++++++++++ >>>> 1 file changed, 41 insertions(+) >>>> create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>>> >>>> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>>> new file mode 100644 >>>> index 000000000000..0a89c334f95c >>>> --- /dev/null >>>> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>>> @@ -0,0 +1,41 @@ >>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) >>>> +%YAML 1.2 >>>> +--- >>>> +$id: http://devicetree.org/schemas/soc/qcom/qcom-pbs.yaml# >>>> +$schema: http://devicetree.org/meta-schemas/core.yaml# >>>> + >>>> +title: Qualcomm Technologies, Inc. PBS >>>> + >>>> +maintainers: >>>> + - Anjelique Melendez <quic_amelende@quicinc.com> >>>> + >>>> +description: | >>>> + Qualcomm PBS (programmable boot sequencer) supports triggering sequences >>>> + for clients upon request. >>>> + >>>> +properties: >>>> + compatible: >>>> + const: qcom,pbs >>>> + >>>> + reg: >>>> + description: | >>>> + Base address of the PBS peripheral. >>>> + maxItems: 1 >>>> + >>>> +required: >>>> + - compatible >>>> + - reg >>>> + >>>> +additionalProperties: false >>>> + >>>> +examples: >>>> + - | >>>> + pmic { >>>> + #address-cells = <1>; >>>> + #size-cells = <0>; >>>> + >>>> + qcom,pbs@7400 { >>>> + compatible = "qcom,pbs"; >>>> + reg = <0x7400>; >>>> + }; >>> >>> Why do you need a child node for this? Is there more than 1 instance in >>> a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. >>> >> >> We currently have another downstream driver (which is planned to get upstreamed) >> which also needs a handle to a pbs device in order to properly trigger events. > > Does it have to be a separate driver? Or is it a part of the LPG driver, just being artificially split away? Sure, I just discussed with team and we are ok with removing this as a separate driver. Will have that for next version. > >> >>> Rob >> >> >> >
On 30/06/2023 00:53, Anjelique Melendez wrote: > > > On 6/29/2023 1:45 AM, Dmitry Baryshkov wrote: >> On 29/06/2023 04:19, Anjelique Melendez wrote: >>> >>> >>> On 6/26/2023 6:58 AM, Rob Herring wrote: >>>> On Wed, Jun 21, 2023 at 11:59:45AM -0700, 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 | 41 +++++++++++++++++++ >>>>> 1 file changed, 41 insertions(+) >>>>> create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>>>> >>>>> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>>>> new file mode 100644 >>>>> index 000000000000..0a89c334f95c >>>>> --- /dev/null >>>>> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-pbs.yaml >>>>> @@ -0,0 +1,41 @@ >>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) >>>>> +%YAML 1.2 >>>>> +--- >>>>> +$id: http://devicetree.org/schemas/soc/qcom/qcom-pbs.yaml# >>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml# >>>>> + >>>>> +title: Qualcomm Technologies, Inc. PBS >>>>> + >>>>> +maintainers: >>>>> + - Anjelique Melendez <quic_amelende@quicinc.com> >>>>> + >>>>> +description: | >>>>> + Qualcomm PBS (programmable boot sequencer) supports triggering sequences >>>>> + for clients upon request. >>>>> + >>>>> +properties: >>>>> + compatible: >>>>> + const: qcom,pbs >>>>> + >>>>> + reg: >>>>> + description: | >>>>> + Base address of the PBS peripheral. >>>>> + maxItems: 1 >>>>> + >>>>> +required: >>>>> + - compatible >>>>> + - reg >>>>> + >>>>> +additionalProperties: false >>>>> + >>>>> +examples: >>>>> + - | >>>>> + pmic { >>>>> + #address-cells = <1>; >>>>> + #size-cells = <0>; >>>>> + >>>>> + qcom,pbs@7400 { >>>>> + compatible = "qcom,pbs"; >>>>> + reg = <0x7400>; >>>>> + }; >>>> >>>> Why do you need a child node for this? Is there more than 1 instance in >>>> a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. >>>> >>> >>> We currently have another downstream driver (which is planned to get upstreamed) >>> which also needs a handle to a pbs device in order to properly trigger events. >> >> Does it have to be a separate driver? Or is it a part of the LPG driver, just being artificially split away? > > Sure, I just discussed with team and we are ok with removing this as a separate driver. Will have that > for next version. I saw that the PBS can also be used with the haptics device. Will it talk to the LPG driver? >> >>> >>>> Rob >>> >>> >>> >>
On 29/06/2023 02:12, Anjelique Melendez wrote: >> >> >> >>> + required when LUT mode is supported and the LUT pattern is stored in a single >>> + SDAM module instead of a LUT module. >> >> Which devices support LUT? Why this is not constrained per variant? > When you say constrained per variant, are you looking for something more like this? > i.e. > allOf: > - if: > properties: > compatible: > contains: > const: qcom,pmi632-lpg > then: > properties: > nvmem: > maxItems: 1 > nvmem-names: > items: > - const: lpg_chan_sdam > required: > - nvmem > - qcom,pbs-client > - if: > properties: > compatible: > contains: > const: qcom,pm8350c-pwm > then: > properties: > nvmem: > maxItems: 2 > nvmem-names: > items: > - const: lpg_chan_sdam > - const: lut_sdam > required: > - nvmem Yes. > >> >>> + >>> multi-led: >>> type: object >>> $ref: leds-class-multicolor.yaml# >>> @@ -191,4 +216,64 @@ examples: >>> compatible = "qcom,pm8916-pwm"; >>> #pwm-cells = <2>; >>> }; >>> + - | >>> + #include <dt-bindings/leds/common.h> >>> + >>> + led-controller { >>> + compatible = "qcom,pm8350c-pwm"; >>> + #address-cells = <1>; >>> + #size-cells = <0>; >>> + #pwm-cells = <2>; >>> + nvmem-names = "lpg_chan_sdam" , "lut_sdam"; >> >> Fix your whitespaces. > Ack >> >>> + nvmem = <&pmk8550_sdam_21 &pmk8550_sdam_22>; >> >> Two entries, not one> >> Anyway, adding one property does not justify new example. Integrate it >> into existing one. > > So we actually cannot integrate these properties into existing examples. > The current examples are for PMICs that use LUT peripherals (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/leds/rgb/leds-qcom-lpg.c?h=v6.4#n1417). > This patch series is adding support for PMICs that do not have a LUT peripheral > and instead store LUT patterns and LPG configurations in either 1 or 2 NVMEM(s). >> >>> + >>> + led@1 { >>> + reg = <1>; >>> + color = <LED_COLOR_ID_RED>; >>> + label = "red"; >>> + }; >>> + >>> + led@2 { >>> + reg = <2>; >>> + color = <LED_COLOR_ID_GREEN>; >>> + label = "green"; >>> + }; >>> + >>> + led@3 { >>> + reg = <3>; >>> + color = <LED_COLOR_ID_BLUE>; >>> + label = "blue"; >>> + }; >>> + }; >>> + - | >>> + #include <dt-bindings/leds/common.h> >>> + >>> + led-controller { >>> + compatible = "qcom,pmi632-lpg"; >>> + #address-cells = <1>; >>> + #size-cells = <0>; >>> + #pwm-cells = <2>; >>> + nvmem-names = "lpg_chan_sdam"; >>> + nvmem = <&pmi632_sdam7>; >>> + qcom,pbs-client = <&pmi632_pbs_client3>; >> >> One more example? Why? >> >> Why do you have here only one NVMEM cell? Aren't you missing constraints >> in the binding?The use of the qcom,pbs-client is only used when we have a PMIC device that has a single PPG NVMEM, > which is why this was not included in the above 2 nvmem PPG example. I see how these two PPG examples > are repetitive so I am ok with getting rid of one of them but I do think we should have at least one PPG example. This example probably should replace one of the previous ones, because it is bigger / more complete. Best regards, Krzysztof
On 29/06/2023 03:19, Anjelique Melendez wrote: >>> +examples: >>> + - | >>> + pmic { >>> + #address-cells = <1>; >>> + #size-cells = <0>; >>> + >>> + qcom,pbs@7400 { >>> + compatible = "qcom,pbs"; >>> + reg = <0x7400>; >>> + }; >> >> Why do you need a child node for this? Is there more than 1 instance in >> a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. >> > > We currently have another downstream driver (which is planned to get upstreamed) > which also needs a handle to a pbs device in order to properly trigger events. I don't see how does it answer Rob's concerns. Neither mine about incomplete binding. You don't need pbs node here for that. Anyway, whatever you have downstream also does not justify any changes. Either upstream these so we can see it or drop this binding. Best regards, Krzysztof
On 7/1/2023 4:03 AM, Krzysztof Kozlowski wrote: > On 29/06/2023 03:19, Anjelique Melendez wrote: > >>>> +examples: >>>> + - | >>>> + pmic { >>>> + #address-cells = <1>; >>>> + #size-cells = <0>; >>>> + >>>> + qcom,pbs@7400 { >>>> + compatible = "qcom,pbs"; >>>> + reg = <0x7400>; >>>> + }; >>> >>> Why do you need a child node for this? Is there more than 1 instance in >>> a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. >>> >> >> We currently have another downstream driver (which is planned to get upstreamed) >> which also needs a handle to a pbs device in order to properly trigger events. > > I don't see how does it answer Rob's concerns. Neither mine about > incomplete binding. You don't need pbs node here for that. > > Anyway, whatever you have downstream also does not justify any changes. > Either upstream these so we can see it or drop this binding. > > Best regards, > Krzysztof > On PMI632, peripherals are partitioned over 2 different SIDs (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n42 and https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n149). Unfortunately, the pbs peripheral and the lpg peripherals are on different PMI632 devices and therefore have different regmaps. If we get rid of the pbs node we need to get a handle to the proper regmap. I see two possible options, we could either introduce a new client property which points to a peripheral on the same device as pbs. i.e. led-controller { compatible = "qcom,pmi632-lpg"; #address-cells = <1>; #size-cells = <0>; #pwm-cells = <2>; nvmem-names = "lpg_chan_sdam"; nvmem = <&pmi632_sdam7>; qcom,pbs-phandle = <&pmi632_gpios>; ..... }; Then when client is probing could do something like the following to get the regmap dn = of_parse_phandle(node, "qcom,pbs-phandle", 0); pdev = of_find_device_by_node(dn); pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); Or we could use the nvmem phandle and just have something like this in client's probe dn = of_parse_phandle(node, "nvmem", 0); pdev = of_find_device_by_node(dn); pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); Let me know what your thoughts are on this. Thanks, Anjelique
On 11/07/2023 05:52, Anjelique Melendez wrote: > > > On 7/1/2023 4:03 AM, Krzysztof Kozlowski wrote: >> On 29/06/2023 03:19, Anjelique Melendez wrote: >> >>>>> +examples: >>>>> + - | >>>>> + pmic { >>>>> + #address-cells = <1>; >>>>> + #size-cells = <0>; >>>>> + >>>>> + qcom,pbs@7400 { >>>>> + compatible = "qcom,pbs"; >>>>> + reg = <0x7400>; >>>>> + }; >>>> >>>> Why do you need a child node for this? Is there more than 1 instance in >>>> a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. >>>> >>> >>> We currently have another downstream driver (which is planned to get upstreamed) >>> which also needs a handle to a pbs device in order to properly trigger events. >> >> I don't see how does it answer Rob's concerns. Neither mine about >> incomplete binding. You don't need pbs node here for that. >> >> Anyway, whatever you have downstream also does not justify any changes. >> Either upstream these so we can see it or drop this binding. >> >> Best regards, >> Krzysztof >> > > On PMI632, peripherals are partitioned over 2 different SIDs > (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n42 > and https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n149). > Unfortunately, the pbs peripheral and the lpg peripherals are on different > PMI632 devices and therefore have different regmaps. > > If we get rid of the pbs node we need to get a handle to the proper regmap. > I see two possible options, we could either introduce a new client property > which points to a peripheral on the same device as pbs. > > i.e. > led-controller { > compatible = "qcom,pmi632-lpg"; > #address-cells = <1>; > #size-cells = <0>; > #pwm-cells = <2>; > nvmem-names = "lpg_chan_sdam"; > nvmem = <&pmi632_sdam7>; > qcom,pbs-phandle = <&pmi632_gpios>; > ..... > }; > Then when client is probing could do something like the following to get the regmap > > dn = of_parse_phandle(node, "qcom,pbs-phandle", 0); > pdev = of_find_device_by_node(dn); > pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); > > > > Or we could use the nvmem phandle and just have something like this in client's probe > > dn = of_parse_phandle(node, "nvmem", 0); > pdev = of_find_device_by_node(dn); > pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); > > > > Let me know what your thoughts are on this. Rob asked you - "Is there more than 1 instance in a PMIC?" - and you did not answer positively, just mentioned something about drivers in downstream, which do not matter. So is the answer for that question: yes, you have two instances of the same PMIC differing by presence of PBS and other features"? Best regards, Krzysztof
On 7/10/2023 10:58 PM, Krzysztof Kozlowski wrote: > On 11/07/2023 05:52, Anjelique Melendez wrote: >> >> >> On 7/1/2023 4:03 AM, Krzysztof Kozlowski wrote: >>> On 29/06/2023 03:19, Anjelique Melendez wrote: >>> >>>>>> +examples: >>>>>> + - | >>>>>> + pmic { >>>>>> + #address-cells = <1>; >>>>>> + #size-cells = <0>; >>>>>> + >>>>>> + qcom,pbs@7400 { >>>>>> + compatible = "qcom,pbs"; >>>>>> + reg = <0x7400>; >>>>>> + }; >>>>> >>>>> Why do you need a child node for this? Is there more than 1 instance in >>>>> a PMIC? Every sub-function of a PMIC doesn't have to have a DT node. >>>>> >>>> >>>> We currently have another downstream driver (which is planned to get upstreamed) >>>> which also needs a handle to a pbs device in order to properly trigger events. >>> >>> I don't see how does it answer Rob's concerns. Neither mine about >>> incomplete binding. You don't need pbs node here for that. >>> >>> Anyway, whatever you have downstream also does not justify any changes. >>> Either upstream these so we can see it or drop this binding. >>> >>> Best regards, >>> Krzysztof >>> >> >> On PMI632, peripherals are partitioned over 2 different SIDs >> (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n42 >> and https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n149). >> Unfortunately, the pbs peripheral and the lpg peripherals are on different >> PMI632 devices and therefore have different regmaps. >> >> If we get rid of the pbs node we need to get a handle to the proper regmap. >> I see two possible options, we could either introduce a new client property >> which points to a peripheral on the same device as pbs. >> >> i.e. >> led-controller { >> compatible = "qcom,pmi632-lpg"; >> #address-cells = <1>; >> #size-cells = <0>; >> #pwm-cells = <2>; >> nvmem-names = "lpg_chan_sdam"; >> nvmem = <&pmi632_sdam7>; >> qcom,pbs-phandle = <&pmi632_gpios>; >> ..... >> }; >> Then when client is probing could do something like the following to get the regmap >> >> dn = of_parse_phandle(node, "qcom,pbs-phandle", 0); >> pdev = of_find_device_by_node(dn); >> pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); >> >> >> >> Or we could use the nvmem phandle and just have something like this in client's probe >> >> dn = of_parse_phandle(node, "nvmem", 0); >> pdev = of_find_device_by_node(dn); >> pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); >> >> >> >> Let me know what your thoughts are on this. > > Rob asked you - "Is there more than 1 instance in a PMIC?" - and you did > not answer positively, just mentioned something about drivers in > downstream, which do not matter. So is the answer for that question: > yes, you have two instances of the same PMIC differing by presence of > PBS and other features"? > Sorry that was a misunderstanding on my part. Yes, answer to Rob's question should have been "We have two instances of PMI632, where one instance holds the pbs peripheral and the other holds the lpg peripherals. The child node for pbs is needed so lpg client can access the PMI632 regmap which contains the pbs peripheral." Thanks, Anjelique
On 11/07/2023 22:12, Anjelique Melendez wrote: >>> >>> On PMI632, peripherals are partitioned over 2 different SIDs >>> (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n42 >>> and https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n149). >>> Unfortunately, the pbs peripheral and the lpg peripherals are on different >>> PMI632 devices and therefore have different regmaps. >>> >>> If we get rid of the pbs node we need to get a handle to the proper regmap. >>> I see two possible options, we could either introduce a new client property >>> which points to a peripheral on the same device as pbs. >>> >>> i.e. >>> led-controller { >>> compatible = "qcom,pmi632-lpg"; >>> #address-cells = <1>; >>> #size-cells = <0>; >>> #pwm-cells = <2>; >>> nvmem-names = "lpg_chan_sdam"; >>> nvmem = <&pmi632_sdam7>; >>> qcom,pbs-phandle = <&pmi632_gpios>; >>> ..... >>> }; >>> Then when client is probing could do something like the following to get the regmap >>> >>> dn = of_parse_phandle(node, "qcom,pbs-phandle", 0); >>> pdev = of_find_device_by_node(dn); >>> pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); >>> >>> >>> >>> Or we could use the nvmem phandle and just have something like this in client's probe >>> >>> dn = of_parse_phandle(node, "nvmem", 0); >>> pdev = of_find_device_by_node(dn); >>> pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); >>> >>> >>> >>> Let me know what your thoughts are on this. >> >> Rob asked you - "Is there more than 1 instance in a PMIC?" - and you did >> not answer positively, just mentioned something about drivers in >> downstream, which do not matter. So is the answer for that question: >> yes, you have two instances of the same PMIC differing by presence of >> PBS and other features"? >> > Sorry that was a misunderstanding on my part. > Yes, answer to Rob's question should have been "We have two instances of PMI632, > where one instance holds the pbs peripheral and the other holds the lpg > peripherals. The child node for pbs is needed so lpg client can access > the PMI632 regmap which contains the pbs peripheral." I guess I miss here something. What is "LPG client"? I don't understand why this LPG client needs existence of PBS node, to be able to get the regmap. PBS is a child of PMIC, so it can get regmap from the parent. What's more, which DT property passes the regmap from PMIC to LPG client? Best regards, Krzysztof
On Wed, 12 Jul 2023 at 17:22, Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote: > > On 11/07/2023 22:12, Anjelique Melendez wrote: > > >>> > >>> On PMI632, peripherals are partitioned over 2 different SIDs > >>> (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n42 > >>> and https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/pmi632.dtsi?h=v6.5-rc1#n149). > >>> Unfortunately, the pbs peripheral and the lpg peripherals are on different > >>> PMI632 devices and therefore have different regmaps. > >>> > >>> If we get rid of the pbs node we need to get a handle to the proper regmap. > >>> I see two possible options, we could either introduce a new client property > >>> which points to a peripheral on the same device as pbs. > >>> > >>> i.e. > >>> led-controller { > >>> compatible = "qcom,pmi632-lpg"; > >>> #address-cells = <1>; > >>> #size-cells = <0>; > >>> #pwm-cells = <2>; > >>> nvmem-names = "lpg_chan_sdam"; > >>> nvmem = <&pmi632_sdam7>; > >>> qcom,pbs-phandle = <&pmi632_gpios>; > >>> ..... > >>> }; > >>> Then when client is probing could do something like the following to get the regmap > >>> > >>> dn = of_parse_phandle(node, "qcom,pbs-phandle", 0); > >>> pdev = of_find_device_by_node(dn); > >>> pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); > >>> > >>> > >>> > >>> Or we could use the nvmem phandle and just have something like this in client's probe > >>> > >>> dn = of_parse_phandle(node, "nvmem", 0); > >>> pdev = of_find_device_by_node(dn); > >>> pbs_regmap = dev_get_regmap(&pdev->dev->parent, NULL); > >>> > >>> > >>> > >>> Let me know what your thoughts are on this. > >> > >> Rob asked you - "Is there more than 1 instance in a PMIC?" - and you did > >> not answer positively, just mentioned something about drivers in > >> downstream, which do not matter. So is the answer for that question: > >> yes, you have two instances of the same PMIC differing by presence of > >> PBS and other features"? > >> > > Sorry that was a misunderstanding on my part. > > Yes, answer to Rob's question should have been "We have two instances of PMI632, > > where one instance holds the pbs peripheral and the other holds the lpg > > peripherals. The child node for pbs is needed so lpg client can access > > the PMI632 regmap which contains the pbs peripheral." > > I guess I miss here something. What is "LPG client"? I don't understand > why this LPG client needs existence of PBS node, to be able to get the > regmap. > > PBS is a child of PMIC, so it can get regmap from the parent. What's > more, which DT property passes the regmap from PMIC to LPG client? There are some PMICs which claim two SPMI SIDs. For such PMICs, each SID is a separate device, so it is not directly possible to get the regmap of the other SID.
On 12/07/2023 16:35, Dmitry Baryshkov wrote: >>>> Rob asked you - "Is there more than 1 instance in a PMIC?" - and you did >>>> not answer positively, just mentioned something about drivers in >>>> downstream, which do not matter. So is the answer for that question: >>>> yes, you have two instances of the same PMIC differing by presence of >>>> PBS and other features"? >>>> >>> Sorry that was a misunderstanding on my part. >>> Yes, answer to Rob's question should have been "We have two instances of PMI632, >>> where one instance holds the pbs peripheral and the other holds the lpg >>> peripherals. The child node for pbs is needed so lpg client can access >>> the PMI632 regmap which contains the pbs peripheral." >> >> I guess I miss here something. What is "LPG client"? I don't understand >> why this LPG client needs existence of PBS node, to be able to get the >> regmap. >> >> PBS is a child of PMIC, so it can get regmap from the parent. What's >> more, which DT property passes the regmap from PMIC to LPG client? > > There are some PMICs which claim two SPMI SIDs. For such PMICs, each > SID is a separate device, so it is not directly possible to get the > regmap of the other SID. OK, maybe after implementing all the review changes - including dropping that singleton pattern - this will be clearer. Please send new version and we will discuss it from there. Thank you. Best regards, Krzysztof
On 7/12/2023 1:11 PM, Krzysztof Kozlowski wrote: > On 12/07/2023 16:35, Dmitry Baryshkov wrote: >>>>> Rob asked you - "Is there more than 1 instance in a PMIC?" - and you did >>>>> not answer positively, just mentioned something about drivers in >>>>> downstream, which do not matter. So is the answer for that question: >>>>> yes, you have two instances of the same PMIC differing by presence of >>>>> PBS and other features"? >>>>> >>>> Sorry that was a misunderstanding on my part. >>>> Yes, answer to Rob's question should have been "We have two instances of PMI632, >>>> where one instance holds the pbs peripheral and the other holds the lpg >>>> peripherals. The child node for pbs is needed so lpg client can access >>>> the PMI632 regmap which contains the pbs peripheral." >>> >>> I guess I miss here something. What is "LPG client"? I don't understand >>> why this LPG client needs existence of PBS node, to be able to get the >>> regmap. >>> >>> PBS is a child of PMIC, so it can get regmap from the parent. What's >>> more, which DT property passes the regmap from PMIC to LPG client? >> >> There are some PMICs which claim two SPMI SIDs. For such PMICs, each >> SID is a separate device, so it is not directly possible to get the >> regmap of the other SID. > > OK, maybe after implementing all the review changes - including dropping > that singleton pattern - this will be clearer. Please send new version > and we will discuss it from there. > Sure, will work on getting that new version sent but I did just have clarifying question. When you say "dropping that singleton pattern" are you referring to dropping the PBS node? Want to make sure we are all on the same page with what the next version will include :) Thanks, Anjelique
On 14/07/2023 22:32, Anjelique Melendez wrote: > > > On 7/12/2023 1:11 PM, Krzysztof Kozlowski wrote: >> On 12/07/2023 16:35, Dmitry Baryshkov wrote: >>>>>> Rob asked you - "Is there more than 1 instance in a PMIC?" - and you did >>>>>> not answer positively, just mentioned something about drivers in >>>>>> downstream, which do not matter. So is the answer for that question: >>>>>> yes, you have two instances of the same PMIC differing by presence of >>>>>> PBS and other features"? >>>>>> >>>>> Sorry that was a misunderstanding on my part. >>>>> Yes, answer to Rob's question should have been "We have two instances of PMI632, >>>>> where one instance holds the pbs peripheral and the other holds the lpg >>>>> peripherals. The child node for pbs is needed so lpg client can access >>>>> the PMI632 regmap which contains the pbs peripheral." >>>> >>>> I guess I miss here something. What is "LPG client"? I don't understand >>>> why this LPG client needs existence of PBS node, to be able to get the >>>> regmap. >>>> >>>> PBS is a child of PMIC, so it can get regmap from the parent. What's >>>> more, which DT property passes the regmap from PMIC to LPG client? >>> >>> There are some PMICs which claim two SPMI SIDs. For such PMICs, each >>> SID is a separate device, so it is not directly possible to get the >>> regmap of the other SID. >> >> OK, maybe after implementing all the review changes - including dropping >> that singleton pattern - this will be clearer. Please send new version >> and we will discuss it from there. >> > Sure, will work on getting that new version sent but I did just have clarifying question. > When you say "dropping that singleton pattern" are you referring to dropping the > PBS node? > Want to make sure we are all on the same page with what the next version will include :) I was referring to my comments on driver, that you should not have file-scope variable and get_pbs_client_device() iterating over global list. It isn't singleton, actually, but the pattern in coding is very similar to singleton approach. Best regards, Krzysztof