2023-06-09 15:53:48

by Raymond Hackley

[permalink] [raw]
Subject: [PATCH v2 0/2] NFC: nxp-nci: Add pad supply voltage pvdd-supply

v2: Use dev_err_probe() and drop unnecessary nxp_nci_i2c_poweroff()

PN547/553, QN310/330 chips on some devices require a pad supply voltage
(PVDD). Otherwise, the NFC won't power up.

Implement support for pad supply voltage pvdd-supply that is enabled by
the nxp-nci driver so that the regulator gets enabled when needed.



2023-06-09 15:55:12

by Raymond Hackley

[permalink] [raw]
Subject: [PATCH v2 2/2] NFC: nxp-nci: Add pad supply voltage pvdd-supply

PN547/553, QN310/330 chips on some devices require a pad supply voltage
(PVDD). Otherwise, the NFC won't power up.

Implement support for pad supply voltage pvdd-supply that is enabled by
the nxp-nci driver so that the regulator gets enabled when needed.

Signed-off-by: Raymond Hackley <[email protected]>
---
drivers/nfc/nxp-nci/i2c.c | 42 +++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)

diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
index d4c299be7949..1b8877757cee 100644
--- a/drivers/nfc/nxp-nci/i2c.c
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -35,6 +35,7 @@ struct nxp_nci_i2c_phy {

struct gpio_desc *gpiod_en;
struct gpio_desc *gpiod_fw;
+ struct regulator *pvdd;

int hard_fault; /*
* < 0 if hardware error occurred (e.g. i2c err)
@@ -263,6 +264,22 @@ static const struct acpi_gpio_mapping acpi_nxp_nci_gpios[] = {
{ }
};

+static void nxp_nci_i2c_poweroff(void *data)
+{
+ struct nxp_nci_i2c_phy *phy = data;
+ struct device *dev = &phy->i2c_dev->dev;
+ struct regulator *pvdd = phy->pvdd;
+ int r;
+
+ if (!IS_ERR(pvdd) && regulator_is_enabled(pvdd)) {
+ r = regulator_disable(pvdd);
+ if (r < 0)
+ dev_warn(dev,
+ "Failed to disable regulator pvdd: %d\n",
+ r);
+ }
+}
+
static int nxp_nci_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -298,6 +315,29 @@ static int nxp_nci_i2c_probe(struct i2c_client *client)
return PTR_ERR(phy->gpiod_fw);
}

+ phy->pvdd = devm_regulator_get_optional(dev, "pvdd");
+ if (IS_ERR(phy->pvdd)) {
+ r = PTR_ERR(phy->pvdd);
+ if (r != -ENODEV)
+ return dev_err_probe(dev, r,
+ "Failed to get regulator pvdd\n");
+ } else {
+ r = regulator_enable(phy->pvdd);
+ if (r < 0) {
+ nfc_err(dev,
+ "Failed to enable regulator pvdd: %d\n",
+ r);
+ return r;
+ }
+ }
+
+ r = devm_add_action_or_reset(dev, nxp_nci_i2c_poweroff, phy);
+ if (r < 0) {
+ nfc_err(dev, "Failed to install poweroff handler: %d\n",
+ r);
+ return r;
+ }
+
r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
if (r < 0)
@@ -319,6 +359,8 @@ static void nxp_nci_i2c_remove(struct i2c_client *client)

nxp_nci_remove(phy->ndev);
free_irq(client->irq, phy);
+
+ nxp_nci_i2c_poweroff(phy);
}

static const struct i2c_device_id nxp_nci_i2c_id_table[] = {
--
2.30.2



2023-06-09 15:56:52

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] NFC: nxp-nci: Add pad supply voltage pvdd-supply

On 09/06/2023 17:42, Raymond Hackley wrote:
> PN547/553, QN310/330 chips on some devices require a pad supply voltage
> (PVDD). Otherwise, the NFC won't power up.
>
> Implement support for pad supply voltage pvdd-supply that is enabled by
> the nxp-nci driver so that the regulator gets enabled when needed.
>
> Signed-off-by: Raymond Hackley <[email protected]>
> ---
> drivers/nfc/nxp-nci/i2c.c | 42 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
> index d4c299be7949..1b8877757cee 100644
> --- a/drivers/nfc/nxp-nci/i2c.c
> +++ b/drivers/nfc/nxp-nci/i2c.c
> @@ -35,6 +35,7 @@ struct nxp_nci_i2c_phy {
>
> struct gpio_desc *gpiod_en;
> struct gpio_desc *gpiod_fw;
> + struct regulator *pvdd;
>
> int hard_fault; /*
> * < 0 if hardware error occurred (e.g. i2c err)
> @@ -263,6 +264,22 @@ static const struct acpi_gpio_mapping acpi_nxp_nci_gpios[] = {
> { }
> };
>
> +static void nxp_nci_i2c_poweroff(void *data)
> +{
> + struct nxp_nci_i2c_phy *phy = data;
> + struct device *dev = &phy->i2c_dev->dev;
> + struct regulator *pvdd = phy->pvdd;
> + int r;
> +
> + if (!IS_ERR(pvdd) && regulator_is_enabled(pvdd)) {

Why do you need these checks? This should be called in correct context,
so when regulator is valid and enabled. If you have such checks it
suggests that code is buggy and this is being called in wrong contexts.

> + r = regulator_disable(pvdd);
> + if (r < 0)
> + dev_warn(dev,
> + "Failed to disable regulator pvdd: %d\n",
> + r);

Weird wrapping. Why r is wrapped?

> + }
> +}
> +
> static int nxp_nci_i2c_probe(struct i2c_client *client)
> {
> struct device *dev = &client->dev;
> @@ -298,6 +315,29 @@ static int nxp_nci_i2c_probe(struct i2c_client *client)
> return PTR_ERR(phy->gpiod_fw);
> }
>
> + phy->pvdd = devm_regulator_get_optional(dev, "pvdd");
> + if (IS_ERR(phy->pvdd)) {
> + r = PTR_ERR(phy->pvdd);
> + if (r != -ENODEV)
> + return dev_err_probe(dev, r,
> + "Failed to get regulator pvdd\n");
> + } else {
> + r = regulator_enable(phy->pvdd);
> + if (r < 0) {
> + nfc_err(dev,
> + "Failed to enable regulator pvdd: %d\n",
> + r);

Weird wrapping. Why r is wrapped?

> + return r;
> + }
> + }
> +
> + r = devm_add_action_or_reset(dev, nxp_nci_i2c_poweroff, phy);
> + if (r < 0) {
> + nfc_err(dev, "Failed to install poweroff handler: %d\n",
> + r);

Weird wrapping. Why r is wrapped?

Just move it to the success path of enabling regulator.


> + return r;
> + }
> +
> r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
> NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
> if (r < 0)
> @@ -319,6 +359,8 @@ static void nxp_nci_i2c_remove(struct i2c_client *client)
>
> nxp_nci_remove(phy->ndev);
> free_irq(client->irq, phy);
> +
> + nxp_nci_i2c_poweroff(phy);

Why? This code is buggy...



Best regards,
Krzysztof


2023-06-09 16:03:58

by Raymond Hackley

[permalink] [raw]
Subject: [PATCH v2 1/2] dt-bindings: nfc: nxp-nci: document pvdd-supply

PN547/553, QN310/330 chips on some devices require a pad supply voltage
(PVDD). Otherwise, the NFC won't power up.

Document support for pad supply voltage pvdd-supply that is enabled by
the nxp-nci driver so that the regulator gets enabled when needed.

Signed-off-by: Raymond Hackley <[email protected]>
Acked-by: Krzysztof Kozlowski <[email protected]>
---
Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml b/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml
index 6924aff0b2c5..d5a4f935c2ce 100644
--- a/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml
+++ b/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml
@@ -25,6 +25,11 @@ properties:
firmware-gpios:
description: Output GPIO pin used to enter firmware download mode

+ pvdd-supply:
+ description: |
+ Optional regulator that provides pad supply voltage for some
+ controllers
+
interrupts:
maxItems: 1

--
2.30.2



2023-06-09 18:18:11

by Raymond Hackley

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] NFC: nxp-nci: Add pad supply voltage pvdd-supply

Hi Krzysztof,

On Friday, June 9th, 2023 at 3:46 PM, Krzysztof Kozlowski <[email protected]> wrote:


> On 09/06/2023 17:42, Raymond Hackley wrote:
>
> > PN547/553, QN310/330 chips on some devices require a pad supply voltage
> > (PVDD). Otherwise, the NFC won't power up.
> >
> > Implement support for pad supply voltage pvdd-supply that is enabled by
> > the nxp-nci driver so that the regulator gets enabled when needed.
> >
> > Signed-off-by: Raymond Hackley [email protected]
> > ---
> > drivers/nfc/nxp-nci/i2c.c | 42 +++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 42 insertions(+)
> >
> > diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
> > index d4c299be7949..1b8877757cee 100644
> > --- a/drivers/nfc/nxp-nci/i2c.c
> > +++ b/drivers/nfc/nxp-nci/i2c.c
> > @@ -35,6 +35,7 @@ struct nxp_nci_i2c_phy {
> >
> > struct gpio_desc *gpiod_en;
> > struct gpio_desc *gpiod_fw;
> > + struct regulator *pvdd;
> >
> > int hard_fault; /*
> > * < 0 if hardware error occurred (e.g. i2c err)
> > @@ -263,6 +264,22 @@ static const struct acpi_gpio_mapping acpi_nxp_nci_gpios[] = {
> > { }
> > };
> >
> > +static void nxp_nci_i2c_poweroff(void *data)
> > +{
> > + struct nxp_nci_i2c_phy *phy = data;
> > + struct device *dev = &phy->i2c_dev->dev;
> > + struct regulator *pvdd = phy->pvdd;
> > + int r;
> > +
> > + if (!IS_ERR(pvdd) && regulator_is_enabled(pvdd)) {
>
>
> Why do you need these checks? This should be called in correct context,
> so when regulator is valid and enabled. If you have such checks it
> suggests that code is buggy and this is being called in wrong contexts.
>

First condition !IS_ERR(pvdd) is to check if pvdd exists.
Some devices, msm8916-samsung-serranove for example, doesn't need pvdd or
have it bound in the device tree:

https://github.com/torvalds/linux/commit/ab0f0987e035f908d670fed7d86efa6fac66c0bb

Without !IS_ERR(pvdd), checking it with regulator_is_enabled(pvdd):

[ 50.161882] 8<--- cut here ---
[ 50.161906] Unable to handle kernel paging request at virtual address fffffff9 when read
[ 50.161916] [fffffff9] *pgd=affff841, *pte=00000000, *ppte=00000000
[ 50.161938] Internal error: Oops: 27 [#1] PREEMPT SMP ARM

Or disabling it directly with regulator_disable(pvdd):

[ 69.439827] 8<--- cut here ---
[ 69.439841] Unable to handle kernel NULL pointer dereference at virtual address 00000045 when read
[ 69.439852] [00000045] *pgd=00000000
[ 69.439864] Internal error: Oops: 5 [#1] PREEMPT SMP ARM

Second condition regulator_is_enabled(pvdd) is to make sure that pvdd is
disabled with balance.

Similar checks can be found here:

https://elixir.bootlin.com/linux/v6.4-rc5/source/drivers/staging/greybus/arche-apb-ctrl.c#L208

> > + r = regulator_disable(pvdd);
> > + if (r < 0)
> > + dev_warn(dev,
> > + "Failed to disable regulator pvdd: %d\n",
> > + r);
>
>
> Weird wrapping. Why r is wrapped?
>
> > + }
> > +}
> > +
> > static int nxp_nci_i2c_probe(struct i2c_client *client)
> > {
> > struct device *dev = &client->dev;
> > @@ -298,6 +315,29 @@ static int nxp_nci_i2c_probe(struct i2c_client *client)
> > return PTR_ERR(phy->gpiod_fw);
> > }
> >
> > + phy->pvdd = devm_regulator_get_optional(dev, "pvdd");
> > + if (IS_ERR(phy->pvdd)) {
> > + r = PTR_ERR(phy->pvdd);
> > + if (r != -ENODEV)
> > + return dev_err_probe(dev, r,
> > + "Failed to get regulator pvdd\n");
> > + } else {
> > + r = regulator_enable(phy->pvdd);
> > + if (r < 0) {
> > + nfc_err(dev,
> > + "Failed to enable regulator pvdd: %d\n",
> > + r);
>
>
> Weird wrapping. Why r is wrapped?
>
> > + return r;
> > + }
> > + }
> > +
> > + r = devm_add_action_or_reset(dev, nxp_nci_i2c_poweroff, phy);
> > + if (r < 0) {
> > + nfc_err(dev, "Failed to install poweroff handler: %d\n",
> > + r);
>
>
> Weird wrapping. Why r is wrapped?
>
> Just move it to the success path of enabling regulator.
>

Yes. This will be fixed in v3.

> > + return r;
> > + }
> > +
> > r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
> > NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
> > if (r < 0)
> > @@ -319,6 +359,8 @@ static void nxp_nci_i2c_remove(struct i2c_client *client)
> >
> > nxp_nci_remove(phy->ndev);
> > free_irq(client->irq, phy);
> > +
> > + nxp_nci_i2c_poweroff(phy);
>
>
> Why? This code is buggy...
>

I don't have a good reason to keep it and will drop it in v3.

Regards,
Raymond

>
>
> Best regards,
> Krzysztof


2023-06-09 19:52:16

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] NFC: nxp-nci: Add pad supply voltage pvdd-supply

On 09/06/2023 19:40, Raymond Hackley wrote:
> Hi Krzysztof,
>
> On Friday, June 9th, 2023 at 3:46 PM, Krzysztof Kozlowski <[email protected]> wrote:
>
>
>> On 09/06/2023 17:42, Raymond Hackley wrote:
>>
>>> PN547/553, QN310/330 chips on some devices require a pad supply voltage
>>> (PVDD). Otherwise, the NFC won't power up.
>>>
>>> Implement support for pad supply voltage pvdd-supply that is enabled by
>>> the nxp-nci driver so that the regulator gets enabled when needed.
>>>
>>> Signed-off-by: Raymond Hackley [email protected]
>>> ---
>>> drivers/nfc/nxp-nci/i2c.c | 42 +++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 42 insertions(+)
>>>
>>> diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
>>> index d4c299be7949..1b8877757cee 100644
>>> --- a/drivers/nfc/nxp-nci/i2c.c
>>> +++ b/drivers/nfc/nxp-nci/i2c.c
>>> @@ -35,6 +35,7 @@ struct nxp_nci_i2c_phy {
>>>
>>> struct gpio_desc *gpiod_en;
>>> struct gpio_desc *gpiod_fw;
>>> + struct regulator *pvdd;
>>>
>>> int hard_fault; /*
>>> * < 0 if hardware error occurred (e.g. i2c err)
>>> @@ -263,6 +264,22 @@ static const struct acpi_gpio_mapping acpi_nxp_nci_gpios[] = {
>>> { }
>>> };
>>>
>>> +static void nxp_nci_i2c_poweroff(void *data)
>>> +{
>>> + struct nxp_nci_i2c_phy *phy = data;
>>> + struct device *dev = &phy->i2c_dev->dev;
>>> + struct regulator *pvdd = phy->pvdd;
>>> + int r;
>>> +
>>> + if (!IS_ERR(pvdd) && regulator_is_enabled(pvdd)) {
>>
>>
>> Why do you need these checks? This should be called in correct context,
>> so when regulator is valid and enabled. If you have such checks it
>> suggests that code is buggy and this is being called in wrong contexts.
>>
>
> First condition !IS_ERR(pvdd) is to check if pvdd exists.
> Some devices, msm8916-samsung-serranove for example, doesn't need pvdd or
> have it bound in the device tree:

If regulator is missing you should get a dummy.

But anyway the code will not be executed if you don't get proper regulator.

>
> https://github.com/torvalds/linux/commit/ab0f0987e035f908d670fed7d86efa6fac66c0bb
>
> Without !IS_ERR(pvdd), checking it with regulator_is_enabled(pvdd):
>
> [ 50.161882] 8<--- cut here ---
> [ 50.161906] Unable to handle kernel paging request at virtual address fffffff9 when read
> [ 50.161916] [fffffff9] *pgd=affff841, *pte=00000000, *ppte=00000000
> [ 50.161938] Internal error: Oops: 27 [#1] PREEMPT SMP ARM
>
> Or disabling it directly with regulator_disable(pvdd):
>
> [ 69.439827] 8<--- cut here ---
> [ 69.439841] Unable to handle kernel NULL pointer dereference at virtual address 00000045 when read
> [ 69.439852] [00000045] *pgd=00000000
> [ 69.439864] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>
> Second condition regulator_is_enabled(pvdd) is to make sure that pvdd is
> disabled with balance.
>

So you have buggy code and to hide the bug you add checks? No, make the
code correct so the check is not needed.


> Similar checks can be found here:
>
> https://elixir.bootlin.com/linux/v6.4-rc5/source/drivers/staging/greybus/arche-apb-ctrl.c#L208

staging driver is not an example...

>


Best regards,
Krzysztof


2023-06-09 19:56:50

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] NFC: nxp-nci: Add pad supply voltage pvdd-supply

On Fri, Jun 09, 2023 at 09:29:51PM +0200, Krzysztof Kozlowski wrote:
> On 09/06/2023 19:40, Raymond Hackley wrote:
> > On Friday, June 9th, 2023 at 3:46 PM, Krzysztof Kozlowski <[email protected]> wrote:

> > Second condition regulator_is_enabled(pvdd) is to make sure that pvdd is
> > disabled with balance.

> So you have buggy code and to hide the bug you add checks? No, make the
> code correct so the check is not needed.

Specifically your driver should only ever call regulator_disable() to
balance out regulator_enable() calls it made itself and it should know
how many of those it has done. regulator_is_enabled() should only ever
be used during probe if for some reason it is important to figure out if
the device is already powered for startup, this should be very unusual.
If something else enabled the regualtor then whatever did that needs to
undo those enables, not another driver.


Attachments:
(No filename) (928.00 B)
signature.asc (499.00 B)
Download all attachments

2023-06-09 21:24:53

by Raymond Hackley

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] NFC: nxp-nci: Add pad supply voltage pvdd-supply

Hi Krzysztof,

On Friday, June 9th, 2023 at 7:29 PM, Krzysztof Kozlowski <[email protected]> wrote:

> > > Why do you need these checks? This should be called in correct context,
> > > so when regulator is valid and enabled. If you have such checks it
> > > suggests that code is buggy and this is being called in wrong contexts.
> >
> > First condition !IS_ERR(pvdd) is to check if pvdd exists.
> > Some devices, msm8916-samsung-serranove for example, doesn't need pvdd or
> > have it bound in the device tree:
>
>
> If regulator is missing you should get a dummy.
>
> But anyway the code will not be executed if you don't get proper regulator.
>

The current patch set is using devm_regulator_get_optional() instead of
devm_regulator_get(), which doesn't get a dummy regulator.

> > https://github.com/torvalds/linux/commit/ab0f0987e035f908d670fed7d86efa6fac66c0bb
> >
> > Without !IS_ERR(pvdd), checking it with regulator_is_enabled(pvdd):
> >
> > [ 50.161882] 8<--- cut here ---
> > [ 50.161906] Unable to handle kernel paging request at virtual address fffffff9 when read
> > [ 50.161916] [fffffff9] *pgd=affff841, *pte=00000000, *ppte=00000000
> > [ 50.161938] Internal error: Oops: 27 [#1] PREEMPT SMP ARM
> >
> > Or disabling it directly with regulator_disable(pvdd):
> >
> > [ 69.439827] 8<--- cut here ---
> > [ 69.439841] Unable to handle kernel NULL pointer dereference at virtual address 00000045 when read
> > [ 69.439852] [00000045] *pgd=00000000
> > [ 69.439864] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >
> > Second condition regulator_is_enabled(pvdd) is to make sure that pvdd is
> > disabled with balance.
>
>
> So you have buggy code and to hide the bug you add checks? No, make the
> code correct so the check is not needed.
>

Do you mean that I should use devm_regulator_get() instead in order to get
a dummy regulator, so that it can disable pvdd without unnecessary checks?
Actually there is v4 with those buggy codes and checks dropped.
Please do let me know if I am understanding and doing it correctly. I would
send it after proper period of cooldown.

Regards,
Raymond


2023-06-09 21:24:53

by Raymond Hackley

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] NFC: nxp-nci: Add pad supply voltage pvdd-supply

Hi Mark,

On Friday, June 9th, 2023 at 7:34 PM, Mark Brown <[email protected]> wrote:

> Specifically your driver should only ever call regulator_disable() to
> balance out regulator_enable() calls it made itself and it should know
> how many of those it has done. regulator_is_enabled() should only ever
> be used during probe if for some reason it is important to figure out if
> the device is already powered for startup, this should be very unusual.
> If something else enabled the regualtor then whatever did that needs to
> undo those enables, not another driver.

Thnak you for explanation. I should drop regulator_is_enabled() here since
it's misused.

Regards,
Raymond