diff mbox series

[V15,6/9] mfd: pm8008: Use i2c_new_dummy_device() API

Message ID 1655200111-18357-7-git-send-email-quic_c_skakit@quicinc.com (mailing list archive)
State Not Applicable
Headers show
Series Add Qualcomm Technologies, Inc. PM8008 regulator driver | expand

Commit Message

Satya Priya Kakitapalli (Temp) June 14, 2022, 9:48 a.m. UTC
Use i2c_new_dummy_device() to register pm8008-regulator
client present at a different address space, instead of
defining a separate DT node. This avoids calling the probe
twice for the same chip, once for each client pm8008-infra
and pm8008-regulator.

As a part of this define pm8008_regmap_init() to do regmap
init for both the clients and define pm8008_get_regmap() to
pass the regmap to the regulator driver.

Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
---
Changes in V15:
 - None.

Changes in V14:
 - None.

Changes in V13:
 - None.

 drivers/mfd/qcom-pm8008.c       | 34 ++++++++++++++++++++++++++++++++--
 include/linux/mfd/qcom_pm8008.h |  9 +++++++++
 2 files changed, 41 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/mfd/qcom_pm8008.h

Comments

Lee Jones June 16, 2022, 8:57 p.m. UTC | #1
On Tue, 14 Jun 2022, Satya Priya wrote:

> Use i2c_new_dummy_device() to register pm8008-regulator
> client present at a different address space, instead of
> defining a separate DT node. This avoids calling the probe
> twice for the same chip, once for each client pm8008-infra
> and pm8008-regulator.
> 
> As a part of this define pm8008_regmap_init() to do regmap
> init for both the clients and define pm8008_get_regmap() to
> pass the regmap to the regulator driver.
> 
> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> ---
> Changes in V15:
>  - None.
> 
> Changes in V14:
>  - None.
> 
> Changes in V13:
>  - None.
> 
>  drivers/mfd/qcom-pm8008.c       | 34 ++++++++++++++++++++++++++++++++--
>  include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>  2 files changed, 41 insertions(+), 2 deletions(-)
>  create mode 100644 include/linux/mfd/qcom_pm8008.h
> 
> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> index 569ffd50..55e2a8e 100644
> --- a/drivers/mfd/qcom-pm8008.c
> +++ b/drivers/mfd/qcom-pm8008.c
> @@ -9,6 +9,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/irqdomain.h>
> +#include <linux/mfd/qcom_pm8008.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
>  #include <linux/of_platform.h>
> @@ -57,6 +58,7 @@ enum {
>  
>  struct pm8008_data {
>  	struct device *dev;
> +	struct regmap *regulators_regmap;
>  	int irq;
>  	struct regmap_irq_chip_data *irq_data;
>  };
> @@ -150,6 +152,12 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>  	.max_register	= 0xFFFF,
>  };
>  
> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> +{
> +	return chip->regulators_regmap;
> +}
> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);

Seems like abstraction for the sake of abstraction.

Why not do the dereference inside the regulator driver?

>  static int pm8008_init(struct regmap *regmap)
>  {
>  	int rc;
> @@ -217,11 +225,25 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>  	return 0;
>  }
>  
> +static struct regmap *pm8008_regmap_init(struct i2c_client *client,
> +							struct pm8008_data *chip)
> +{
> +	struct regmap *regmap;
> +
> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> +	if (!regmap)
> +		return NULL;
> +
> +	i2c_set_clientdata(client, chip);
> +	return regmap;
> +}

This function seems superfluous.

It's only called once and it contains a single call.

Just pop the call directly into probe.

>  static int pm8008_probe(struct i2c_client *client)
>  {
>  	int rc;
>  	struct pm8008_data *chip;
>  	struct gpio_desc *reset_gpio;
> +	struct i2c_client *regulators_client;
>  	struct regmap *regmap;
>  
>  	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> @@ -229,11 +251,19 @@ static int pm8008_probe(struct i2c_client *client)
>  		return -ENOMEM;
>  
>  	chip->dev = &client->dev;
> -	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> +	regmap = pm8008_regmap_init(client, chip);
>  	if (!regmap)
>  		return -ENODEV;
>  
> -	i2c_set_clientdata(client, chip);
> +	regulators_client = i2c_new_dummy_device(client->adapter, client->addr + 1);
> +	if (IS_ERR(regulators_client)) {
> +		dev_err(&client->dev, "can't attach client\n");
> +		return PTR_ERR(regulators_client);
> +	}
> +
> +	chip->regulators_regmap = pm8008_regmap_init(regulators_client, chip);
> +	if (!chip->regulators_regmap)
> +		return -ENODEV;
>  
>  	reset_gpio = devm_gpiod_get(chip->dev, "reset", GPIOD_OUT_LOW);
>  	if (IS_ERR(reset_gpio))
> diff --git a/include/linux/mfd/qcom_pm8008.h b/include/linux/mfd/qcom_pm8008.h
> new file mode 100644
> index 0000000..3814bff
> --- /dev/null
> +++ b/include/linux/mfd/qcom_pm8008.h
> @@ -0,0 +1,9 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> +#ifndef __QCOM_PM8008_H__
> +#define __QCOM_PM8008_H__
> +
> +struct pm8008_data;
> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip);
> +
> +#endif
Satya Priya Kakitapalli (Temp) June 20, 2022, 5:28 a.m. UTC | #2
On 6/17/2022 2:27 AM, Lee Jones wrote:
> On Tue, 14 Jun 2022, Satya Priya wrote:
>
>> Use i2c_new_dummy_device() to register pm8008-regulator
>> client present at a different address space, instead of
>> defining a separate DT node. This avoids calling the probe
>> twice for the same chip, once for each client pm8008-infra
>> and pm8008-regulator.
>>
>> As a part of this define pm8008_regmap_init() to do regmap
>> init for both the clients and define pm8008_get_regmap() to
>> pass the regmap to the regulator driver.
>>
>> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
>> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
>> ---
>> Changes in V15:
>>   - None.
>>
>> Changes in V14:
>>   - None.
>>
>> Changes in V13:
>>   - None.
>>
>>   drivers/mfd/qcom-pm8008.c       | 34 ++++++++++++++++++++++++++++++++--
>>   include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>   2 files changed, 41 insertions(+), 2 deletions(-)
>>   create mode 100644 include/linux/mfd/qcom_pm8008.h
>>
>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>> index 569ffd50..55e2a8e 100644
>> --- a/drivers/mfd/qcom-pm8008.c
>> +++ b/drivers/mfd/qcom-pm8008.c
>> @@ -9,6 +9,7 @@
>>   #include <linux/interrupt.h>
>>   #include <linux/irq.h>
>>   #include <linux/irqdomain.h>
>> +#include <linux/mfd/qcom_pm8008.h>
>>   #include <linux/module.h>
>>   #include <linux/of_device.h>
>>   #include <linux/of_platform.h>
>> @@ -57,6 +58,7 @@ enum {
>>   
>>   struct pm8008_data {
>>   	struct device *dev;
>> +	struct regmap *regulators_regmap;
>>   	int irq;
>>   	struct regmap_irq_chip_data *irq_data;
>>   };
>> @@ -150,6 +152,12 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>   	.max_register	= 0xFFFF,
>>   };
>>   
>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>> +{
>> +	return chip->regulators_regmap;
>> +}
>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> Seems like abstraction for the sake of abstraction.
>
> Why not do the dereference inside the regulator driver?


To derefer this in the regulator driver, we need to have the pm8008_data 
struct definition in the qcom_pm8008 header file.

I think it doesn't look great to have only that structure in header and 
all other structs and enum in the mfd driver.


>>   static int pm8008_init(struct regmap *regmap)
>>   {
>>   	int rc;
>> @@ -217,11 +225,25 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>   	return 0;
>>   }
>>   
>> +static struct regmap *pm8008_regmap_init(struct i2c_client *client,
>> +							struct pm8008_data *chip)
>> +{
>> +	struct regmap *regmap;
>> +
>> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>> +	if (!regmap)
>> +		return NULL;
>> +
>> +	i2c_set_clientdata(client, chip);
>> +	return regmap;
>> +}
> This function seems superfluous.
>
> It's only called once and it contains a single call.


No, It is being called twice. To avoid repetitive code, I've added this 
subroutine.


> Just pop the call directly into probe.
>
>>   static int pm8008_probe(struct i2c_client *client)
>>   {
>>   	int rc;
>>   	struct pm8008_data *chip;
>>   	struct gpio_desc *reset_gpio;
>> +	struct i2c_client *regulators_client;
>>   	struct regmap *regmap;
>>   
>>   	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
>> @@ -229,11 +251,19 @@ static int pm8008_probe(struct i2c_client *client)
>>   		return -ENOMEM;
>>   
>>   	chip->dev = &client->dev;
>> -	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>> +	regmap = pm8008_regmap_init(client, chip);
>>   	if (!regmap)
>>   		return -ENODEV;
>>   
>> -	i2c_set_clientdata(client, chip);
>> +	regulators_client = i2c_new_dummy_device(client->adapter, client->addr + 1);
>> +	if (IS_ERR(regulators_client)) {
>> +		dev_err(&client->dev, "can't attach client\n");
>> +		return PTR_ERR(regulators_client);
>> +	}
>> +
>> +	chip->regulators_regmap = pm8008_regmap_init(regulators_client, chip);
>> +	if (!chip->regulators_regmap)
>> +		return -ENODEV;
>>   
>>   	reset_gpio = devm_gpiod_get(chip->dev, "reset", GPIOD_OUT_LOW);
>>   	if (IS_ERR(reset_gpio))
>> diff --git a/include/linux/mfd/qcom_pm8008.h b/include/linux/mfd/qcom_pm8008.h
>> new file mode 100644
>> index 0000000..3814bff
>> --- /dev/null
>> +++ b/include/linux/mfd/qcom_pm8008.h
>> @@ -0,0 +1,9 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +// Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
>> +#ifndef __QCOM_PM8008_H__
>> +#define __QCOM_PM8008_H__
>> +
>> +struct pm8008_data;
>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip);
>> +
>> +#endif
Lee Jones June 20, 2022, 8:20 a.m. UTC | #3
On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 6/17/2022 2:27 AM, Lee Jones wrote:
> > On Tue, 14 Jun 2022, Satya Priya wrote:
> > 
> > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > client present at a different address space, instead of
> > > defining a separate DT node. This avoids calling the probe
> > > twice for the same chip, once for each client pm8008-infra
> > > and pm8008-regulator.
> > > 
> > > As a part of this define pm8008_regmap_init() to do regmap
> > > init for both the clients and define pm8008_get_regmap() to
> > > pass the regmap to the regulator driver.
> > > 
> > > Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
> > > Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> > > ---
> > > Changes in V15:
> > >   - None.
> > > 
> > > Changes in V14:
> > >   - None.
> > > 
> > > Changes in V13:
> > >   - None.
> > > 
> > >   drivers/mfd/qcom-pm8008.c       | 34 ++++++++++++++++++++++++++++++++--
> > >   include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > >   2 files changed, 41 insertions(+), 2 deletions(-)
> > >   create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > 
> > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > index 569ffd50..55e2a8e 100644
> > > --- a/drivers/mfd/qcom-pm8008.c
> > > +++ b/drivers/mfd/qcom-pm8008.c
> > > @@ -9,6 +9,7 @@
> > >   #include <linux/interrupt.h>
> > >   #include <linux/irq.h>
> > >   #include <linux/irqdomain.h>
> > > +#include <linux/mfd/qcom_pm8008.h>
> > >   #include <linux/module.h>
> > >   #include <linux/of_device.h>
> > >   #include <linux/of_platform.h>
> > > @@ -57,6 +58,7 @@ enum {
> > >   struct pm8008_data {
> > >   	struct device *dev;
> > > +	struct regmap *regulators_regmap;
> > >   	int irq;
> > >   	struct regmap_irq_chip_data *irq_data;
> > >   };
> > > @@ -150,6 +152,12 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
> > >   	.max_register	= 0xFFFF,
> > >   };
> > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > +{
> > > +	return chip->regulators_regmap;
> > > +}
> > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > Seems like abstraction for the sake of abstraction.
> > 
> > Why not do the dereference inside the regulator driver?
> 
> To derefer this in the regulator driver, we need to have the pm8008_data
> struct definition in the qcom_pm8008 header file.
> 
> I think it doesn't look great to have only that structure in header and all
> other structs and enum in the mfd driver.

Then why pass 'pm8008_data' at all?

What's preventing you from passing 'regmap'?
Satya Priya Kakitapalli (Temp) June 20, 2022, 11:07 a.m. UTC | #4
On 6/20/2022 1:50 PM, Lee Jones wrote:
> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>
>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>> client present at a different address space, instead of
>>>> defining a separate DT node. This avoids calling the probe
>>>> twice for the same chip, once for each client pm8008-infra
>>>> and pm8008-regulator.
>>>>
>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>> init for both the clients and define pm8008_get_regmap() to
>>>> pass the regmap to the regulator driver.
>>>>
>>>> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
>>>> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
>>>> ---
>>>> Changes in V15:
>>>>    - None.
>>>>
>>>> Changes in V14:
>>>>    - None.
>>>>
>>>> Changes in V13:
>>>>    - None.
>>>>
>>>>    drivers/mfd/qcom-pm8008.c       | 34 ++++++++++++++++++++++++++++++++--
>>>>    include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>    2 files changed, 41 insertions(+), 2 deletions(-)
>>>>    create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>
>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>> index 569ffd50..55e2a8e 100644
>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>> @@ -9,6 +9,7 @@
>>>>    #include <linux/interrupt.h>
>>>>    #include <linux/irq.h>
>>>>    #include <linux/irqdomain.h>
>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>    #include <linux/module.h>
>>>>    #include <linux/of_device.h>
>>>>    #include <linux/of_platform.h>
>>>> @@ -57,6 +58,7 @@ enum {
>>>>    struct pm8008_data {
>>>>    	struct device *dev;
>>>> +	struct regmap *regulators_regmap;
>>>>    	int irq;
>>>>    	struct regmap_irq_chip_data *irq_data;
>>>>    };
>>>> @@ -150,6 +152,12 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>>>    	.max_register	= 0xFFFF,
>>>>    };
>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>> +{
>>>> +	return chip->regulators_regmap;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>> Seems like abstraction for the sake of abstraction.
>>>
>>> Why not do the dereference inside the regulator driver?
>> To derefer this in the regulator driver, we need to have the pm8008_data
>> struct definition in the qcom_pm8008 header file.
>>
>> I think it doesn't look great to have only that structure in header and all
>> other structs and enum in the mfd driver.
> Then why pass 'pm8008_data' at all?


There is one more option, instead of passing the pm8008_data, we could 
pass the pdev->dev.parent and get the pm8008 chip data directly in the 
pm8008_get_regmap() like below


struct regmap *pm8008_get_regmap(const struct device *dev)
  {
      const struct pm8008_data *chip = dev_get_drvdata(dev);

      return chip->regulators_regmap;
}
EXPORT_SYMBOL_GPL(pm8008_get_regmap);


By doing this we can avoid having declaration of pm8008_data also in the 
header. Please let me know if this looks good.

> What's preventing you from passing 'regmap'?


I didn't get what you meant here, could you please elaborate a bit?
Satya Priya Kakitapalli (Temp) June 27, 2022, 5:07 a.m. UTC | #5
Hi Lee,


On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>
> On 6/20/2022 1:50 PM, Lee Jones wrote:
>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>
>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>
>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>> client present at a different address space, instead of
>>>>> defining a separate DT node. This avoids calling the probe
>>>>> twice for the same chip, once for each client pm8008-infra
>>>>> and pm8008-regulator.
>>>>>
>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>> pass the regmap to the regulator driver.
>>>>>
>>>>> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
>>>>> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
>>>>> ---
>>>>> Changes in V15:
>>>>>    - None.
>>>>>
>>>>> Changes in V14:
>>>>>    - None.
>>>>>
>>>>> Changes in V13:
>>>>>    - None.
>>>>>
>>>>>    drivers/mfd/qcom-pm8008.c       | 34 
>>>>> ++++++++++++++++++++++++++++++++--
>>>>>    include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>    2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>    create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>
>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>> index 569ffd50..55e2a8e 100644
>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>> @@ -9,6 +9,7 @@
>>>>>    #include <linux/interrupt.h>
>>>>>    #include <linux/irq.h>
>>>>>    #include <linux/irqdomain.h>
>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>    #include <linux/module.h>
>>>>>    #include <linux/of_device.h>
>>>>>    #include <linux/of_platform.h>
>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>    struct pm8008_data {
>>>>>        struct device *dev;
>>>>> +    struct regmap *regulators_regmap;
>>>>>        int irq;
>>>>>        struct regmap_irq_chip_data *irq_data;
>>>>>    };
>>>>> @@ -150,6 +152,12 @@ static struct regmap_config 
>>>>> qcom_mfd_regmap_cfg = {
>>>>>        .max_register    = 0xFFFF,
>>>>>    };
>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>> +{
>>>>> +    return chip->regulators_regmap;
>>>>> +}
>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>> Seems like abstraction for the sake of abstraction.
>>>>
>>>> Why not do the dereference inside the regulator driver?
>>> To derefer this in the regulator driver, we need to have the 
>>> pm8008_data
>>> struct definition in the qcom_pm8008 header file.
>>>
>>> I think it doesn't look great to have only that structure in header 
>>> and all
>>> other structs and enum in the mfd driver.
>> Then why pass 'pm8008_data' at all?
>
>
> There is one more option, instead of passing the pm8008_data, we could 
> pass the pdev->dev.parent and get the pm8008 chip data directly in the 
> pm8008_get_regmap() like below
>
>
> struct regmap *pm8008_get_regmap(const struct device *dev)
>  {
>      const struct pm8008_data *chip = dev_get_drvdata(dev);
>
>      return chip->regulators_regmap;
> }
> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>
>
> By doing this we can avoid having declaration of pm8008_data also in 
> the header. Please let me know if this looks good.
>

Could you please confirm on this?


>> What's preventing you from passing 'regmap'?
>
>
> I didn't get what you meant here, could you please elaborate a bit?
>
>
Lee Jones June 27, 2022, 7:41 a.m. UTC | #6
On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:

> Hi Lee,
> 
> 
> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > On 6/20/2022 1:50 PM, Lee Jones wrote:
> > > On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > 
> > > > On 6/17/2022 2:27 AM, Lee Jones wrote:
> > > > > On Tue, 14 Jun 2022, Satya Priya wrote:
> > > > > 
> > > > > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > > > > client present at a different address space, instead of
> > > > > > defining a separate DT node. This avoids calling the probe
> > > > > > twice for the same chip, once for each client pm8008-infra
> > > > > > and pm8008-regulator.
> > > > > > 
> > > > > > As a part of this define pm8008_regmap_init() to do regmap
> > > > > > init for both the clients and define pm8008_get_regmap() to
> > > > > > pass the regmap to the regulator driver.
> > > > > > 
> > > > > > Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
> > > > > > Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> > > > > > ---
> > > > > > Changes in V15:
> > > > > >    - None.
> > > > > > 
> > > > > > Changes in V14:
> > > > > >    - None.
> > > > > > 
> > > > > > Changes in V13:
> > > > > >    - None.
> > > > > > 
> > > > > >    drivers/mfd/qcom-pm8008.c       | 34
> > > > > > ++++++++++++++++++++++++++++++++--
> > > > > >    include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > > > > >    2 files changed, 41 insertions(+), 2 deletions(-)
> > > > > >    create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > > > > 
> > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > index 569ffd50..55e2a8e 100644
> > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > @@ -9,6 +9,7 @@
> > > > > >    #include <linux/interrupt.h>
> > > > > >    #include <linux/irq.h>
> > > > > >    #include <linux/irqdomain.h>
> > > > > > +#include <linux/mfd/qcom_pm8008.h>
> > > > > >    #include <linux/module.h>
> > > > > >    #include <linux/of_device.h>
> > > > > >    #include <linux/of_platform.h>
> > > > > > @@ -57,6 +58,7 @@ enum {
> > > > > >    struct pm8008_data {
> > > > > >        struct device *dev;
> > > > > > +    struct regmap *regulators_regmap;
> > > > > >        int irq;
> > > > > >        struct regmap_irq_chip_data *irq_data;
> > > > > >    };
> > > > > > @@ -150,6 +152,12 @@ static struct regmap_config
> > > > > > qcom_mfd_regmap_cfg = {
> > > > > >        .max_register    = 0xFFFF,
> > > > > >    };
> > > > > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > > > > +{
> > > > > > +    return chip->regulators_regmap;
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > Seems like abstraction for the sake of abstraction.
> > > > > 
> > > > > Why not do the dereference inside the regulator driver?
> > > > To derefer this in the regulator driver, we need to have the
> > > > pm8008_data
> > > > struct definition in the qcom_pm8008 header file.
> > > > 
> > > > I think it doesn't look great to have only that structure in
> > > > header and all
> > > > other structs and enum in the mfd driver.
> > > Then why pass 'pm8008_data' at all?
> > 
> > 
> > There is one more option, instead of passing the pm8008_data, we could
> > pass the pdev->dev.parent and get the pm8008 chip data directly in the
> > pm8008_get_regmap() like below
> > 
> > 
> > struct regmap *pm8008_get_regmap(const struct device *dev)
> >  {
> >      const struct pm8008_data *chip = dev_get_drvdata(dev);
> > 
> >      return chip->regulators_regmap;
> > }
> > EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > 
> > 
> > By doing this we can avoid having declaration of pm8008_data also in the
> > header. Please let me know if this looks good.
> > 
> 
> Could you please confirm on this?
> 
> > > What's preventing you from passing 'regmap'?
> > 
> > 
> > I didn't get what you meant here, could you please elaborate a bit?

Ah yes.  I authored you a patch, but became distracted. Here:

-----8<--------------------8<-------

From: Lee Jones <lee.jones@linaro.org>

mfd: pm8008: Remove driver data structure pm8008_data
    
Maintaining a local driver data structure that is never shared
outside of the core device is an unnecessary complexity.  Half of the
attributes were not used outside of a single function, one of which
was not used at all.  The remaining 2 are generic and can be passed
around as required.
    
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
 1 file changed, 20 insertions(+), 33 deletions(-)

diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
index c472d7f8103c4..4b8ff947762f2 100644
--- a/drivers/mfd/qcom-pm8008.c
+++ b/drivers/mfd/qcom-pm8008.c
@@ -54,13 +54,6 @@ enum {
 
 #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
 
-struct pm8008_data {
-	struct device *dev;
-	struct regmap *regmap;
-	int irq;
-	struct regmap_irq_chip_data *irq_data;
-};
-
 static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
 static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
 static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
@@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
 	.max_register	= 0xFFFF,
 };
 
-static int pm8008_init(struct pm8008_data *chip)
+static int pm8008_init(struct regmap *regmap)
 {
 	int rc;
 
@@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
 	 * This is required to enable the writing of TYPE registers in
 	 * regmap_irq_sync_unlock().
 	 */
-	rc = regmap_write(chip->regmap,
-			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
-			 BIT(0));
+	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
 	if (rc)
 		return rc;
 
 	/* Do the same for GPIO1 and GPIO2 peripherals */
-	rc = regmap_write(chip->regmap,
-			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
+	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
 	if (rc)
 		return rc;
 
-	rc = regmap_write(chip->regmap,
-			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
+	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
 
 	return rc;
 }
 
-static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
+static int pm8008_probe_irq_peripherals(struct device *dev,
+					struct regmap *regmap,
 					int client_irq)
 {
 	int rc, i;
 	struct regmap_irq_type *type;
 	struct regmap_irq_chip_data *irq_data;
 
-	rc = pm8008_init(chip);
+	rc = pm8008_init(regmap);
 	if (rc) {
-		dev_err(chip->dev, "Init failed: %d\n", rc);
+		dev_err(dev, "Init failed: %d\n", rc);
 		return rc;
 	}
 
@@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
 				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
 	}
 
-	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
+	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
 			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
 	if (rc) {
-		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
+		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
 		return rc;
 	}
 
@@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
 static int pm8008_probe(struct i2c_client *client)
 {
 	int rc;
-	struct pm8008_data *chip;
-
-	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
-	if (!chip)
-		return -ENOMEM;
+	struct device *dev;
+	struct regmap *regmap;
 
-	chip->dev = &client->dev;
-	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
-	if (!chip->regmap)
+	dev = &client->dev;
+	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
+	if (!regmap)
 		return -ENODEV;
 
-	i2c_set_clientdata(client, chip);
+	i2c_set_clientdata(client, regmap);
 
-	if (of_property_read_bool(chip->dev->of_node, "interrupt-controller")) {
-		rc = pm8008_probe_irq_peripherals(chip, client->irq);
+	if (of_property_read_bool(dev->of_node, "interrupt-controller")) {
+		rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq);
 		if (rc)
-			dev_err(chip->dev, "Failed to probe irq periphs: %d\n", rc);
+			dev_err(dev, "Failed to probe irq periphs: %d\n", rc);
 	}
 
-	return devm_of_platform_populate(chip->dev);
+	return devm_of_platform_populate(dev);
 }
 
 static const struct of_device_id pm8008_match[] = {
Satya Priya Kakitapalli (Temp) June 28, 2022, 4:53 a.m. UTC | #7
On 6/27/2022 1:11 PM, Lee Jones wrote:
> On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> Hi Lee,
>>
>>
>> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>>> On 6/20/2022 1:50 PM, Lee Jones wrote:
>>>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>
>>>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>>>
>>>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>>>> client present at a different address space, instead of
>>>>>>> defining a separate DT node. This avoids calling the probe
>>>>>>> twice for the same chip, once for each client pm8008-infra
>>>>>>> and pm8008-regulator.
>>>>>>>
>>>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>>>> pass the regmap to the regulator driver.
>>>>>>>
>>>>>>> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
>>>>>>> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
>>>>>>> ---
>>>>>>> Changes in V15:
>>>>>>>     - None.
>>>>>>>
>>>>>>> Changes in V14:
>>>>>>>     - None.
>>>>>>>
>>>>>>> Changes in V13:
>>>>>>>     - None.
>>>>>>>
>>>>>>>     drivers/mfd/qcom-pm8008.c       | 34
>>>>>>> ++++++++++++++++++++++++++++++++--
>>>>>>>     include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>>>     2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>>>     create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>>>
>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>> index 569ffd50..55e2a8e 100644
>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>> @@ -9,6 +9,7 @@
>>>>>>>     #include <linux/interrupt.h>
>>>>>>>     #include <linux/irq.h>
>>>>>>>     #include <linux/irqdomain.h>
>>>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>>>     #include <linux/module.h>
>>>>>>>     #include <linux/of_device.h>
>>>>>>>     #include <linux/of_platform.h>
>>>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>>>     struct pm8008_data {
>>>>>>>         struct device *dev;
>>>>>>> +    struct regmap *regulators_regmap;
>>>>>>>         int irq;
>>>>>>>         struct regmap_irq_chip_data *irq_data;
>>>>>>>     };
>>>>>>> @@ -150,6 +152,12 @@ static struct regmap_config
>>>>>>> qcom_mfd_regmap_cfg = {
>>>>>>>         .max_register    = 0xFFFF,
>>>>>>>     };
>>>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>>>> +{
>>>>>>> +    return chip->regulators_regmap;
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>> Seems like abstraction for the sake of abstraction.
>>>>>>
>>>>>> Why not do the dereference inside the regulator driver?
>>>>> To derefer this in the regulator driver, we need to have the
>>>>> pm8008_data
>>>>> struct definition in the qcom_pm8008 header file.
>>>>>
>>>>> I think it doesn't look great to have only that structure in
>>>>> header and all
>>>>> other structs and enum in the mfd driver.
>>>> Then why pass 'pm8008_data' at all?
>>>
>>> There is one more option, instead of passing the pm8008_data, we could
>>> pass the pdev->dev.parent and get the pm8008 chip data directly in the
>>> pm8008_get_regmap() like below
>>>
>>>
>>> struct regmap *pm8008_get_regmap(const struct device *dev)
>>>   {
>>>       const struct pm8008_data *chip = dev_get_drvdata(dev);
>>>
>>>       return chip->regulators_regmap;
>>> }
>>> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>
>>>
>>> By doing this we can avoid having declaration of pm8008_data also in the
>>> header. Please let me know if this looks good.
>>>
>> Could you please confirm on this?
>>
>>>> What's preventing you from passing 'regmap'?
>>>
>>> I didn't get what you meant here, could you please elaborate a bit?
> Ah yes.  I authored you a patch, but became distracted. Here:
>
> -----8<--------------------8<-------
>
> From: Lee Jones <lee.jones@linaro.org>
>
> mfd: pm8008: Remove driver data structure pm8008_data
>      
> Maintaining a local driver data structure that is never shared
> outside of the core device is an unnecessary complexity.  Half of the
> attributes were not used outside of a single function, one of which
> was not used at all.  The remaining 2 are generic and can be passed
> around as required.


Okay, but we still need to store the regulators_regmap, which is 
required in the pm8008 regulator driver. Could we use a global variable 
for it?


> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
>   drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
>   1 file changed, 20 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> index c472d7f8103c4..4b8ff947762f2 100644
> --- a/drivers/mfd/qcom-pm8008.c
> +++ b/drivers/mfd/qcom-pm8008.c
> @@ -54,13 +54,6 @@ enum {
>   
>   #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
>   
> -struct pm8008_data {
> -	struct device *dev;
> -	struct regmap *regmap;
> -	int irq;
> -	struct regmap_irq_chip_data *irq_data;
> -};
> -
>   static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
>   static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
>   static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
> @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>   	.max_register	= 0xFFFF,
>   };
>   
> -static int pm8008_init(struct pm8008_data *chip)
> +static int pm8008_init(struct regmap *regmap)
>   {
>   	int rc;
>   
> @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
>   	 * This is required to enable the writing of TYPE registers in
>   	 * regmap_irq_sync_unlock().
>   	 */
> -	rc = regmap_write(chip->regmap,
> -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
> -			 BIT(0));
> +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>   	if (rc)
>   		return rc;
>   
>   	/* Do the same for GPIO1 and GPIO2 peripherals */
> -	rc = regmap_write(chip->regmap,
> -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>   	if (rc)
>   		return rc;
>   
> -	rc = regmap_write(chip->regmap,
> -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>   
>   	return rc;
>   }
>   
> -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> +static int pm8008_probe_irq_peripherals(struct device *dev,
> +					struct regmap *regmap,
>   					int client_irq)
>   {
>   	int rc, i;
>   	struct regmap_irq_type *type;
>   	struct regmap_irq_chip_data *irq_data;
>   
> -	rc = pm8008_init(chip);
> +	rc = pm8008_init(regmap);
>   	if (rc) {
> -		dev_err(chip->dev, "Init failed: %d\n", rc);
> +		dev_err(dev, "Init failed: %d\n", rc);
>   		return rc;
>   	}
>   
> @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>   				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
>   	}
>   
> -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
> +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
>   			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
>   	if (rc) {
> -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
> +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
>   		return rc;
>   	}
>   
> @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>   static int pm8008_probe(struct i2c_client *client)
>   {
>   	int rc;
> -	struct pm8008_data *chip;
> -
> -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> -	if (!chip)
> -		return -ENOMEM;
> +	struct device *dev;
> +	struct regmap *regmap;
>   
> -	chip->dev = &client->dev;
> -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> -	if (!chip->regmap)
> +	dev = &client->dev;
> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> +	if (!regmap)
>   		return -ENODEV;
>   
> -	i2c_set_clientdata(client, chip);
> +	i2c_set_clientdata(client, regmap);
>   
> -	if (of_property_read_bool(chip->dev->of_node, "interrupt-controller")) {
> -		rc = pm8008_probe_irq_peripherals(chip, client->irq);
> +	if (of_property_read_bool(dev->of_node, "interrupt-controller")) {
> +		rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq);
>   		if (rc)
> -			dev_err(chip->dev, "Failed to probe irq periphs: %d\n", rc);
> +			dev_err(dev, "Failed to probe irq periphs: %d\n", rc);
>   	}
>   
> -	return devm_of_platform_populate(chip->dev);
> +	return devm_of_platform_populate(dev);
>   }
>   
>   static const struct of_device_id pm8008_match[] = {
>
Lee Jones June 28, 2022, 7:42 a.m. UTC | #8
On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 6/27/2022 1:11 PM, Lee Jones wrote:
> > On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > > Hi Lee,
> > > 
> > > 
> > > On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
> > > > On 6/20/2022 1:50 PM, Lee Jones wrote:
> > > > > On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > 
> > > > > > On 6/17/2022 2:27 AM, Lee Jones wrote:
> > > > > > > On Tue, 14 Jun 2022, Satya Priya wrote:
> > > > > > > 
> > > > > > > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > > > > > > client present at a different address space, instead of
> > > > > > > > defining a separate DT node. This avoids calling the probe
> > > > > > > > twice for the same chip, once for each client pm8008-infra
> > > > > > > > and pm8008-regulator.
> > > > > > > > 
> > > > > > > > As a part of this define pm8008_regmap_init() to do regmap
> > > > > > > > init for both the clients and define pm8008_get_regmap() to
> > > > > > > > pass the regmap to the regulator driver.
> > > > > > > > 
> > > > > > > > Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
> > > > > > > > Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> > > > > > > > ---
> > > > > > > > Changes in V15:
> > > > > > > >     - None.
> > > > > > > > 
> > > > > > > > Changes in V14:
> > > > > > > >     - None.
> > > > > > > > 
> > > > > > > > Changes in V13:
> > > > > > > >     - None.
> > > > > > > > 
> > > > > > > >     drivers/mfd/qcom-pm8008.c       | 34
> > > > > > > > ++++++++++++++++++++++++++++++++--
> > > > > > > >     include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > > > > > > >     2 files changed, 41 insertions(+), 2 deletions(-)
> > > > > > > >     create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > > > > > > 
> > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > index 569ffd50..55e2a8e 100644
> > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > @@ -9,6 +9,7 @@
> > > > > > > >     #include <linux/interrupt.h>
> > > > > > > >     #include <linux/irq.h>
> > > > > > > >     #include <linux/irqdomain.h>
> > > > > > > > +#include <linux/mfd/qcom_pm8008.h>
> > > > > > > >     #include <linux/module.h>
> > > > > > > >     #include <linux/of_device.h>
> > > > > > > >     #include <linux/of_platform.h>
> > > > > > > > @@ -57,6 +58,7 @@ enum {
> > > > > > > >     struct pm8008_data {
> > > > > > > >         struct device *dev;
> > > > > > > > +    struct regmap *regulators_regmap;
> > > > > > > >         int irq;
> > > > > > > >         struct regmap_irq_chip_data *irq_data;
> > > > > > > >     };
> > > > > > > > @@ -150,6 +152,12 @@ static struct regmap_config
> > > > > > > > qcom_mfd_regmap_cfg = {
> > > > > > > >         .max_register    = 0xFFFF,
> > > > > > > >     };
> > > > > > > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > > > > > > +{
> > > > > > > > +    return chip->regulators_regmap;
> > > > > > > > +}
> > > > > > > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > Seems like abstraction for the sake of abstraction.
> > > > > > > 
> > > > > > > Why not do the dereference inside the regulator driver?
> > > > > > To derefer this in the regulator driver, we need to have the
> > > > > > pm8008_data
> > > > > > struct definition in the qcom_pm8008 header file.
> > > > > > 
> > > > > > I think it doesn't look great to have only that structure in
> > > > > > header and all
> > > > > > other structs and enum in the mfd driver.
> > > > > Then why pass 'pm8008_data' at all?
> > > > 
> > > > There is one more option, instead of passing the pm8008_data, we could
> > > > pass the pdev->dev.parent and get the pm8008 chip data directly in the
> > > > pm8008_get_regmap() like below
> > > > 
> > > > 
> > > > struct regmap *pm8008_get_regmap(const struct device *dev)
> > > >   {
> > > >       const struct pm8008_data *chip = dev_get_drvdata(dev);
> > > > 
> > > >       return chip->regulators_regmap;
> > > > }
> > > > EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > 
> > > > 
> > > > By doing this we can avoid having declaration of pm8008_data also in the
> > > > header. Please let me know if this looks good.
> > > > 
> > > Could you please confirm on this?
> > > 
> > > > > What's preventing you from passing 'regmap'?
> > > > 
> > > > I didn't get what you meant here, could you please elaborate a bit?
> > Ah yes.  I authored you a patch, but became distracted. Here:
> > 
> > -----8<--------------------8<-------
> > 
> > From: Lee Jones <lee.jones@linaro.org>
> > 
> > mfd: pm8008: Remove driver data structure pm8008_data
> > Maintaining a local driver data structure that is never shared
> > outside of the core device is an unnecessary complexity.  Half of the
> > attributes were not used outside of a single function, one of which
> > was not used at all.  The remaining 2 are generic and can be passed
> > around as required.
> 
> 
> Okay, but we still need to store the regulators_regmap, which is required in
> the pm8008 regulator driver. Could we use a global variable for it?

Look down ...

> > Signed-off-by: Lee Jones <lee.jones@linaro.org>
> > ---
> >   drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
> >   1 file changed, 20 insertions(+), 33 deletions(-)
> > 
> > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > index c472d7f8103c4..4b8ff947762f2 100644
> > --- a/drivers/mfd/qcom-pm8008.c
> > +++ b/drivers/mfd/qcom-pm8008.c
> > @@ -54,13 +54,6 @@ enum {
> >   #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
> > -struct pm8008_data {
> > -	struct device *dev;
> > -	struct regmap *regmap;
> > -	int irq;
> > -	struct regmap_irq_chip_data *irq_data;
> > -};
> > -
> >   static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
> >   static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
> >   static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
> > @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
> >   	.max_register	= 0xFFFF,
> >   };
> > -static int pm8008_init(struct pm8008_data *chip)
> > +static int pm8008_init(struct regmap *regmap)
> >   {
> >   	int rc;
> > @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
> >   	 * This is required to enable the writing of TYPE registers in
> >   	 * regmap_irq_sync_unlock().
> >   	 */
> > -	rc = regmap_write(chip->regmap,
> > -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
> > -			 BIT(0));
> > +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> >   	if (rc)
> >   		return rc;
> >   	/* Do the same for GPIO1 and GPIO2 peripherals */
> > -	rc = regmap_write(chip->regmap,
> > -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> >   	if (rc)
> >   		return rc;
> > -	rc = regmap_write(chip->regmap,
> > -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> >   	return rc;
> >   }
> > -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > +static int pm8008_probe_irq_peripherals(struct device *dev,
> > +					struct regmap *regmap,
> >   					int client_irq)
> >   {
> >   	int rc, i;
> >   	struct regmap_irq_type *type;
> >   	struct regmap_irq_chip_data *irq_data;
> > -	rc = pm8008_init(chip);
> > +	rc = pm8008_init(regmap);
> >   	if (rc) {
> > -		dev_err(chip->dev, "Init failed: %d\n", rc);
> > +		dev_err(dev, "Init failed: %d\n", rc);
> >   		return rc;
> >   	}
> > @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> >   				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
> >   	}
> > -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
> > +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
> >   			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
> >   	if (rc) {
> > -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
> > +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
> >   		return rc;
> >   	}
> > @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> >   static int pm8008_probe(struct i2c_client *client)
> >   {
> >   	int rc;
> > -	struct pm8008_data *chip;
> > -
> > -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > -	if (!chip)
> > -		return -ENOMEM;
> > +	struct device *dev;
> > +	struct regmap *regmap;
> > -	chip->dev = &client->dev;
> > -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > -	if (!chip->regmap)
> > +	dev = &client->dev;
> > +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > +	if (!regmap)
> >   		return -ENODEV;
> > -	i2c_set_clientdata(client, chip);
> > +	i2c_set_clientdata(client, regmap);

Here ^

> > -	if (of_property_read_bool(chip->dev->of_node, "interrupt-controller")) {
> > -		rc = pm8008_probe_irq_peripherals(chip, client->irq);
> > +	if (of_property_read_bool(dev->of_node, "interrupt-controller")) {
> > +		rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq);
> >   		if (rc)
> > -			dev_err(chip->dev, "Failed to probe irq periphs: %d\n", rc);
> > +			dev_err(dev, "Failed to probe irq periphs: %d\n", rc);
> >   	}
> > -	return devm_of_platform_populate(chip->dev);
> > +	return devm_of_platform_populate(dev);
> >   }
> >   static const struct of_device_id pm8008_match[] = {
> >
Satya Priya Kakitapalli (Temp) June 29, 2022, 10:36 a.m. UTC | #9
On 6/28/2022 1:12 PM, Lee Jones wrote:
> On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> On 6/27/2022 1:11 PM, Lee Jones wrote:
>>> On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>
>>>> Hi Lee,
>>>>
>>>>
>>>> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>>>>> On 6/20/2022 1:50 PM, Lee Jones wrote:
>>>>>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>
>>>>>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>>>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>>>>>
>>>>>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>>>>>> client present at a different address space, instead of
>>>>>>>>> defining a separate DT node. This avoids calling the probe
>>>>>>>>> twice for the same chip, once for each client pm8008-infra
>>>>>>>>> and pm8008-regulator.
>>>>>>>>>
>>>>>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>>>>>> pass the regmap to the regulator driver.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
>>>>>>>>> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
>>>>>>>>> ---
>>>>>>>>> Changes in V15:
>>>>>>>>>      - None.
>>>>>>>>>
>>>>>>>>> Changes in V14:
>>>>>>>>>      - None.
>>>>>>>>>
>>>>>>>>> Changes in V13:
>>>>>>>>>      - None.
>>>>>>>>>
>>>>>>>>>      drivers/mfd/qcom-pm8008.c       | 34
>>>>>>>>> ++++++++++++++++++++++++++++++++--
>>>>>>>>>      include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>>>>>      2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>>>>>      create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>> index 569ffd50..55e2a8e 100644
>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>> @@ -9,6 +9,7 @@
>>>>>>>>>      #include <linux/interrupt.h>
>>>>>>>>>      #include <linux/irq.h>
>>>>>>>>>      #include <linux/irqdomain.h>
>>>>>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>>>>>      #include <linux/module.h>
>>>>>>>>>      #include <linux/of_device.h>
>>>>>>>>>      #include <linux/of_platform.h>
>>>>>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>>>>>      struct pm8008_data {
>>>>>>>>>          struct device *dev;
>>>>>>>>> +    struct regmap *regulators_regmap;
>>>>>>>>>          int irq;
>>>>>>>>>          struct regmap_irq_chip_data *irq_data;
>>>>>>>>>      };
>>>>>>>>> @@ -150,6 +152,12 @@ static struct regmap_config
>>>>>>>>> qcom_mfd_regmap_cfg = {
>>>>>>>>>          .max_register    = 0xFFFF,
>>>>>>>>>      };
>>>>>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>>>>>> +{
>>>>>>>>> +    return chip->regulators_regmap;
>>>>>>>>> +}
>>>>>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>> Seems like abstraction for the sake of abstraction.
>>>>>>>>
>>>>>>>> Why not do the dereference inside the regulator driver?
>>>>>>> To derefer this in the regulator driver, we need to have the
>>>>>>> pm8008_data
>>>>>>> struct definition in the qcom_pm8008 header file.
>>>>>>>
>>>>>>> I think it doesn't look great to have only that structure in
>>>>>>> header and all
>>>>>>> other structs and enum in the mfd driver.
>>>>>> Then why pass 'pm8008_data' at all?
>>>>> There is one more option, instead of passing the pm8008_data, we could
>>>>> pass the pdev->dev.parent and get the pm8008 chip data directly in the
>>>>> pm8008_get_regmap() like below
>>>>>
>>>>>
>>>>> struct regmap *pm8008_get_regmap(const struct device *dev)
>>>>>    {
>>>>>        const struct pm8008_data *chip = dev_get_drvdata(dev);
>>>>>
>>>>>        return chip->regulators_regmap;
>>>>> }
>>>>> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>
>>>>>
>>>>> By doing this we can avoid having declaration of pm8008_data also in the
>>>>> header. Please let me know if this looks good.
>>>>>
>>>> Could you please confirm on this?
>>>>
>>>>>> What's preventing you from passing 'regmap'?
>>>>> I didn't get what you meant here, could you please elaborate a bit?
>>> Ah yes.  I authored you a patch, but became distracted. Here:
>>>
>>> -----8<--------------------8<-------
>>>
>>> From: Lee Jones <lee.jones@linaro.org>
>>>
>>> mfd: pm8008: Remove driver data structure pm8008_data
>>> Maintaining a local driver data structure that is never shared
>>> outside of the core device is an unnecessary complexity.  Half of the
>>> attributes were not used outside of a single function, one of which
>>> was not used at all.  The remaining 2 are generic and can be passed
>>> around as required.
>>
>> Okay, but we still need to store the regulators_regmap, which is required in
>> the pm8008 regulator driver. Could we use a global variable for it?
> Look down ...
>
>>> Signed-off-by: Lee Jones <lee.jones@linaro.org>
>>> ---
>>>    drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
>>>    1 file changed, 20 insertions(+), 33 deletions(-)
>>>
>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>> index c472d7f8103c4..4b8ff947762f2 100644
>>> --- a/drivers/mfd/qcom-pm8008.c
>>> +++ b/drivers/mfd/qcom-pm8008.c
>>> @@ -54,13 +54,6 @@ enum {
>>>    #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
>>> -struct pm8008_data {
>>> -	struct device *dev;
>>> -	struct regmap *regmap;
>>> -	int irq;
>>> -	struct regmap_irq_chip_data *irq_data;
>>> -};
>>> -
>>>    static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
>>>    static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
>>>    static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
>>> @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>>    	.max_register	= 0xFFFF,
>>>    };
>>> -static int pm8008_init(struct pm8008_data *chip)
>>> +static int pm8008_init(struct regmap *regmap)
>>>    {
>>>    	int rc;
>>> @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
>>>    	 * This is required to enable the writing of TYPE registers in
>>>    	 * regmap_irq_sync_unlock().
>>>    	 */
>>> -	rc = regmap_write(chip->regmap,
>>> -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
>>> -			 BIT(0));
>>> +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>    	if (rc)
>>>    		return rc;
>>>    	/* Do the same for GPIO1 and GPIO2 peripherals */
>>> -	rc = regmap_write(chip->regmap,
>>> -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>> +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>    	if (rc)
>>>    		return rc;
>>> -	rc = regmap_write(chip->regmap,
>>> -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>> +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>    	return rc;
>>>    }
>>> -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>> +static int pm8008_probe_irq_peripherals(struct device *dev,
>>> +					struct regmap *regmap,
>>>    					int client_irq)
>>>    {
>>>    	int rc, i;
>>>    	struct regmap_irq_type *type;
>>>    	struct regmap_irq_chip_data *irq_data;
>>> -	rc = pm8008_init(chip);
>>> +	rc = pm8008_init(regmap);
>>>    	if (rc) {
>>> -		dev_err(chip->dev, "Init failed: %d\n", rc);
>>> +		dev_err(dev, "Init failed: %d\n", rc);
>>>    		return rc;
>>>    	}
>>> @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>    				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
>>>    	}
>>> -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
>>> +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
>>>    			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
>>>    	if (rc) {
>>> -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
>>> +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
>>>    		return rc;
>>>    	}
>>> @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>    static int pm8008_probe(struct i2c_client *client)
>>>    {
>>>    	int rc;
>>> -	struct pm8008_data *chip;
>>> -
>>> -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
>>> -	if (!chip)
>>> -		return -ENOMEM;
>>> +	struct device *dev;
>>> +	struct regmap *regmap;
>>> -	chip->dev = &client->dev;
>>> -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>> -	if (!chip->regmap)
>>> +	dev = &client->dev;
>>> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>> +	if (!regmap)
>>>    		return -ENODEV;
>>> -	i2c_set_clientdata(client, chip);
>>> +	i2c_set_clientdata(client, regmap);
> Here ^


I have added a dummy device and set the client data by passing regmap, 
see below:

+       regulators_client = i2c_new_dummy_device(client->adapter, 
client->addr + 1);
+       if (IS_ERR(regulators_client)) {
+               dev_err(dev, "can't attach client\n");
+               return PTR_ERR(regulators_client);
+       }
+
+       regulators_regmap = devm_regmap_init_i2c(regulators_client, 
&qcom_mfd_regmap_cfg[1]);
+       if (!regmap)
+               return -ENODEV;
+
+       i2c_set_clientdata(client, regulators_regmap);

Now if i try to get this regmap from regulator driver by doing

struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);

it still gets me the regmap of pm8008@8 device and not the regulator 
device regmap (0x9). Not sure if I'm missing something here.


>>> -	if (of_property_read_bool(chip->dev->of_node, "interrupt-controller")) {
>>> -		rc = pm8008_probe_irq_peripherals(chip, client->irq);
>>> +	if (of_property_read_bool(dev->of_node, "interrupt-controller")) {
>>> +		rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq);
>>>    		if (rc)
>>> -			dev_err(chip->dev, "Failed to probe irq periphs: %d\n", rc);
>>> +			dev_err(dev, "Failed to probe irq periphs: %d\n", rc);
>>>    	}
>>> -	return devm_of_platform_populate(chip->dev);
>>> +	return devm_of_platform_populate(dev);
>>>    }
>>>    static const struct of_device_id pm8008_match[] = {
>>>
Lee Jones June 29, 2022, 3:18 p.m. UTC | #10
On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 6/28/2022 1:12 PM, Lee Jones wrote:
> > On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > > On 6/27/2022 1:11 PM, Lee Jones wrote:
> > > > On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > 
> > > > > Hi Lee,
> > > > > 
> > > > > 
> > > > > On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > On 6/20/2022 1:50 PM, Lee Jones wrote:
> > > > > > > On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > 
> > > > > > > > On 6/17/2022 2:27 AM, Lee Jones wrote:
> > > > > > > > > On Tue, 14 Jun 2022, Satya Priya wrote:
> > > > > > > > > 
> > > > > > > > > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > > > > > > > > client present at a different address space, instead of
> > > > > > > > > > defining a separate DT node. This avoids calling the probe
> > > > > > > > > > twice for the same chip, once for each client pm8008-infra
> > > > > > > > > > and pm8008-regulator.
> > > > > > > > > > 
> > > > > > > > > > As a part of this define pm8008_regmap_init() to do regmap
> > > > > > > > > > init for both the clients and define pm8008_get_regmap() to
> > > > > > > > > > pass the regmap to the regulator driver.
> > > > > > > > > > 
> > > > > > > > > > Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
> > > > > > > > > > Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> > > > > > > > > > ---
> > > > > > > > > > Changes in V15:
> > > > > > > > > >      - None.
> > > > > > > > > > 
> > > > > > > > > > Changes in V14:
> > > > > > > > > >      - None.
> > > > > > > > > > 
> > > > > > > > > > Changes in V13:
> > > > > > > > > >      - None.
> > > > > > > > > > 
> > > > > > > > > >      drivers/mfd/qcom-pm8008.c       | 34
> > > > > > > > > > ++++++++++++++++++++++++++++++++--
> > > > > > > > > >      include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > > > > > > > > >      2 files changed, 41 insertions(+), 2 deletions(-)
> > > > > > > > > >      create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > > > > > > > > 
> > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > index 569ffd50..55e2a8e 100644
> > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > @@ -9,6 +9,7 @@
> > > > > > > > > >      #include <linux/interrupt.h>
> > > > > > > > > >      #include <linux/irq.h>
> > > > > > > > > >      #include <linux/irqdomain.h>
> > > > > > > > > > +#include <linux/mfd/qcom_pm8008.h>
> > > > > > > > > >      #include <linux/module.h>
> > > > > > > > > >      #include <linux/of_device.h>
> > > > > > > > > >      #include <linux/of_platform.h>
> > > > > > > > > > @@ -57,6 +58,7 @@ enum {
> > > > > > > > > >      struct pm8008_data {
> > > > > > > > > >          struct device *dev;
> > > > > > > > > > +    struct regmap *regulators_regmap;
> > > > > > > > > >          int irq;
> > > > > > > > > >          struct regmap_irq_chip_data *irq_data;
> > > > > > > > > >      };
> > > > > > > > > > @@ -150,6 +152,12 @@ static struct regmap_config
> > > > > > > > > > qcom_mfd_regmap_cfg = {
> > > > > > > > > >          .max_register    = 0xFFFF,
> > > > > > > > > >      };
> > > > > > > > > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > > > > > > > > +{
> > > > > > > > > > +    return chip->regulators_regmap;
> > > > > > > > > > +}
> > > > > > > > > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > Seems like abstraction for the sake of abstraction.
> > > > > > > > > 
> > > > > > > > > Why not do the dereference inside the regulator driver?
> > > > > > > > To derefer this in the regulator driver, we need to have the
> > > > > > > > pm8008_data
> > > > > > > > struct definition in the qcom_pm8008 header file.
> > > > > > > > 
> > > > > > > > I think it doesn't look great to have only that structure in
> > > > > > > > header and all
> > > > > > > > other structs and enum in the mfd driver.
> > > > > > > Then why pass 'pm8008_data' at all?
> > > > > > There is one more option, instead of passing the pm8008_data, we could
> > > > > > pass the pdev->dev.parent and get the pm8008 chip data directly in the
> > > > > > pm8008_get_regmap() like below
> > > > > > 
> > > > > > 
> > > > > > struct regmap *pm8008_get_regmap(const struct device *dev)
> > > > > >    {
> > > > > >        const struct pm8008_data *chip = dev_get_drvdata(dev);
> > > > > > 
> > > > > >        return chip->regulators_regmap;
> > > > > > }
> > > > > > EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > 
> > > > > > 
> > > > > > By doing this we can avoid having declaration of pm8008_data also in the
> > > > > > header. Please let me know if this looks good.
> > > > > > 
> > > > > Could you please confirm on this?
> > > > > 
> > > > > > > What's preventing you from passing 'regmap'?
> > > > > > I didn't get what you meant here, could you please elaborate a bit?
> > > > Ah yes.  I authored you a patch, but became distracted. Here:
> > > > 
> > > > -----8<--------------------8<-------
> > > > 
> > > > From: Lee Jones <lee.jones@linaro.org>
> > > > 
> > > > mfd: pm8008: Remove driver data structure pm8008_data
> > > > Maintaining a local driver data structure that is never shared
> > > > outside of the core device is an unnecessary complexity.  Half of the
> > > > attributes were not used outside of a single function, one of which
> > > > was not used at all.  The remaining 2 are generic and can be passed
> > > > around as required.
> > > 
> > > Okay, but we still need to store the regulators_regmap, which is required in
> > > the pm8008 regulator driver. Could we use a global variable for it?
> > Look down ...
> > 
> > > > Signed-off-by: Lee Jones <lee.jones@linaro.org>
> > > > ---
> > > >    drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
> > > >    1 file changed, 20 insertions(+), 33 deletions(-)
> > > > 
> > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > index c472d7f8103c4..4b8ff947762f2 100644
> > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > @@ -54,13 +54,6 @@ enum {
> > > >    #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
> > > > -struct pm8008_data {
> > > > -	struct device *dev;
> > > > -	struct regmap *regmap;
> > > > -	int irq;
> > > > -	struct regmap_irq_chip_data *irq_data;
> > > > -};
> > > > -
> > > >    static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
> > > >    static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
> > > >    static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
> > > > @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
> > > >    	.max_register	= 0xFFFF,
> > > >    };
> > > > -static int pm8008_init(struct pm8008_data *chip)
> > > > +static int pm8008_init(struct regmap *regmap)
> > > >    {
> > > >    	int rc;
> > > > @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
> > > >    	 * This is required to enable the writing of TYPE registers in
> > > >    	 * regmap_irq_sync_unlock().
> > > >    	 */
> > > > -	rc = regmap_write(chip->regmap,
> > > > -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
> > > > -			 BIT(0));
> > > > +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > >    	if (rc)
> > > >    		return rc;
> > > >    	/* Do the same for GPIO1 and GPIO2 peripherals */
> > > > -	rc = regmap_write(chip->regmap,
> > > > -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > >    	if (rc)
> > > >    		return rc;
> > > > -	rc = regmap_write(chip->regmap,
> > > > -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > >    	return rc;
> > > >    }
> > > > -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > +static int pm8008_probe_irq_peripherals(struct device *dev,
> > > > +					struct regmap *regmap,
> > > >    					int client_irq)
> > > >    {
> > > >    	int rc, i;
> > > >    	struct regmap_irq_type *type;
> > > >    	struct regmap_irq_chip_data *irq_data;
> > > > -	rc = pm8008_init(chip);
> > > > +	rc = pm8008_init(regmap);
> > > >    	if (rc) {
> > > > -		dev_err(chip->dev, "Init failed: %d\n", rc);
> > > > +		dev_err(dev, "Init failed: %d\n", rc);
> > > >    		return rc;
> > > >    	}
> > > > @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > >    				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
> > > >    	}
> > > > -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
> > > > +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
> > > >    			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
> > > >    	if (rc) {
> > > > -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
> > > > +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
> > > >    		return rc;
> > > >    	}
> > > > @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > >    static int pm8008_probe(struct i2c_client *client)
> > > >    {
> > > >    	int rc;
> > > > -	struct pm8008_data *chip;
> > > > -
> > > > -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > > > -	if (!chip)
> > > > -		return -ENOMEM;
> > > > +	struct device *dev;
> > > > +	struct regmap *regmap;
> > > > -	chip->dev = &client->dev;
> > > > -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > -	if (!chip->regmap)
> > > > +	dev = &client->dev;
> > > > +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > +	if (!regmap)
> > > >    		return -ENODEV;
> > > > -	i2c_set_clientdata(client, chip);
> > > > +	i2c_set_clientdata(client, regmap);
> > Here ^
> 
> 
> I have added a dummy device and set the client data by passing regmap, see
> below:
> 
> +       regulators_client = i2c_new_dummy_device(client->adapter,
> client->addr + 1);
> +       if (IS_ERR(regulators_client)) {
> +               dev_err(dev, "can't attach client\n");
> +               return PTR_ERR(regulators_client);
> +       }
> +
> +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
> &qcom_mfd_regmap_cfg[1]);
> +       if (!regmap)
> +               return -ENODEV;
> +
> +       i2c_set_clientdata(client, regulators_regmap);
> 
> Now if i try to get this regmap from regulator driver by doing
> 
> struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
> 
> it still gets me the regmap of pm8008@8 device and not the regulator device
> regmap (0x9). Not sure if I'm missing something here.

So you need to pass 2 regmap pointers?

If you need to pass more than one item to the child devices, you do
need to use a struct for that.
Satya Priya Kakitapalli (Temp) June 30, 2022, 9:37 a.m. UTC | #11
On 6/29/2022 8:48 PM, Lee Jones wrote:
> On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> On 6/28/2022 1:12 PM, Lee Jones wrote:
>>> On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>
>>>> On 6/27/2022 1:11 PM, Lee Jones wrote:
>>>>> On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>
>>>>>> Hi Lee,
>>>>>>
>>>>>>
>>>>>> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>> On 6/20/2022 1:50 PM, Lee Jones wrote:
>>>>>>>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>
>>>>>>>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>>>>>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>>>>>>>
>>>>>>>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>>>>>>>> client present at a different address space, instead of
>>>>>>>>>>> defining a separate DT node. This avoids calling the probe
>>>>>>>>>>> twice for the same chip, once for each client pm8008-infra
>>>>>>>>>>> and pm8008-regulator.
>>>>>>>>>>>
>>>>>>>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>>>>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>>>>>>>> pass the regmap to the regulator driver.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
>>>>>>>>>>> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
>>>>>>>>>>> ---
>>>>>>>>>>> Changes in V15:
>>>>>>>>>>>       - None.
>>>>>>>>>>>
>>>>>>>>>>> Changes in V14:
>>>>>>>>>>>       - None.
>>>>>>>>>>>
>>>>>>>>>>> Changes in V13:
>>>>>>>>>>>       - None.
>>>>>>>>>>>
>>>>>>>>>>>       drivers/mfd/qcom-pm8008.c       | 34
>>>>>>>>>>> ++++++++++++++++++++++++++++++++--
>>>>>>>>>>>       include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>>>>>>>       2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>>>>>>>       create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>>>>>>>
>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>> index 569ffd50..55e2a8e 100644
>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>> @@ -9,6 +9,7 @@
>>>>>>>>>>>       #include <linux/interrupt.h>
>>>>>>>>>>>       #include <linux/irq.h>
>>>>>>>>>>>       #include <linux/irqdomain.h>
>>>>>>>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>>>>>>>       #include <linux/module.h>
>>>>>>>>>>>       #include <linux/of_device.h>
>>>>>>>>>>>       #include <linux/of_platform.h>
>>>>>>>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>>>>>>>       struct pm8008_data {
>>>>>>>>>>>           struct device *dev;
>>>>>>>>>>> +    struct regmap *regulators_regmap;
>>>>>>>>>>>           int irq;
>>>>>>>>>>>           struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>       };
>>>>>>>>>>> @@ -150,6 +152,12 @@ static struct regmap_config
>>>>>>>>>>> qcom_mfd_regmap_cfg = {
>>>>>>>>>>>           .max_register    = 0xFFFF,
>>>>>>>>>>>       };
>>>>>>>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>>>>>>>> +{
>>>>>>>>>>> +    return chip->regulators_regmap;
>>>>>>>>>>> +}
>>>>>>>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>> Seems like abstraction for the sake of abstraction.
>>>>>>>>>>
>>>>>>>>>> Why not do the dereference inside the regulator driver?
>>>>>>>>> To derefer this in the regulator driver, we need to have the
>>>>>>>>> pm8008_data
>>>>>>>>> struct definition in the qcom_pm8008 header file.
>>>>>>>>>
>>>>>>>>> I think it doesn't look great to have only that structure in
>>>>>>>>> header and all
>>>>>>>>> other structs and enum in the mfd driver.
>>>>>>>> Then why pass 'pm8008_data' at all?
>>>>>>> There is one more option, instead of passing the pm8008_data, we could
>>>>>>> pass the pdev->dev.parent and get the pm8008 chip data directly in the
>>>>>>> pm8008_get_regmap() like below
>>>>>>>
>>>>>>>
>>>>>>> struct regmap *pm8008_get_regmap(const struct device *dev)
>>>>>>>     {
>>>>>>>         const struct pm8008_data *chip = dev_get_drvdata(dev);
>>>>>>>
>>>>>>>         return chip->regulators_regmap;
>>>>>>> }
>>>>>>> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>
>>>>>>>
>>>>>>> By doing this we can avoid having declaration of pm8008_data also in the
>>>>>>> header. Please let me know if this looks good.
>>>>>>>
>>>>>> Could you please confirm on this?
>>>>>>
>>>>>>>> What's preventing you from passing 'regmap'?
>>>>>>> I didn't get what you meant here, could you please elaborate a bit?
>>>>> Ah yes.  I authored you a patch, but became distracted. Here:
>>>>>
>>>>> -----8<--------------------8<-------
>>>>>
>>>>> From: Lee Jones <lee.jones@linaro.org>
>>>>>
>>>>> mfd: pm8008: Remove driver data structure pm8008_data
>>>>> Maintaining a local driver data structure that is never shared
>>>>> outside of the core device is an unnecessary complexity.  Half of the
>>>>> attributes were not used outside of a single function, one of which
>>>>> was not used at all.  The remaining 2 are generic and can be passed
>>>>> around as required.
>>>> Okay, but we still need to store the regulators_regmap, which is required in
>>>> the pm8008 regulator driver. Could we use a global variable for it?
>>> Look down ...
>>>
>>>>> Signed-off-by: Lee Jones <lee.jones@linaro.org>
>>>>> ---
>>>>>     drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
>>>>>     1 file changed, 20 insertions(+), 33 deletions(-)
>>>>>
>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>> index c472d7f8103c4..4b8ff947762f2 100644
>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>> @@ -54,13 +54,6 @@ enum {
>>>>>     #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
>>>>> -struct pm8008_data {
>>>>> -	struct device *dev;
>>>>> -	struct regmap *regmap;
>>>>> -	int irq;
>>>>> -	struct regmap_irq_chip_data *irq_data;
>>>>> -};
>>>>> -
>>>>>     static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
>>>>>     static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
>>>>>     static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
>>>>> @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>>>>     	.max_register	= 0xFFFF,
>>>>>     };
>>>>> -static int pm8008_init(struct pm8008_data *chip)
>>>>> +static int pm8008_init(struct regmap *regmap)
>>>>>     {
>>>>>     	int rc;
>>>>> @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
>>>>>     	 * This is required to enable the writing of TYPE registers in
>>>>>     	 * regmap_irq_sync_unlock().
>>>>>     	 */
>>>>> -	rc = regmap_write(chip->regmap,
>>>>> -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
>>>>> -			 BIT(0));
>>>>> +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>     	if (rc)
>>>>>     		return rc;
>>>>>     	/* Do the same for GPIO1 and GPIO2 peripherals */
>>>>> -	rc = regmap_write(chip->regmap,
>>>>> -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>     	if (rc)
>>>>>     		return rc;
>>>>> -	rc = regmap_write(chip->regmap,
>>>>> -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>     	return rc;
>>>>>     }
>>>>> -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>> +static int pm8008_probe_irq_peripherals(struct device *dev,
>>>>> +					struct regmap *regmap,
>>>>>     					int client_irq)
>>>>>     {
>>>>>     	int rc, i;
>>>>>     	struct regmap_irq_type *type;
>>>>>     	struct regmap_irq_chip_data *irq_data;
>>>>> -	rc = pm8008_init(chip);
>>>>> +	rc = pm8008_init(regmap);
>>>>>     	if (rc) {
>>>>> -		dev_err(chip->dev, "Init failed: %d\n", rc);
>>>>> +		dev_err(dev, "Init failed: %d\n", rc);
>>>>>     		return rc;
>>>>>     	}
>>>>> @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>     				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
>>>>>     	}
>>>>> -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
>>>>> +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
>>>>>     			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
>>>>>     	if (rc) {
>>>>> -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
>>>>> +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>     		return rc;
>>>>>     	}
>>>>> @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>     static int pm8008_probe(struct i2c_client *client)
>>>>>     {
>>>>>     	int rc;
>>>>> -	struct pm8008_data *chip;
>>>>> -
>>>>> -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
>>>>> -	if (!chip)
>>>>> -		return -ENOMEM;
>>>>> +	struct device *dev;
>>>>> +	struct regmap *regmap;
>>>>> -	chip->dev = &client->dev;
>>>>> -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>> -	if (!chip->regmap)
>>>>> +	dev = &client->dev;
>>>>> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>> +	if (!regmap)
>>>>>     		return -ENODEV;
>>>>> -	i2c_set_clientdata(client, chip);
>>>>> +	i2c_set_clientdata(client, regmap);
>>> Here ^
>>
>> I have added a dummy device and set the client data by passing regmap, see
>> below:
>>
>> +       regulators_client = i2c_new_dummy_device(client->adapter,
>> client->addr + 1);
>> +       if (IS_ERR(regulators_client)) {
>> +               dev_err(dev, "can't attach client\n");
>> +               return PTR_ERR(regulators_client);
>> +       }
>> +
>> +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
>> &qcom_mfd_regmap_cfg[1]);
>> +       if (!regmap)
>> +               return -ENODEV;
>> +
>> +       i2c_set_clientdata(client, regulators_regmap);
>>
>> Now if i try to get this regmap from regulator driver by doing
>>
>> struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
>>
>> it still gets me the regmap of pm8008@8 device and not the regulator device
>> regmap (0x9). Not sure if I'm missing something here.
> So you need to pass 2 regmap pointers?
>
> If you need to pass more than one item to the child devices, you do
> need to use a struct for that.


I need to pass only one regmap out of the two, but i am not able to 
retrieve the correct regmap simply by doing i2c_set_clientdata

probably because we are having all the child nodes under same DT node 
and thus not able to distinguish based on the dev pointer
Lee Jones June 30, 2022, 10:34 a.m. UTC | #12
On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 6/29/2022 8:48 PM, Lee Jones wrote:
> > On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > > On 6/28/2022 1:12 PM, Lee Jones wrote:
> > > > On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > 
> > > > > On 6/27/2022 1:11 PM, Lee Jones wrote:
> > > > > > On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > 
> > > > > > > Hi Lee,
> > > > > > > 
> > > > > > > 
> > > > > > > On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > On 6/20/2022 1:50 PM, Lee Jones wrote:
> > > > > > > > > On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > 
> > > > > > > > > > On 6/17/2022 2:27 AM, Lee Jones wrote:
> > > > > > > > > > > On Tue, 14 Jun 2022, Satya Priya wrote:
> > > > > > > > > > > 
> > > > > > > > > > > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > > > > > > > > > > client present at a different address space, instead of
> > > > > > > > > > > > defining a separate DT node. This avoids calling the probe
> > > > > > > > > > > > twice for the same chip, once for each client pm8008-infra
> > > > > > > > > > > > and pm8008-regulator.
> > > > > > > > > > > > 
> > > > > > > > > > > > As a part of this define pm8008_regmap_init() to do regmap
> > > > > > > > > > > > init for both the clients and define pm8008_get_regmap() to
> > > > > > > > > > > > pass the regmap to the regulator driver.
> > > > > > > > > > > > 
> > > > > > > > > > > > Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
> > > > > > > > > > > > Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> > > > > > > > > > > > ---
> > > > > > > > > > > > Changes in V15:
> > > > > > > > > > > >       - None.
> > > > > > > > > > > > 
> > > > > > > > > > > > Changes in V14:
> > > > > > > > > > > >       - None.
> > > > > > > > > > > > 
> > > > > > > > > > > > Changes in V13:
> > > > > > > > > > > >       - None.
> > > > > > > > > > > > 
> > > > > > > > > > > >       drivers/mfd/qcom-pm8008.c       | 34
> > > > > > > > > > > > ++++++++++++++++++++++++++++++++--
> > > > > > > > > > > >       include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > > > > > > > > > > >       2 files changed, 41 insertions(+), 2 deletions(-)
> > > > > > > > > > > >       create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > > > > > > > > > > 
> > > > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > index 569ffd50..55e2a8e 100644
> > > > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > @@ -9,6 +9,7 @@
> > > > > > > > > > > >       #include <linux/interrupt.h>
> > > > > > > > > > > >       #include <linux/irq.h>
> > > > > > > > > > > >       #include <linux/irqdomain.h>
> > > > > > > > > > > > +#include <linux/mfd/qcom_pm8008.h>
> > > > > > > > > > > >       #include <linux/module.h>
> > > > > > > > > > > >       #include <linux/of_device.h>
> > > > > > > > > > > >       #include <linux/of_platform.h>
> > > > > > > > > > > > @@ -57,6 +58,7 @@ enum {
> > > > > > > > > > > >       struct pm8008_data {
> > > > > > > > > > > >           struct device *dev;
> > > > > > > > > > > > +    struct regmap *regulators_regmap;
> > > > > > > > > > > >           int irq;
> > > > > > > > > > > >           struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > >       };
> > > > > > > > > > > > @@ -150,6 +152,12 @@ static struct regmap_config
> > > > > > > > > > > > qcom_mfd_regmap_cfg = {
> > > > > > > > > > > >           .max_register    = 0xFFFF,
> > > > > > > > > > > >       };
> > > > > > > > > > > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > > > > > > > > > > +{
> > > > > > > > > > > > +    return chip->regulators_regmap;
> > > > > > > > > > > > +}
> > > > > > > > > > > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > > Seems like abstraction for the sake of abstraction.
> > > > > > > > > > > 
> > > > > > > > > > > Why not do the dereference inside the regulator driver?
> > > > > > > > > > To derefer this in the regulator driver, we need to have the
> > > > > > > > > > pm8008_data
> > > > > > > > > > struct definition in the qcom_pm8008 header file.
> > > > > > > > > > 
> > > > > > > > > > I think it doesn't look great to have only that structure in
> > > > > > > > > > header and all
> > > > > > > > > > other structs and enum in the mfd driver.
> > > > > > > > > Then why pass 'pm8008_data' at all?
> > > > > > > > There is one more option, instead of passing the pm8008_data, we could
> > > > > > > > pass the pdev->dev.parent and get the pm8008 chip data directly in the
> > > > > > > > pm8008_get_regmap() like below
> > > > > > > > 
> > > > > > > > 
> > > > > > > > struct regmap *pm8008_get_regmap(const struct device *dev)
> > > > > > > >     {
> > > > > > > >         const struct pm8008_data *chip = dev_get_drvdata(dev);
> > > > > > > > 
> > > > > > > >         return chip->regulators_regmap;
> > > > > > > > }
> > > > > > > > EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > 
> > > > > > > > 
> > > > > > > > By doing this we can avoid having declaration of pm8008_data also in the
> > > > > > > > header. Please let me know if this looks good.
> > > > > > > > 
> > > > > > > Could you please confirm on this?
> > > > > > > 
> > > > > > > > > What's preventing you from passing 'regmap'?
> > > > > > > > I didn't get what you meant here, could you please elaborate a bit?
> > > > > > Ah yes.  I authored you a patch, but became distracted. Here:
> > > > > > 
> > > > > > -----8<--------------------8<-------
> > > > > > 
> > > > > > From: Lee Jones <lee.jones@linaro.org>
> > > > > > 
> > > > > > mfd: pm8008: Remove driver data structure pm8008_data
> > > > > > Maintaining a local driver data structure that is never shared
> > > > > > outside of the core device is an unnecessary complexity.  Half of the
> > > > > > attributes were not used outside of a single function, one of which
> > > > > > was not used at all.  The remaining 2 are generic and can be passed
> > > > > > around as required.
> > > > > Okay, but we still need to store the regulators_regmap, which is required in
> > > > > the pm8008 regulator driver. Could we use a global variable for it?
> > > > Look down ...
> > > > 
> > > > > > Signed-off-by: Lee Jones <lee.jones@linaro.org>
> > > > > > ---
> > > > > >     drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
> > > > > >     1 file changed, 20 insertions(+), 33 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > index c472d7f8103c4..4b8ff947762f2 100644
> > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > @@ -54,13 +54,6 @@ enum {
> > > > > >     #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
> > > > > > -struct pm8008_data {
> > > > > > -	struct device *dev;
> > > > > > -	struct regmap *regmap;
> > > > > > -	int irq;
> > > > > > -	struct regmap_irq_chip_data *irq_data;
> > > > > > -};
> > > > > > -
> > > > > >     static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
> > > > > >     static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
> > > > > >     static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
> > > > > > @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
> > > > > >     	.max_register	= 0xFFFF,
> > > > > >     };
> > > > > > -static int pm8008_init(struct pm8008_data *chip)
> > > > > > +static int pm8008_init(struct regmap *regmap)
> > > > > >     {
> > > > > >     	int rc;
> > > > > > @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
> > > > > >     	 * This is required to enable the writing of TYPE registers in
> > > > > >     	 * regmap_irq_sync_unlock().
> > > > > >     	 */
> > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
> > > > > > -			 BIT(0));
> > > > > > +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > >     	if (rc)
> > > > > >     		return rc;
> > > > > >     	/* Do the same for GPIO1 and GPIO2 peripherals */
> > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > >     	if (rc)
> > > > > >     		return rc;
> > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > >     	return rc;
> > > > > >     }
> > > > > > -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > +static int pm8008_probe_irq_peripherals(struct device *dev,
> > > > > > +					struct regmap *regmap,
> > > > > >     					int client_irq)
> > > > > >     {
> > > > > >     	int rc, i;
> > > > > >     	struct regmap_irq_type *type;
> > > > > >     	struct regmap_irq_chip_data *irq_data;
> > > > > > -	rc = pm8008_init(chip);
> > > > > > +	rc = pm8008_init(regmap);
> > > > > >     	if (rc) {
> > > > > > -		dev_err(chip->dev, "Init failed: %d\n", rc);
> > > > > > +		dev_err(dev, "Init failed: %d\n", rc);
> > > > > >     		return rc;
> > > > > >     	}
> > > > > > @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > >     				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
> > > > > >     	}
> > > > > > -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
> > > > > > +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
> > > > > >     			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
> > > > > >     	if (rc) {
> > > > > > -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > >     		return rc;
> > > > > >     	}
> > > > > > @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > >     static int pm8008_probe(struct i2c_client *client)
> > > > > >     {
> > > > > >     	int rc;
> > > > > > -	struct pm8008_data *chip;
> > > > > > -
> > > > > > -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > > > > > -	if (!chip)
> > > > > > -		return -ENOMEM;
> > > > > > +	struct device *dev;
> > > > > > +	struct regmap *regmap;
> > > > > > -	chip->dev = &client->dev;
> > > > > > -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > -	if (!chip->regmap)
> > > > > > +	dev = &client->dev;
> > > > > > +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > +	if (!regmap)
> > > > > >     		return -ENODEV;
> > > > > > -	i2c_set_clientdata(client, chip);
> > > > > > +	i2c_set_clientdata(client, regmap);
> > > > Here ^
> > > 
> > > I have added a dummy device and set the client data by passing regmap, see
> > > below:
> > > 
> > > +       regulators_client = i2c_new_dummy_device(client->adapter,
> > > client->addr + 1);
> > > +       if (IS_ERR(regulators_client)) {
> > > +               dev_err(dev, "can't attach client\n");
> > > +               return PTR_ERR(regulators_client);
> > > +       }
> > > +
> > > +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
> > > &qcom_mfd_regmap_cfg[1]);
> > > +       if (!regmap)
> > > +               return -ENODEV;
> > > +
> > > +       i2c_set_clientdata(client, regulators_regmap);
> > > 
> > > Now if i try to get this regmap from regulator driver by doing
> > > 
> > > struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
> > > 
> > > it still gets me the regmap of pm8008@8 device and not the regulator device
> > > regmap (0x9). Not sure if I'm missing something here.
> > So you need to pass 2 regmap pointers?
> > 
> > If you need to pass more than one item to the child devices, you do
> > need to use a struct for that.
> 
> I need to pass only one regmap out of the two, but i am not able to retrieve
> the correct regmap simply by doing i2c_set_clientdata
> 
> probably because we are having all the child nodes under same DT node and
> thus not able to distinguish based on the dev pointer

You can only pull out (get) the pointer that you put in (set).

Unless you over-wrote it later in the thread of execution, you are
pulling out whatever regulators_regmap happens to be.

Is qcom_mfd_regmap_cfg[1] definitely the one you want?
Satya Priya Kakitapalli (Temp) July 1, 2022, 6:46 a.m. UTC | #13
On 6/30/2022 4:04 PM, Lee Jones wrote:
> On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> On 6/29/2022 8:48 PM, Lee Jones wrote:
>>> On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>
>>>> On 6/28/2022 1:12 PM, Lee Jones wrote:
>>>>> On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>
>>>>>> On 6/27/2022 1:11 PM, Lee Jones wrote:
>>>>>>> On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>
>>>>>>>> Hi Lee,
>>>>>>>>
>>>>>>>>
>>>>>>>> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>> On 6/20/2022 1:50 PM, Lee Jones wrote:
>>>>>>>>>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>
>>>>>>>>>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>>>>>>>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>>>>>>>>>> client present at a different address space, instead of
>>>>>>>>>>>>> defining a separate DT node. This avoids calling the probe
>>>>>>>>>>>>> twice for the same chip, once for each client pm8008-infra
>>>>>>>>>>>>> and pm8008-regulator.
>>>>>>>>>>>>>
>>>>>>>>>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>>>>>>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>>>>>>>>>> pass the regmap to the regulator driver.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
>>>>>>>>>>>>> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
>>>>>>>>>>>>> ---
>>>>>>>>>>>>> Changes in V15:
>>>>>>>>>>>>>        - None.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Changes in V14:
>>>>>>>>>>>>>        - None.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Changes in V13:
>>>>>>>>>>>>>        - None.
>>>>>>>>>>>>>
>>>>>>>>>>>>>        drivers/mfd/qcom-pm8008.c       | 34
>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++--
>>>>>>>>>>>>>        include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>>>>>>>>>        2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>>>>>>>>>        create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>>>>>>>>>
>>>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> index 569ffd50..55e2a8e 100644
>>>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> @@ -9,6 +9,7 @@
>>>>>>>>>>>>>        #include <linux/interrupt.h>
>>>>>>>>>>>>>        #include <linux/irq.h>
>>>>>>>>>>>>>        #include <linux/irqdomain.h>
>>>>>>>>>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>>>>>>>>>        #include <linux/module.h>
>>>>>>>>>>>>>        #include <linux/of_device.h>
>>>>>>>>>>>>>        #include <linux/of_platform.h>
>>>>>>>>>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>>>>>>>>>        struct pm8008_data {
>>>>>>>>>>>>>            struct device *dev;
>>>>>>>>>>>>> +    struct regmap *regulators_regmap;
>>>>>>>>>>>>>            int irq;
>>>>>>>>>>>>>            struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>>        };
>>>>>>>>>>>>> @@ -150,6 +152,12 @@ static struct regmap_config
>>>>>>>>>>>>> qcom_mfd_regmap_cfg = {
>>>>>>>>>>>>>            .max_register    = 0xFFFF,
>>>>>>>>>>>>>        };
>>>>>>>>>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    return chip->regulators_regmap;
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>> Seems like abstraction for the sake of abstraction.
>>>>>>>>>>>>
>>>>>>>>>>>> Why not do the dereference inside the regulator driver?
>>>>>>>>>>> To derefer this in the regulator driver, we need to have the
>>>>>>>>>>> pm8008_data
>>>>>>>>>>> struct definition in the qcom_pm8008 header file.
>>>>>>>>>>>
>>>>>>>>>>> I think it doesn't look great to have only that structure in
>>>>>>>>>>> header and all
>>>>>>>>>>> other structs and enum in the mfd driver.
>>>>>>>>>> Then why pass 'pm8008_data' at all?
>>>>>>>>> There is one more option, instead of passing the pm8008_data, we could
>>>>>>>>> pass the pdev->dev.parent and get the pm8008 chip data directly in the
>>>>>>>>> pm8008_get_regmap() like below
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> struct regmap *pm8008_get_regmap(const struct device *dev)
>>>>>>>>>      {
>>>>>>>>>          const struct pm8008_data *chip = dev_get_drvdata(dev);
>>>>>>>>>
>>>>>>>>>          return chip->regulators_regmap;
>>>>>>>>> }
>>>>>>>>> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> By doing this we can avoid having declaration of pm8008_data also in the
>>>>>>>>> header. Please let me know if this looks good.
>>>>>>>>>
>>>>>>>> Could you please confirm on this?
>>>>>>>>
>>>>>>>>>> What's preventing you from passing 'regmap'?
>>>>>>>>> I didn't get what you meant here, could you please elaborate a bit?
>>>>>>> Ah yes.  I authored you a patch, but became distracted. Here:
>>>>>>>
>>>>>>> -----8<--------------------8<-------
>>>>>>>
>>>>>>> From: Lee Jones <lee.jones@linaro.org>
>>>>>>>
>>>>>>> mfd: pm8008: Remove driver data structure pm8008_data
>>>>>>> Maintaining a local driver data structure that is never shared
>>>>>>> outside of the core device is an unnecessary complexity.  Half of the
>>>>>>> attributes were not used outside of a single function, one of which
>>>>>>> was not used at all.  The remaining 2 are generic and can be passed
>>>>>>> around as required.
>>>>>> Okay, but we still need to store the regulators_regmap, which is required in
>>>>>> the pm8008 regulator driver. Could we use a global variable for it?
>>>>> Look down ...
>>>>>
>>>>>>> Signed-off-by: Lee Jones <lee.jones@linaro.org>
>>>>>>> ---
>>>>>>>      drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
>>>>>>>      1 file changed, 20 insertions(+), 33 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>> index c472d7f8103c4..4b8ff947762f2 100644
>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>> @@ -54,13 +54,6 @@ enum {
>>>>>>>      #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
>>>>>>> -struct pm8008_data {
>>>>>>> -	struct device *dev;
>>>>>>> -	struct regmap *regmap;
>>>>>>> -	int irq;
>>>>>>> -	struct regmap_irq_chip_data *irq_data;
>>>>>>> -};
>>>>>>> -
>>>>>>>      static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
>>>>>>>      static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
>>>>>>>      static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
>>>>>>> @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>>>>>>      	.max_register	= 0xFFFF,
>>>>>>>      };
>>>>>>> -static int pm8008_init(struct pm8008_data *chip)
>>>>>>> +static int pm8008_init(struct regmap *regmap)
>>>>>>>      {
>>>>>>>      	int rc;
>>>>>>> @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
>>>>>>>      	 * This is required to enable the writing of TYPE registers in
>>>>>>>      	 * regmap_irq_sync_unlock().
>>>>>>>      	 */
>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>> -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
>>>>>>> -			 BIT(0));
>>>>>>> +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>      	if (rc)
>>>>>>>      		return rc;
>>>>>>>      	/* Do the same for GPIO1 and GPIO2 peripherals */
>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>> -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>      	if (rc)
>>>>>>>      		return rc;
>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>> -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>      	return rc;
>>>>>>>      }
>>>>>>> -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>> +static int pm8008_probe_irq_peripherals(struct device *dev,
>>>>>>> +					struct regmap *regmap,
>>>>>>>      					int client_irq)
>>>>>>>      {
>>>>>>>      	int rc, i;
>>>>>>>      	struct regmap_irq_type *type;
>>>>>>>      	struct regmap_irq_chip_data *irq_data;
>>>>>>> -	rc = pm8008_init(chip);
>>>>>>> +	rc = pm8008_init(regmap);
>>>>>>>      	if (rc) {
>>>>>>> -		dev_err(chip->dev, "Init failed: %d\n", rc);
>>>>>>> +		dev_err(dev, "Init failed: %d\n", rc);
>>>>>>>      		return rc;
>>>>>>>      	}
>>>>>>> @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>      				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
>>>>>>>      	}
>>>>>>> -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
>>>>>>> +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
>>>>>>>      			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
>>>>>>>      	if (rc) {
>>>>>>> -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>> +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>      		return rc;
>>>>>>>      	}
>>>>>>> @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>      static int pm8008_probe(struct i2c_client *client)
>>>>>>>      {
>>>>>>>      	int rc;
>>>>>>> -	struct pm8008_data *chip;
>>>>>>> -
>>>>>>> -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
>>>>>>> -	if (!chip)
>>>>>>> -		return -ENOMEM;
>>>>>>> +	struct device *dev;
>>>>>>> +	struct regmap *regmap;
>>>>>>> -	chip->dev = &client->dev;
>>>>>>> -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>> -	if (!chip->regmap)
>>>>>>> +	dev = &client->dev;
>>>>>>> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>> +	if (!regmap)
>>>>>>>      		return -ENODEV;
>>>>>>> -	i2c_set_clientdata(client, chip);
>>>>>>> +	i2c_set_clientdata(client, regmap);
>>>>> Here ^
>>>> I have added a dummy device and set the client data by passing regmap, see
>>>> below:
>>>>
>>>> +       regulators_client = i2c_new_dummy_device(client->adapter,
>>>> client->addr + 1);
>>>> +       if (IS_ERR(regulators_client)) {
>>>> +               dev_err(dev, "can't attach client\n");
>>>> +               return PTR_ERR(regulators_client);
>>>> +       }
>>>> +
>>>> +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
>>>> &qcom_mfd_regmap_cfg[1]);
>>>> +       if (!regmap)
>>>> +               return -ENODEV;
>>>> +
>>>> +       i2c_set_clientdata(client, regulators_regmap);
>>>>
>>>> Now if i try to get this regmap from regulator driver by doing
>>>>
>>>> struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
>>>>
>>>> it still gets me the regmap of pm8008@8 device and not the regulator device
>>>> regmap (0x9). Not sure if I'm missing something here.
>>> So you need to pass 2 regmap pointers?
>>>
>>> If you need to pass more than one item to the child devices, you do
>>> need to use a struct for that.
>> I need to pass only one regmap out of the two, but i am not able to retrieve
>> the correct regmap simply by doing i2c_set_clientdata
>>
>> probably because we are having all the child nodes under same DT node and
>> thus not able to distinguish based on the dev pointer
> You can only pull out (get) the pointer that you put in (set).
>
> Unless you over-wrote it later in the thread of execution, you are
> pulling out whatever regulators_regmap happens to be.
>
> Is qcom_mfd_regmap_cfg[1] definitely the one you want?


Yes, I need qcom_mfd_regmap_cfg[1]

Pasting code snippet for reference:

static struct regmap_config qcom_mfd_regmap_cfg[2] = {
      {

          .name = "infra",
          .reg_bits   = 16,
          .val_bits   = 8,
          .max_register   = 0xFFFF,
      },
      {
          .name = "regulators",
          .reg_bits   = 16,
          .val_bits   = 8,
          .max_register   = 0xFFFF,
      },

};


Inside pm8008_probe:


      regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
      if (!regmap)
          return -ENODEV;

      i2c_set_clientdata(client, regmap);


      regulators_client = i2c_new_dummy_device(client->adapter, 
client->addr + 1);
      if (IS_ERR(regulators_client)) {
          dev_err(dev, "can't attach client\n");
          return PTR_ERR(regulators_client);
      }

      regulators_regmap = devm_regmap_init_i2c(regulators_client, 
&qcom_mfd_regmap_cfg[1]);
      if (!regmap)
          return -ENODEV;

      i2c_set_clientdata(regulators_client, regulators_regmap);

In qcom-pm8008-regulator.c I tried to get the regmap using


dev_get_regmap(pdev->dev.parent, "regulators");
Lee Jones July 1, 2022, 7:54 a.m. UTC | #14
On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 6/30/2022 4:04 PM, Lee Jones wrote:
> > On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > > On 6/29/2022 8:48 PM, Lee Jones wrote:
> > > > On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > 
> > > > > On 6/28/2022 1:12 PM, Lee Jones wrote:
> > > > > > On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > 
> > > > > > > On 6/27/2022 1:11 PM, Lee Jones wrote:
> > > > > > > > On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > 
> > > > > > > > > Hi Lee,
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > On 6/20/2022 1:50 PM, Lee Jones wrote:
> > > > > > > > > > > On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > 
> > > > > > > > > > > > On 6/17/2022 2:27 AM, Lee Jones wrote:
> > > > > > > > > > > > > On Tue, 14 Jun 2022, Satya Priya wrote:
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > > > > > > > > > > > > client present at a different address space, instead of
> > > > > > > > > > > > > > defining a separate DT node. This avoids calling the probe
> > > > > > > > > > > > > > twice for the same chip, once for each client pm8008-infra
> > > > > > > > > > > > > > and pm8008-regulator.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > As a part of this define pm8008_regmap_init() to do regmap
> > > > > > > > > > > > > > init for both the clients and define pm8008_get_regmap() to
> > > > > > > > > > > > > > pass the regmap to the regulator driver.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
> > > > > > > > > > > > > > Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> > > > > > > > > > > > > > ---
> > > > > > > > > > > > > > Changes in V15:
> > > > > > > > > > > > > >        - None.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Changes in V14:
> > > > > > > > > > > > > >        - None.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Changes in V13:
> > > > > > > > > > > > > >        - None.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > >        drivers/mfd/qcom-pm8008.c       | 34
> > > > > > > > > > > > > > ++++++++++++++++++++++++++++++++--
> > > > > > > > > > > > > >        include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > > > > > > > > > > > > >        2 files changed, 41 insertions(+), 2 deletions(-)
> > > > > > > > > > > > > >        create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > index 569ffd50..55e2a8e 100644
> > > > > > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > @@ -9,6 +9,7 @@
> > > > > > > > > > > > > >        #include <linux/interrupt.h>
> > > > > > > > > > > > > >        #include <linux/irq.h>
> > > > > > > > > > > > > >        #include <linux/irqdomain.h>
> > > > > > > > > > > > > > +#include <linux/mfd/qcom_pm8008.h>
> > > > > > > > > > > > > >        #include <linux/module.h>
> > > > > > > > > > > > > >        #include <linux/of_device.h>
> > > > > > > > > > > > > >        #include <linux/of_platform.h>
> > > > > > > > > > > > > > @@ -57,6 +58,7 @@ enum {
> > > > > > > > > > > > > >        struct pm8008_data {
> > > > > > > > > > > > > >            struct device *dev;
> > > > > > > > > > > > > > +    struct regmap *regulators_regmap;
> > > > > > > > > > > > > >            int irq;
> > > > > > > > > > > > > >            struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > > > >        };
> > > > > > > > > > > > > > @@ -150,6 +152,12 @@ static struct regmap_config
> > > > > > > > > > > > > > qcom_mfd_regmap_cfg = {
> > > > > > > > > > > > > >            .max_register    = 0xFFFF,
> > > > > > > > > > > > > >        };
> > > > > > > > > > > > > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > > > > > > > > > > > > +{
> > > > > > > > > > > > > > +    return chip->regulators_regmap;
> > > > > > > > > > > > > > +}
> > > > > > > > > > > > > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > > > > Seems like abstraction for the sake of abstraction.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Why not do the dereference inside the regulator driver?
> > > > > > > > > > > > To derefer this in the regulator driver, we need to have the
> > > > > > > > > > > > pm8008_data
> > > > > > > > > > > > struct definition in the qcom_pm8008 header file.
> > > > > > > > > > > > 
> > > > > > > > > > > > I think it doesn't look great to have only that structure in
> > > > > > > > > > > > header and all
> > > > > > > > > > > > other structs and enum in the mfd driver.
> > > > > > > > > > > Then why pass 'pm8008_data' at all?
> > > > > > > > > > There is one more option, instead of passing the pm8008_data, we could
> > > > > > > > > > pass the pdev->dev.parent and get the pm8008 chip data directly in the
> > > > > > > > > > pm8008_get_regmap() like below
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > struct regmap *pm8008_get_regmap(const struct device *dev)
> > > > > > > > > >      {
> > > > > > > > > >          const struct pm8008_data *chip = dev_get_drvdata(dev);
> > > > > > > > > > 
> > > > > > > > > >          return chip->regulators_regmap;
> > > > > > > > > > }
> > > > > > > > > > EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > By doing this we can avoid having declaration of pm8008_data also in the
> > > > > > > > > > header. Please let me know if this looks good.
> > > > > > > > > > 
> > > > > > > > > Could you please confirm on this?
> > > > > > > > > 
> > > > > > > > > > > What's preventing you from passing 'regmap'?
> > > > > > > > > > I didn't get what you meant here, could you please elaborate a bit?
> > > > > > > > Ah yes.  I authored you a patch, but became distracted. Here:
> > > > > > > > 
> > > > > > > > -----8<--------------------8<-------
> > > > > > > > 
> > > > > > > > From: Lee Jones <lee.jones@linaro.org>
> > > > > > > > 
> > > > > > > > mfd: pm8008: Remove driver data structure pm8008_data
> > > > > > > > Maintaining a local driver data structure that is never shared
> > > > > > > > outside of the core device is an unnecessary complexity.  Half of the
> > > > > > > > attributes were not used outside of a single function, one of which
> > > > > > > > was not used at all.  The remaining 2 are generic and can be passed
> > > > > > > > around as required.
> > > > > > > Okay, but we still need to store the regulators_regmap, which is required in
> > > > > > > the pm8008 regulator driver. Could we use a global variable for it?
> > > > > > Look down ...
> > > > > > 
> > > > > > > > Signed-off-by: Lee Jones <lee.jones@linaro.org>
> > > > > > > > ---
> > > > > > > >      drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
> > > > > > > >      1 file changed, 20 insertions(+), 33 deletions(-)
> > > > > > > > 
> > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > index c472d7f8103c4..4b8ff947762f2 100644
> > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > @@ -54,13 +54,6 @@ enum {
> > > > > > > >      #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
> > > > > > > > -struct pm8008_data {
> > > > > > > > -	struct device *dev;
> > > > > > > > -	struct regmap *regmap;
> > > > > > > > -	int irq;
> > > > > > > > -	struct regmap_irq_chip_data *irq_data;
> > > > > > > > -};
> > > > > > > > -
> > > > > > > >      static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
> > > > > > > >      static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
> > > > > > > >      static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
> > > > > > > > @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
> > > > > > > >      	.max_register	= 0xFFFF,
> > > > > > > >      };
> > > > > > > > -static int pm8008_init(struct pm8008_data *chip)
> > > > > > > > +static int pm8008_init(struct regmap *regmap)
> > > > > > > >      {
> > > > > > > >      	int rc;
> > > > > > > > @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
> > > > > > > >      	 * This is required to enable the writing of TYPE registers in
> > > > > > > >      	 * regmap_irq_sync_unlock().
> > > > > > > >      	 */
> > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
> > > > > > > > -			 BIT(0));
> > > > > > > > +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > >      	if (rc)
> > > > > > > >      		return rc;
> > > > > > > >      	/* Do the same for GPIO1 and GPIO2 peripherals */
> > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > >      	if (rc)
> > > > > > > >      		return rc;
> > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > >      	return rc;
> > > > > > > >      }
> > > > > > > > -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > +static int pm8008_probe_irq_peripherals(struct device *dev,
> > > > > > > > +					struct regmap *regmap,
> > > > > > > >      					int client_irq)
> > > > > > > >      {
> > > > > > > >      	int rc, i;
> > > > > > > >      	struct regmap_irq_type *type;
> > > > > > > >      	struct regmap_irq_chip_data *irq_data;
> > > > > > > > -	rc = pm8008_init(chip);
> > > > > > > > +	rc = pm8008_init(regmap);
> > > > > > > >      	if (rc) {
> > > > > > > > -		dev_err(chip->dev, "Init failed: %d\n", rc);
> > > > > > > > +		dev_err(dev, "Init failed: %d\n", rc);
> > > > > > > >      		return rc;
> > > > > > > >      	}
> > > > > > > > @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > >      				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
> > > > > > > >      	}
> > > > > > > > -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
> > > > > > > > +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
> > > > > > > >      			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
> > > > > > > >      	if (rc) {
> > > > > > > > -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > > > +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > > >      		return rc;
> > > > > > > >      	}
> > > > > > > > @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > >      static int pm8008_probe(struct i2c_client *client)
> > > > > > > >      {
> > > > > > > >      	int rc;
> > > > > > > > -	struct pm8008_data *chip;
> > > > > > > > -
> > > > > > > > -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > > > > > > > -	if (!chip)
> > > > > > > > -		return -ENOMEM;
> > > > > > > > +	struct device *dev;
> > > > > > > > +	struct regmap *regmap;
> > > > > > > > -	chip->dev = &client->dev;
> > > > > > > > -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > > > -	if (!chip->regmap)
> > > > > > > > +	dev = &client->dev;
> > > > > > > > +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > > > +	if (!regmap)
> > > > > > > >      		return -ENODEV;
> > > > > > > > -	i2c_set_clientdata(client, chip);
> > > > > > > > +	i2c_set_clientdata(client, regmap);
> > > > > > Here ^
> > > > > I have added a dummy device and set the client data by passing regmap, see
> > > > > below:
> > > > > 
> > > > > +       regulators_client = i2c_new_dummy_device(client->adapter,
> > > > > client->addr + 1);
> > > > > +       if (IS_ERR(regulators_client)) {
> > > > > +               dev_err(dev, "can't attach client\n");
> > > > > +               return PTR_ERR(regulators_client);
> > > > > +       }
> > > > > +
> > > > > +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
> > > > > &qcom_mfd_regmap_cfg[1]);
> > > > > +       if (!regmap)
> > > > > +               return -ENODEV;
> > > > > +
> > > > > +       i2c_set_clientdata(client, regulators_regmap);
> > > > > 
> > > > > Now if i try to get this regmap from regulator driver by doing
> > > > > 
> > > > > struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
> > > > > 
> > > > > it still gets me the regmap of pm8008@8 device and not the regulator device
> > > > > regmap (0x9). Not sure if I'm missing something here.
> > > > So you need to pass 2 regmap pointers?
> > > > 
> > > > If you need to pass more than one item to the child devices, you do
> > > > need to use a struct for that.
> > > I need to pass only one regmap out of the two, but i am not able to retrieve
> > > the correct regmap simply by doing i2c_set_clientdata
> > > 
> > > probably because we are having all the child nodes under same DT node and
> > > thus not able to distinguish based on the dev pointer
> > You can only pull out (get) the pointer that you put in (set).
> > 
> > Unless you over-wrote it later in the thread of execution, you are
> > pulling out whatever regulators_regmap happens to be.
> > 
> > Is qcom_mfd_regmap_cfg[1] definitely the one you want?
> 
> 
> Yes, I need qcom_mfd_regmap_cfg[1]
> 
> Pasting code snippet for reference:
> 
> static struct regmap_config qcom_mfd_regmap_cfg[2] = {
>      {
> 
>          .name = "infra",
>          .reg_bits   = 16,
>          .val_bits   = 8,
>          .max_register   = 0xFFFF,
>      },
>      {
>          .name = "regulators",
>          .reg_bits   = 16,
>          .val_bits   = 8,
>          .max_register   = 0xFFFF,
>      },
> 
> };
> 
> 
> Inside pm8008_probe:
> 
> 
>      regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
>      if (!regmap)
>          return -ENODEV;
> 
>      i2c_set_clientdata(client, regmap);
> 
> 
>      regulators_client = i2c_new_dummy_device(client->adapter, client->addr
> + 1);
>      if (IS_ERR(regulators_client)) {
>          dev_err(dev, "can't attach client\n");
>          return PTR_ERR(regulators_client);
>      }
> 
>      regulators_regmap = devm_regmap_init_i2c(regulators_client,
> &qcom_mfd_regmap_cfg[1]);
>      if (!regmap)
>          return -ENODEV;
> 
>      i2c_set_clientdata(regulators_client, regulators_regmap);

You can't call this twice.

Doing so with over-write regmap with regulators_regmap.

You said you only needed one?

  "I need to pass only one regmap out of the two, but i am not able to retrieve"

> In qcom-pm8008-regulator.c I tried to get the regmap using
> 
> dev_get_regmap(pdev->dev.parent, "regulators");

I haven't looked at this API before.  I suggest that this would be
used *instead* of passing the regmap pointer via driver_data.

It looks like you're using different devices to init your regmaps;
'client' and 'regulator_client' (derived from client->adapter).

"regulators" is registered using regulators_regmap which was *not*
init'ed with pdev->dev.parent (same as client->dev), so trying to
dev_get_regmap() with that device pointer will not work.
Satya Priya Kakitapalli (Temp) July 1, 2022, 8:47 a.m. UTC | #15
On 7/1/2022 1:24 PM, Lee Jones wrote:
> On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> On 6/30/2022 4:04 PM, Lee Jones wrote:
>>> On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>
>>>> On 6/29/2022 8:48 PM, Lee Jones wrote:
>>>>> On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>
>>>>>> On 6/28/2022 1:12 PM, Lee Jones wrote:
>>>>>>> On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>
>>>>>>>> On 6/27/2022 1:11 PM, Lee Jones wrote:
>>>>>>>>> On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>
>>>>>>>>>> Hi Lee,
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>> On 6/20/2022 1:50 PM, Lee Jones wrote:
>>>>>>>>>>>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>>>>>>>>>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>>>>>>>>>>>> client present at a different address space, instead of
>>>>>>>>>>>>>>> defining a separate DT node. This avoids calling the probe
>>>>>>>>>>>>>>> twice for the same chip, once for each client pm8008-infra
>>>>>>>>>>>>>>> and pm8008-regulator.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>>>>>>>>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>>>>>>>>>>>> pass the regmap to the regulator driver.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
>>>>>>>>>>>>>>> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>> Changes in V15:
>>>>>>>>>>>>>>>         - None.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Changes in V14:
>>>>>>>>>>>>>>>         - None.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Changes in V13:
>>>>>>>>>>>>>>>         - None.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>         drivers/mfd/qcom-pm8008.c       | 34
>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++--
>>>>>>>>>>>>>>>         include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>>>>>>>>>>>         2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>>>>>>>>>>>         create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>> index 569ffd50..55e2a8e 100644
>>>>>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>> @@ -9,6 +9,7 @@
>>>>>>>>>>>>>>>         #include <linux/interrupt.h>
>>>>>>>>>>>>>>>         #include <linux/irq.h>
>>>>>>>>>>>>>>>         #include <linux/irqdomain.h>
>>>>>>>>>>>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>>>>>>>>>>>         #include <linux/module.h>
>>>>>>>>>>>>>>>         #include <linux/of_device.h>
>>>>>>>>>>>>>>>         #include <linux/of_platform.h>
>>>>>>>>>>>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>>>>>>>>>>>         struct pm8008_data {
>>>>>>>>>>>>>>>             struct device *dev;
>>>>>>>>>>>>>>> +    struct regmap *regulators_regmap;
>>>>>>>>>>>>>>>             int irq;
>>>>>>>>>>>>>>>             struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>>>>         };
>>>>>>>>>>>>>>> @@ -150,6 +152,12 @@ static struct regmap_config
>>>>>>>>>>>>>>> qcom_mfd_regmap_cfg = {
>>>>>>>>>>>>>>>             .max_register    = 0xFFFF,
>>>>>>>>>>>>>>>         };
>>>>>>>>>>>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    return chip->regulators_regmap;
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>>>> Seems like abstraction for the sake of abstraction.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Why not do the dereference inside the regulator driver?
>>>>>>>>>>>>> To derefer this in the regulator driver, we need to have the
>>>>>>>>>>>>> pm8008_data
>>>>>>>>>>>>> struct definition in the qcom_pm8008 header file.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I think it doesn't look great to have only that structure in
>>>>>>>>>>>>> header and all
>>>>>>>>>>>>> other structs and enum in the mfd driver.
>>>>>>>>>>>> Then why pass 'pm8008_data' at all?
>>>>>>>>>>> There is one more option, instead of passing the pm8008_data, we could
>>>>>>>>>>> pass the pdev->dev.parent and get the pm8008 chip data directly in the
>>>>>>>>>>> pm8008_get_regmap() like below
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> struct regmap *pm8008_get_regmap(const struct device *dev)
>>>>>>>>>>>       {
>>>>>>>>>>>           const struct pm8008_data *chip = dev_get_drvdata(dev);
>>>>>>>>>>>
>>>>>>>>>>>           return chip->regulators_regmap;
>>>>>>>>>>> }
>>>>>>>>>>> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> By doing this we can avoid having declaration of pm8008_data also in the
>>>>>>>>>>> header. Please let me know if this looks good.
>>>>>>>>>>>
>>>>>>>>>> Could you please confirm on this?
>>>>>>>>>>
>>>>>>>>>>>> What's preventing you from passing 'regmap'?
>>>>>>>>>>> I didn't get what you meant here, could you please elaborate a bit?
>>>>>>>>> Ah yes.  I authored you a patch, but became distracted. Here:
>>>>>>>>>
>>>>>>>>> -----8<--------------------8<-------
>>>>>>>>>
>>>>>>>>> From: Lee Jones <lee.jones@linaro.org>
>>>>>>>>>
>>>>>>>>> mfd: pm8008: Remove driver data structure pm8008_data
>>>>>>>>> Maintaining a local driver data structure that is never shared
>>>>>>>>> outside of the core device is an unnecessary complexity.  Half of the
>>>>>>>>> attributes were not used outside of a single function, one of which
>>>>>>>>> was not used at all.  The remaining 2 are generic and can be passed
>>>>>>>>> around as required.
>>>>>>>> Okay, but we still need to store the regulators_regmap, which is required in
>>>>>>>> the pm8008 regulator driver. Could we use a global variable for it?
>>>>>>> Look down ...
>>>>>>>
>>>>>>>>> Signed-off-by: Lee Jones <lee.jones@linaro.org>
>>>>>>>>> ---
>>>>>>>>>       drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
>>>>>>>>>       1 file changed, 20 insertions(+), 33 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>> index c472d7f8103c4..4b8ff947762f2 100644
>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>> @@ -54,13 +54,6 @@ enum {
>>>>>>>>>       #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
>>>>>>>>> -struct pm8008_data {
>>>>>>>>> -	struct device *dev;
>>>>>>>>> -	struct regmap *regmap;
>>>>>>>>> -	int irq;
>>>>>>>>> -	struct regmap_irq_chip_data *irq_data;
>>>>>>>>> -};
>>>>>>>>> -
>>>>>>>>>       static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
>>>>>>>>>       static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
>>>>>>>>>       static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
>>>>>>>>> @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>>>>>>>>       	.max_register	= 0xFFFF,
>>>>>>>>>       };
>>>>>>>>> -static int pm8008_init(struct pm8008_data *chip)
>>>>>>>>> +static int pm8008_init(struct regmap *regmap)
>>>>>>>>>       {
>>>>>>>>>       	int rc;
>>>>>>>>> @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
>>>>>>>>>       	 * This is required to enable the writing of TYPE registers in
>>>>>>>>>       	 * regmap_irq_sync_unlock().
>>>>>>>>>       	 */
>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>> -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
>>>>>>>>> -			 BIT(0));
>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>       	if (rc)
>>>>>>>>>       		return rc;
>>>>>>>>>       	/* Do the same for GPIO1 and GPIO2 peripherals */
>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>> -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>       	if (rc)
>>>>>>>>>       		return rc;
>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>> -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>       	return rc;
>>>>>>>>>       }
>>>>>>>>> -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>> +static int pm8008_probe_irq_peripherals(struct device *dev,
>>>>>>>>> +					struct regmap *regmap,
>>>>>>>>>       					int client_irq)
>>>>>>>>>       {
>>>>>>>>>       	int rc, i;
>>>>>>>>>       	struct regmap_irq_type *type;
>>>>>>>>>       	struct regmap_irq_chip_data *irq_data;
>>>>>>>>> -	rc = pm8008_init(chip);
>>>>>>>>> +	rc = pm8008_init(regmap);
>>>>>>>>>       	if (rc) {
>>>>>>>>> -		dev_err(chip->dev, "Init failed: %d\n", rc);
>>>>>>>>> +		dev_err(dev, "Init failed: %d\n", rc);
>>>>>>>>>       		return rc;
>>>>>>>>>       	}
>>>>>>>>> @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>       				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
>>>>>>>>>       	}
>>>>>>>>> -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
>>>>>>>>> +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
>>>>>>>>>       			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
>>>>>>>>>       	if (rc) {
>>>>>>>>> -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>>> +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>>>       		return rc;
>>>>>>>>>       	}
>>>>>>>>> @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>       static int pm8008_probe(struct i2c_client *client)
>>>>>>>>>       {
>>>>>>>>>       	int rc;
>>>>>>>>> -	struct pm8008_data *chip;
>>>>>>>>> -
>>>>>>>>> -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
>>>>>>>>> -	if (!chip)
>>>>>>>>> -		return -ENOMEM;
>>>>>>>>> +	struct device *dev;
>>>>>>>>> +	struct regmap *regmap;
>>>>>>>>> -	chip->dev = &client->dev;
>>>>>>>>> -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>>>> -	if (!chip->regmap)
>>>>>>>>> +	dev = &client->dev;
>>>>>>>>> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>>>> +	if (!regmap)
>>>>>>>>>       		return -ENODEV;
>>>>>>>>> -	i2c_set_clientdata(client, chip);
>>>>>>>>> +	i2c_set_clientdata(client, regmap);
>>>>>>> Here ^
>>>>>> I have added a dummy device and set the client data by passing regmap, see
>>>>>> below:
>>>>>>
>>>>>> +       regulators_client = i2c_new_dummy_device(client->adapter,
>>>>>> client->addr + 1);
>>>>>> +       if (IS_ERR(regulators_client)) {
>>>>>> +               dev_err(dev, "can't attach client\n");
>>>>>> +               return PTR_ERR(regulators_client);
>>>>>> +       }
>>>>>> +
>>>>>> +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
>>>>>> &qcom_mfd_regmap_cfg[1]);
>>>>>> +       if (!regmap)
>>>>>> +               return -ENODEV;
>>>>>> +
>>>>>> +       i2c_set_clientdata(client, regulators_regmap);
>>>>>>
>>>>>> Now if i try to get this regmap from regulator driver by doing
>>>>>>
>>>>>> struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
>>>>>>
>>>>>> it still gets me the regmap of pm8008@8 device and not the regulator device
>>>>>> regmap (0x9). Not sure if I'm missing something here.
>>>>> So you need to pass 2 regmap pointers?
>>>>>
>>>>> If you need to pass more than one item to the child devices, you do
>>>>> need to use a struct for that.
>>>> I need to pass only one regmap out of the two, but i am not able to retrieve
>>>> the correct regmap simply by doing i2c_set_clientdata
>>>>
>>>> probably because we are having all the child nodes under same DT node and
>>>> thus not able to distinguish based on the dev pointer
>>> You can only pull out (get) the pointer that you put in (set).
>>>
>>> Unless you over-wrote it later in the thread of execution, you are
>>> pulling out whatever regulators_regmap happens to be.
>>>
>>> Is qcom_mfd_regmap_cfg[1] definitely the one you want?
>>
>> Yes, I need qcom_mfd_regmap_cfg[1]
>>
>> Pasting code snippet for reference:
>>
>> static struct regmap_config qcom_mfd_regmap_cfg[2] = {
>>       {
>>
>>           .name = "infra",
>>           .reg_bits   = 16,
>>           .val_bits   = 8,
>>           .max_register   = 0xFFFF,
>>       },
>>       {
>>           .name = "regulators",
>>           .reg_bits   = 16,
>>           .val_bits   = 8,
>>           .max_register   = 0xFFFF,
>>       },
>>
>> };
>>
>>
>> Inside pm8008_probe:
>>
>>
>>       regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
>>       if (!regmap)
>>           return -ENODEV;
>>
>>       i2c_set_clientdata(client, regmap);
>>
>>
>>       regulators_client = i2c_new_dummy_device(client->adapter, client->addr
>> + 1);
>>       if (IS_ERR(regulators_client)) {
>>           dev_err(dev, "can't attach client\n");
>>           return PTR_ERR(regulators_client);
>>       }
>>
>>       regulators_regmap = devm_regmap_init_i2c(regulators_client,
>> &qcom_mfd_regmap_cfg[1]);
>>       if (!regmap)
>>           return -ENODEV;
>>
>>       i2c_set_clientdata(regulators_client, regulators_regmap);
> You can't call this twice.
>
> Doing so with over-write regmap with regulators_regmap.
>
> You said you only needed one?
>
>    "I need to pass only one regmap out of the two, but i am not able to retrieve"


I thought you asked whether we have to pass two regmaps to the child 
regulator driver.


>> In qcom-pm8008-regulator.c I tried to get the regmap using
>>
>> dev_get_regmap(pdev->dev.parent, "regulators");
> I haven't looked at this API before.  I suggest that this would be
> used *instead* of passing the regmap pointer via driver_data.
>
> It looks like you're using different devices to init your regmaps;
> 'client' and 'regulator_client' (derived from client->adapter).
>
> "regulators" is registered using regulators_regmap which was *not*
> init'ed with pdev->dev.parent (same as client->dev), so trying to
> dev_get_regmap() with that device pointer will not work.


Okay, So I will leave the driver as is then?
Lee Jones July 1, 2022, 9:12 a.m. UTC | #16
On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 7/1/2022 1:24 PM, Lee Jones wrote:
> > On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > > On 6/30/2022 4:04 PM, Lee Jones wrote:
> > > > On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > 
> > > > > On 6/29/2022 8:48 PM, Lee Jones wrote:
> > > > > > On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > 
> > > > > > > On 6/28/2022 1:12 PM, Lee Jones wrote:
> > > > > > > > On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > 
> > > > > > > > > On 6/27/2022 1:11 PM, Lee Jones wrote:
> > > > > > > > > > On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > 
> > > > > > > > > > > Hi Lee,
> > > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > On 6/20/2022 1:50 PM, Lee Jones wrote:
> > > > > > > > > > > > > On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > On 6/17/2022 2:27 AM, Lee Jones wrote:
> > > > > > > > > > > > > > > On Tue, 14 Jun 2022, Satya Priya wrote:
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > > > > > > > > > > > > > > client present at a different address space, instead of
> > > > > > > > > > > > > > > > defining a separate DT node. This avoids calling the probe
> > > > > > > > > > > > > > > > twice for the same chip, once for each client pm8008-infra
> > > > > > > > > > > > > > > > and pm8008-regulator.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > As a part of this define pm8008_regmap_init() to do regmap
> > > > > > > > > > > > > > > > init for both the clients and define pm8008_get_regmap() to
> > > > > > > > > > > > > > > > pass the regmap to the regulator driver.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Signed-off-by: Satya Priya <quic_c_skakit@quicinc.com>
> > > > > > > > > > > > > > > > Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> > > > > > > > > > > > > > > > ---
> > > > > > > > > > > > > > > > Changes in V15:
> > > > > > > > > > > > > > > >         - None.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Changes in V14:
> > > > > > > > > > > > > > > >         - None.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Changes in V13:
> > > > > > > > > > > > > > > >         - None.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > >         drivers/mfd/qcom-pm8008.c       | 34
> > > > > > > > > > > > > > > > ++++++++++++++++++++++++++++++++--
> > > > > > > > > > > > > > > >         include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > > > > > > > > > > > > > > >         2 files changed, 41 insertions(+), 2 deletions(-)
> > > > > > > > > > > > > > > >         create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > index 569ffd50..55e2a8e 100644
> > > > > > > > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > @@ -9,6 +9,7 @@
> > > > > > > > > > > > > > > >         #include <linux/interrupt.h>
> > > > > > > > > > > > > > > >         #include <linux/irq.h>
> > > > > > > > > > > > > > > >         #include <linux/irqdomain.h>
> > > > > > > > > > > > > > > > +#include <linux/mfd/qcom_pm8008.h>
> > > > > > > > > > > > > > > >         #include <linux/module.h>
> > > > > > > > > > > > > > > >         #include <linux/of_device.h>
> > > > > > > > > > > > > > > >         #include <linux/of_platform.h>
> > > > > > > > > > > > > > > > @@ -57,6 +58,7 @@ enum {
> > > > > > > > > > > > > > > >         struct pm8008_data {
> > > > > > > > > > > > > > > >             struct device *dev;
> > > > > > > > > > > > > > > > +    struct regmap *regulators_regmap;
> > > > > > > > > > > > > > > >             int irq;
> > > > > > > > > > > > > > > >             struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > > > > > >         };
> > > > > > > > > > > > > > > > @@ -150,6 +152,12 @@ static struct regmap_config
> > > > > > > > > > > > > > > > qcom_mfd_regmap_cfg = {
> > > > > > > > > > > > > > > >             .max_register    = 0xFFFF,
> > > > > > > > > > > > > > > >         };
> > > > > > > > > > > > > > > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > > > > > > > > > > > > > > +{
> > > > > > > > > > > > > > > > +    return chip->regulators_regmap;
> > > > > > > > > > > > > > > > +}
> > > > > > > > > > > > > > > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > > > > > > Seems like abstraction for the sake of abstraction.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Why not do the dereference inside the regulator driver?
> > > > > > > > > > > > > > To derefer this in the regulator driver, we need to have the
> > > > > > > > > > > > > > pm8008_data
> > > > > > > > > > > > > > struct definition in the qcom_pm8008 header file.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > I think it doesn't look great to have only that structure in
> > > > > > > > > > > > > > header and all
> > > > > > > > > > > > > > other structs and enum in the mfd driver.
> > > > > > > > > > > > > Then why pass 'pm8008_data' at all?
> > > > > > > > > > > > There is one more option, instead of passing the pm8008_data, we could
> > > > > > > > > > > > pass the pdev->dev.parent and get the pm8008 chip data directly in the
> > > > > > > > > > > > pm8008_get_regmap() like below
> > > > > > > > > > > > 
> > > > > > > > > > > > 
> > > > > > > > > > > > struct regmap *pm8008_get_regmap(const struct device *dev)
> > > > > > > > > > > >       {
> > > > > > > > > > > >           const struct pm8008_data *chip = dev_get_drvdata(dev);
> > > > > > > > > > > > 
> > > > > > > > > > > >           return chip->regulators_regmap;
> > > > > > > > > > > > }
> > > > > > > > > > > > EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > > > 
> > > > > > > > > > > > 
> > > > > > > > > > > > By doing this we can avoid having declaration of pm8008_data also in the
> > > > > > > > > > > > header. Please let me know if this looks good.
> > > > > > > > > > > > 
> > > > > > > > > > > Could you please confirm on this?
> > > > > > > > > > > 
> > > > > > > > > > > > > What's preventing you from passing 'regmap'?
> > > > > > > > > > > > I didn't get what you meant here, could you please elaborate a bit?
> > > > > > > > > > Ah yes.  I authored you a patch, but became distracted. Here:
> > > > > > > > > > 
> > > > > > > > > > -----8<--------------------8<-------
> > > > > > > > > > 
> > > > > > > > > > From: Lee Jones <lee.jones@linaro.org>
> > > > > > > > > > 
> > > > > > > > > > mfd: pm8008: Remove driver data structure pm8008_data
> > > > > > > > > > Maintaining a local driver data structure that is never shared
> > > > > > > > > > outside of the core device is an unnecessary complexity.  Half of the
> > > > > > > > > > attributes were not used outside of a single function, one of which
> > > > > > > > > > was not used at all.  The remaining 2 are generic and can be passed
> > > > > > > > > > around as required.
> > > > > > > > > Okay, but we still need to store the regulators_regmap, which is required in
> > > > > > > > > the pm8008 regulator driver. Could we use a global variable for it?
> > > > > > > > Look down ...
> > > > > > > > 
> > > > > > > > > > Signed-off-by: Lee Jones <lee.jones@linaro.org>
> > > > > > > > > > ---
> > > > > > > > > >       drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
> > > > > > > > > >       1 file changed, 20 insertions(+), 33 deletions(-)
> > > > > > > > > > 
> > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > index c472d7f8103c4..4b8ff947762f2 100644
> > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > @@ -54,13 +54,6 @@ enum {
> > > > > > > > > >       #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
> > > > > > > > > > -struct pm8008_data {
> > > > > > > > > > -	struct device *dev;
> > > > > > > > > > -	struct regmap *regmap;
> > > > > > > > > > -	int irq;
> > > > > > > > > > -	struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > -};
> > > > > > > > > > -
> > > > > > > > > >       static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
> > > > > > > > > >       static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
> > > > > > > > > >       static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
> > > > > > > > > > @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
> > > > > > > > > >       	.max_register	= 0xFFFF,
> > > > > > > > > >       };
> > > > > > > > > > -static int pm8008_init(struct pm8008_data *chip)
> > > > > > > > > > +static int pm8008_init(struct regmap *regmap)
> > > > > > > > > >       {
> > > > > > > > > >       	int rc;
> > > > > > > > > > @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
> > > > > > > > > >       	 * This is required to enable the writing of TYPE registers in
> > > > > > > > > >       	 * regmap_irq_sync_unlock().
> > > > > > > > > >       	 */
> > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
> > > > > > > > > > -			 BIT(0));
> > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > >       	if (rc)
> > > > > > > > > >       		return rc;
> > > > > > > > > >       	/* Do the same for GPIO1 and GPIO2 peripherals */
> > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > >       	if (rc)
> > > > > > > > > >       		return rc;
> > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > >       	return rc;
> > > > > > > > > >       }
> > > > > > > > > > -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > > +static int pm8008_probe_irq_peripherals(struct device *dev,
> > > > > > > > > > +					struct regmap *regmap,
> > > > > > > > > >       					int client_irq)
> > > > > > > > > >       {
> > > > > > > > > >       	int rc, i;
> > > > > > > > > >       	struct regmap_irq_type *type;
> > > > > > > > > >       	struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > -	rc = pm8008_init(chip);
> > > > > > > > > > +	rc = pm8008_init(regmap);
> > > > > > > > > >       	if (rc) {
> > > > > > > > > > -		dev_err(chip->dev, "Init failed: %d\n", rc);
> > > > > > > > > > +		dev_err(dev, "Init failed: %d\n", rc);
> > > > > > > > > >       		return rc;
> > > > > > > > > >       	}
> > > > > > > > > > @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > >       				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
> > > > > > > > > >       	}
> > > > > > > > > > -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
> > > > > > > > > > +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
> > > > > > > > > >       			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
> > > > > > > > > >       	if (rc) {
> > > > > > > > > > -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > > > > > +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > > > > >       		return rc;
> > > > > > > > > >       	}
> > > > > > > > > > @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > >       static int pm8008_probe(struct i2c_client *client)
> > > > > > > > > >       {
> > > > > > > > > >       	int rc;
> > > > > > > > > > -	struct pm8008_data *chip;
> > > > > > > > > > -
> > > > > > > > > > -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > > > > > > > > > -	if (!chip)
> > > > > > > > > > -		return -ENOMEM;
> > > > > > > > > > +	struct device *dev;
> > > > > > > > > > +	struct regmap *regmap;
> > > > > > > > > > -	chip->dev = &client->dev;
> > > > > > > > > > -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > > > > > -	if (!chip->regmap)
> > > > > > > > > > +	dev = &client->dev;
> > > > > > > > > > +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > > > > > +	if (!regmap)
> > > > > > > > > >       		return -ENODEV;
> > > > > > > > > > -	i2c_set_clientdata(client, chip);
> > > > > > > > > > +	i2c_set_clientdata(client, regmap);
> > > > > > > > Here ^
> > > > > > > I have added a dummy device and set the client data by passing regmap, see
> > > > > > > below:
> > > > > > > 
> > > > > > > +       regulators_client = i2c_new_dummy_device(client->adapter,
> > > > > > > client->addr + 1);
> > > > > > > +       if (IS_ERR(regulators_client)) {
> > > > > > > +               dev_err(dev, "can't attach client\n");
> > > > > > > +               return PTR_ERR(regulators_client);
> > > > > > > +       }
> > > > > > > +
> > > > > > > +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
> > > > > > > &qcom_mfd_regmap_cfg[1]);
> > > > > > > +       if (!regmap)
> > > > > > > +               return -ENODEV;
> > > > > > > +
> > > > > > > +       i2c_set_clientdata(client, regulators_regmap);
> > > > > > > 
> > > > > > > Now if i try to get this regmap from regulator driver by doing
> > > > > > > 
> > > > > > > struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
> > > > > > > 
> > > > > > > it still gets me the regmap of pm8008@8 device and not the regulator device
> > > > > > > regmap (0x9). Not sure if I'm missing something here.
> > > > > > So you need to pass 2 regmap pointers?
> > > > > > 
> > > > > > If you need to pass more than one item to the child devices, you do
> > > > > > need to use a struct for that.
> > > > > I need to pass only one regmap out of the two, but i am not able to retrieve
> > > > > the correct regmap simply by doing i2c_set_clientdata
> > > > > 
> > > > > probably because we are having all the child nodes under same DT node and
> > > > > thus not able to distinguish based on the dev pointer
> > > > You can only pull out (get) the pointer that you put in (set).
> > > > 
> > > > Unless you over-wrote it later in the thread of execution, you are
> > > > pulling out whatever regulators_regmap happens to be.
> > > > 
> > > > Is qcom_mfd_regmap_cfg[1] definitely the one you want?
> > > 
> > > Yes, I need qcom_mfd_regmap_cfg[1]
> > > 
> > > Pasting code snippet for reference:
> > > 
> > > static struct regmap_config qcom_mfd_regmap_cfg[2] = {
> > >       {
> > > 
> > >           .name = "infra",
> > >           .reg_bits   = 16,
> > >           .val_bits   = 8,
> > >           .max_register   = 0xFFFF,
> > >       },
> > >       {
> > >           .name = "regulators",
> > >           .reg_bits   = 16,
> > >           .val_bits   = 8,
> > >           .max_register   = 0xFFFF,
> > >       },
> > > 
> > > };
> > > 
> > > 
> > > Inside pm8008_probe:
> > > 
> > > 
> > >       regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
> > >       if (!regmap)
> > >           return -ENODEV;
> > > 
> > >       i2c_set_clientdata(client, regmap);
> > > 
> > > 
> > >       regulators_client = i2c_new_dummy_device(client->adapter, client->addr
> > > + 1);
> > >       if (IS_ERR(regulators_client)) {
> > >           dev_err(dev, "can't attach client\n");
> > >           return PTR_ERR(regulators_client);
> > >       }
> > > 
> > >       regulators_regmap = devm_regmap_init_i2c(regulators_client,
> > > &qcom_mfd_regmap_cfg[1]);
> > >       if (!regmap)
> > >           return -ENODEV;
> > > 
> > >       i2c_set_clientdata(regulators_client, regulators_regmap);
> > You can't call this twice.
> > 
> > Doing so with over-write regmap with regulators_regmap.
> > 
> > You said you only needed one?
> > 
> >    "I need to pass only one regmap out of the two, but i am not able to retrieve"
> 
> I thought you asked whether we have to pass two regmaps to the child
> regulator driver.

Yes, that's what I was asking.

So you only need to pass 'regulators_regmap' (derived from
"regulators") right?

In that case, keep:

  i2c_set_clientdata(regulators_client, regulators_regmap);

... and drop:

  i2c_set_clientdata(client, regmap);

> > > In qcom-pm8008-regulator.c I tried to get the regmap using
> > > 
> > > dev_get_regmap(pdev->dev.parent, "regulators");
> > I haven't looked at this API before.  I suggest that this would be
> > used *instead* of passing the regmap pointer via driver_data.
> > 
> > It looks like you're using different devices to init your regmaps;
> > 'client' and 'regulator_client' (derived from client->adapter).
> > 
> > "regulators" is registered using regulators_regmap which was *not*
> > init'ed with pdev->dev.parent (same as client->dev), so trying to
> > dev_get_regmap() with that device pointer will not work.
> 
> Okay, So I will leave the driver as is then?

Right, let's take a step back and try to clarify a few things here.

What is the purpose of the two regmaps that you're creating here?

Where will each of them be used?

Regmaps created in MFD are usually either used only locally, here in
the parent driver or shared amongst *multiple* children.  If that is
not the case for regulators_regmap, which looks suspiciously like it's
only used in the Regulator driver, then why not initialise the regmap
there instead?  Rather than pointlessly creating it here and passing
it via the driver_data pointer.

Once I know more about your intentions, I can help you devise a plan.
Lee Jones July 4, 2022, 12:49 p.m. UTC | #17
On Mon, 04 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 7/1/2022 2:42 PM, Lee Jones wrote:
> > On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > > On 7/1/2022 1:24 PM, Lee Jones wrote:
> > > > On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > 
> > > > > On 6/30/2022 4:04 PM, Lee Jones wrote:
> > > > > > On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > 
> > > > > > > On 6/29/2022 8:48 PM, Lee Jones wrote:
> > > > > > > > On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > 
> > > > > > > > > On 6/28/2022 1:12 PM, Lee Jones wrote:
> > > > > > > > > > On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > 
> > > > > > > > > > > On 6/27/2022 1:11 PM, Lee Jones wrote:
> > > > > > > > > > > > On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > 
> > > > > > > > > > > > > Hi Lee,
> > > > > > > > > > > > > 
> > > > > > > > > > > > > 
> > > > > > > > > > > > > On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > > > On 6/20/2022 1:50 PM, Lee Jones wrote:
> > > > > > > > > > > > > > > On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > On 6/17/2022 2:27 AM, Lee Jones wrote:
> > > > > > > > > > > > > > > > > On Tue, 14 Jun 2022, Satya Priya wrote:
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > > > > > > > > > > > > > > > > client present at a different address space, instead of
> > > > > > > > > > > > > > > > > > defining a separate DT node. This avoids calling the probe
> > > > > > > > > > > > > > > > > > twice for the same chip, once for each client pm8008-infra
> > > > > > > > > > > > > > > > > > and pm8008-regulator.
> > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > As a part of this define pm8008_regmap_init() to do regmap
> > > > > > > > > > > > > > > > > > init for both the clients and define pm8008_get_regmap() to
> > > > > > > > > > > > > > > > > > pass the regmap to the regulator driver.
> > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > Signed-off-by: Satya Priya<quic_c_skakit@quicinc.com>
> > > > > > > > > > > > > > > > > > Reviewed-by: Stephen Boyd<swboyd@chromium.org>
> > > > > > > > > > > > > > > > > > ---
> > > > > > > > > > > > > > > > > > Changes in V15:
> > > > > > > > > > > > > > > > > >          - None.
> > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > Changes in V14:
> > > > > > > > > > > > > > > > > >          - None.
> > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > Changes in V13:
> > > > > > > > > > > > > > > > > >          - None.
> > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > >          drivers/mfd/qcom-pm8008.c       | 34
> > > > > > > > > > > > > > > > > > ++++++++++++++++++++++++++++++++--
> > > > > > > > > > > > > > > > > >          include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > > > > > > > > > > > > > > > > >          2 files changed, 41 insertions(+), 2 deletions(-)
> > > > > > > > > > > > > > > > > >          create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > > > index 569ffd50..55e2a8e 100644
> > > > > > > > > > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > > > @@ -9,6 +9,7 @@
> > > > > > > > > > > > > > > > > >          #include <linux/interrupt.h>
> > > > > > > > > > > > > > > > > >          #include <linux/irq.h>
> > > > > > > > > > > > > > > > > >          #include <linux/irqdomain.h>
> > > > > > > > > > > > > > > > > > +#include <linux/mfd/qcom_pm8008.h>
> > > > > > > > > > > > > > > > > >          #include <linux/module.h>
> > > > > > > > > > > > > > > > > >          #include <linux/of_device.h>
> > > > > > > > > > > > > > > > > >          #include <linux/of_platform.h>
> > > > > > > > > > > > > > > > > > @@ -57,6 +58,7 @@ enum {
> > > > > > > > > > > > > > > > > >          struct pm8008_data {
> > > > > > > > > > > > > > > > > >              struct device *dev;
> > > > > > > > > > > > > > > > > > +    struct regmap *regulators_regmap;
> > > > > > > > > > > > > > > > > >              int irq;
> > > > > > > > > > > > > > > > > >              struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > > > > > > > >          };
> > > > > > > > > > > > > > > > > > @@ -150,6 +152,12 @@ static struct regmap_config
> > > > > > > > > > > > > > > > > > qcom_mfd_regmap_cfg = {
> > > > > > > > > > > > > > > > > >              .max_register    = 0xFFFF,
> > > > > > > > > > > > > > > > > >          };
> > > > > > > > > > > > > > > > > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > > > > > > > > > > > > > > > > +{
> > > > > > > > > > > > > > > > > > +    return chip->regulators_regmap;
> > > > > > > > > > > > > > > > > > +}
> > > > > > > > > > > > > > > > > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > > > > > > > > Seems like abstraction for the sake of abstraction.
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > Why not do the dereference inside the regulator driver?
> > > > > > > > > > > > > > > > To derefer this in the regulator driver, we need to have the
> > > > > > > > > > > > > > > > pm8008_data
> > > > > > > > > > > > > > > > struct definition in the qcom_pm8008 header file.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > I think it doesn't look great to have only that structure in
> > > > > > > > > > > > > > > > header and all
> > > > > > > > > > > > > > > > other structs and enum in the mfd driver.
> > > > > > > > > > > > > > > Then why pass 'pm8008_data' at all?
> > > > > > > > > > > > > > There is one more option, instead of passing the pm8008_data, we could
> > > > > > > > > > > > > > pass the pdev->dev.parent and get the pm8008 chip data directly in the
> > > > > > > > > > > > > > pm8008_get_regmap() like below
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > struct regmap *pm8008_get_regmap(const struct device *dev)
> > > > > > > > > > > > > >        {
> > > > > > > > > > > > > >            const struct pm8008_data *chip = dev_get_drvdata(dev);
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > >            return chip->regulators_regmap;
> > > > > > > > > > > > > > }
> > > > > > > > > > > > > > EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > By doing this we can avoid having declaration of pm8008_data also in the
> > > > > > > > > > > > > > header. Please let me know if this looks good.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > Could you please confirm on this?
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > > What's preventing you from passing 'regmap'?
> > > > > > > > > > > > > > I didn't get what you meant here, could you please elaborate a bit?
> > > > > > > > > > > > Ah yes.  I authored you a patch, but became distracted. Here:
> > > > > > > > > > > > 
> > > > > > > > > > > > -----8<--------------------8<-------
> > > > > > > > > > > > 
> > > > > > > > > > > > From: Lee Jones<lee.jones@linaro.org>
> > > > > > > > > > > > 
> > > > > > > > > > > > mfd: pm8008: Remove driver data structure pm8008_data
> > > > > > > > > > > > Maintaining a local driver data structure that is never shared
> > > > > > > > > > > > outside of the core device is an unnecessary complexity.  Half of the
> > > > > > > > > > > > attributes were not used outside of a single function, one of which
> > > > > > > > > > > > was not used at all.  The remaining 2 are generic and can be passed
> > > > > > > > > > > > around as required.
> > > > > > > > > > > Okay, but we still need to store the regulators_regmap, which is required in
> > > > > > > > > > > the pm8008 regulator driver. Could we use a global variable for it?
> > > > > > > > > > Look down ...
> > > > > > > > > > 
> > > > > > > > > > > > Signed-off-by: Lee Jones<lee.jones@linaro.org>
> > > > > > > > > > > > ---
> > > > > > > > > > > >        drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
> > > > > > > > > > > >        1 file changed, 20 insertions(+), 33 deletions(-)
> > > > > > > > > > > > 
> > > > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > index c472d7f8103c4..4b8ff947762f2 100644
> > > > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > @@ -54,13 +54,6 @@ enum {
> > > > > > > > > > > >        #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
> > > > > > > > > > > > -struct pm8008_data {
> > > > > > > > > > > > -	struct device *dev;
> > > > > > > > > > > > -	struct regmap *regmap;
> > > > > > > > > > > > -	int irq;
> > > > > > > > > > > > -	struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > > -};
> > > > > > > > > > > > -
> > > > > > > > > > > >        static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
> > > > > > > > > > > >        static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
> > > > > > > > > > > >        static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
> > > > > > > > > > > > @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
> > > > > > > > > > > >        	.max_register	= 0xFFFF,
> > > > > > > > > > > >        };
> > > > > > > > > > > > -static int pm8008_init(struct pm8008_data *chip)
> > > > > > > > > > > > +static int pm8008_init(struct regmap *regmap)
> > > > > > > > > > > >        {
> > > > > > > > > > > >        	int rc;
> > > > > > > > > > > > @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
> > > > > > > > > > > >        	 * This is required to enable the writing of TYPE registers in
> > > > > > > > > > > >        	 * regmap_irq_sync_unlock().
> > > > > > > > > > > >        	 */
> > > > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > > > -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
> > > > > > > > > > > > -			 BIT(0));
> > > > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > >        	if (rc)
> > > > > > > > > > > >        		return rc;
> > > > > > > > > > > >        	/* Do the same for GPIO1 and GPIO2 peripherals */
> > > > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > > > -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > >        	if (rc)
> > > > > > > > > > > >        		return rc;
> > > > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > > > -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > >        	return rc;
> > > > > > > > > > > >        }
> > > > > > > > > > > > -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > > > > +static int pm8008_probe_irq_peripherals(struct device *dev,
> > > > > > > > > > > > +					struct regmap *regmap,
> > > > > > > > > > > >        					int client_irq)
> > > > > > > > > > > >        {
> > > > > > > > > > > >        	int rc, i;
> > > > > > > > > > > >        	struct regmap_irq_type *type;
> > > > > > > > > > > >        	struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > > -	rc = pm8008_init(chip);
> > > > > > > > > > > > +	rc = pm8008_init(regmap);
> > > > > > > > > > > >        	if (rc) {
> > > > > > > > > > > > -		dev_err(chip->dev, "Init failed: %d\n", rc);
> > > > > > > > > > > > +		dev_err(dev, "Init failed: %d\n", rc);
> > > > > > > > > > > >        		return rc;
> > > > > > > > > > > >        	}
> > > > > > > > > > > > @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > > > >        				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
> > > > > > > > > > > >        	}
> > > > > > > > > > > > -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
> > > > > > > > > > > > +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
> > > > > > > > > > > >        			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
> > > > > > > > > > > >        	if (rc) {
> > > > > > > > > > > > -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > > > > > > > +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > > > > > > >        		return rc;
> > > > > > > > > > > >        	}
> > > > > > > > > > > > @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > > > >        static int pm8008_probe(struct i2c_client *client)
> > > > > > > > > > > >        {
> > > > > > > > > > > >        	int rc;
> > > > > > > > > > > > -	struct pm8008_data *chip;
> > > > > > > > > > > > -
> > > > > > > > > > > > -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > > > > > > > > > > > -	if (!chip)
> > > > > > > > > > > > -		return -ENOMEM;
> > > > > > > > > > > > +	struct device *dev;
> > > > > > > > > > > > +	struct regmap *regmap;
> > > > > > > > > > > > -	chip->dev = &client->dev;
> > > > > > > > > > > > -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > > > > > > > -	if (!chip->regmap)
> > > > > > > > > > > > +	dev = &client->dev;
> > > > > > > > > > > > +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > > > > > > > +	if (!regmap)
> > > > > > > > > > > >        		return -ENODEV;
> > > > > > > > > > > > -	i2c_set_clientdata(client, chip);
> > > > > > > > > > > > +	i2c_set_clientdata(client, regmap);
> > > > > > > > > > Here ^
> > > > > > > > > I have added a dummy device and set the client data by passing regmap, see
> > > > > > > > > below:
> > > > > > > > > 
> > > > > > > > > +       regulators_client = i2c_new_dummy_device(client->adapter,
> > > > > > > > > client->addr + 1);
> > > > > > > > > +       if (IS_ERR(regulators_client)) {
> > > > > > > > > +               dev_err(dev, "can't attach client\n");
> > > > > > > > > +               return PTR_ERR(regulators_client);
> > > > > > > > > +       }
> > > > > > > > > +
> > > > > > > > > +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
> > > > > > > > > &qcom_mfd_regmap_cfg[1]);
> > > > > > > > > +       if (!regmap)
> > > > > > > > > +               return -ENODEV;
> > > > > > > > > +
> > > > > > > > > +       i2c_set_clientdata(client, regulators_regmap);
> > > > > > > > > 
> > > > > > > > > Now if i try to get this regmap from regulator driver by doing
> > > > > > > > > 
> > > > > > > > > struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
> > > > > > > > > 
> > > > > > > > > it still gets me the regmap of pm8008@8 device and not the regulator device
> > > > > > > > > regmap (0x9). Not sure if I'm missing something here.
> > > > > > > > So you need to pass 2 regmap pointers?
> > > > > > > > 
> > > > > > > > If you need to pass more than one item to the child devices, you do
> > > > > > > > need to use a struct for that.
> > > > > > > I need to pass only one regmap out of the two, but i am not able to retrieve
> > > > > > > the correct regmap simply by doing i2c_set_clientdata
> > > > > > > 
> > > > > > > probably because we are having all the child nodes under same DT node and
> > > > > > > thus not able to distinguish based on the dev pointer
> > > > > > You can only pull out (get) the pointer that you put in (set).
> > > > > > 
> > > > > > Unless you over-wrote it later in the thread of execution, you are
> > > > > > pulling out whatever regulators_regmap happens to be.
> > > > > > 
> > > > > > Is qcom_mfd_regmap_cfg[1] definitely the one you want?
> > > > > Yes, I need qcom_mfd_regmap_cfg[1]
> > > > > 
> > > > > Pasting code snippet for reference:
> > > > > 
> > > > > static struct regmap_config qcom_mfd_regmap_cfg[2] = {
> > > > >        {
> > > > > 
> > > > >            .name = "infra",
> > > > >            .reg_bits   = 16,
> > > > >            .val_bits   = 8,
> > > > >            .max_register   = 0xFFFF,
> > > > >        },
> > > > >        {
> > > > >            .name = "regulators",
> > > > >            .reg_bits   = 16,
> > > > >            .val_bits   = 8,
> > > > >            .max_register   = 0xFFFF,
> > > > >        },
> > > > > 
> > > > > };
> > > > > 
> > > > > 
> > > > > Inside pm8008_probe:
> > > > > 
> > > > > 
> > > > >        regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
> > > > >        if (!regmap)
> > > > >            return -ENODEV;
> > > > > 
> > > > >        i2c_set_clientdata(client, regmap);
> > > > > 
> > > > > 
> > > > >        regulators_client = i2c_new_dummy_device(client->adapter, client->addr
> > > > > + 1);
> > > > >        if (IS_ERR(regulators_client)) {
> > > > >            dev_err(dev, "can't attach client\n");
> > > > >            return PTR_ERR(regulators_client);
> > > > >        }
> > > > > 
> > > > >        regulators_regmap = devm_regmap_init_i2c(regulators_client,
> > > > > &qcom_mfd_regmap_cfg[1]);
> > > > >        if (!regmap)
> > > > >            return -ENODEV;
> > > > > 
> > > > >        i2c_set_clientdata(regulators_client, regulators_regmap);
> > > > You can't call this twice.
> > > > 
> > > > Doing so with over-write regmap with regulators_regmap.
> > > > 
> > > > You said you only needed one?
> > > > 
> > > >     "I need to pass only one regmap out of the two, but i am not able to retrieve"
> > > I thought you asked whether we have to pass two regmaps to the child
> > > regulator driver.
> > Yes, that's what I was asking.
> > 
> > So you only need to pass 'regulators_regmap' (derived from
> > "regulators") right?
> 
> 
> Yes
> 
> 
> > In that case, keep:
> > 
> >    i2c_set_clientdata(regulators_client, regulators_regmap);
> > 
> > ... and drop:
> > 
> >    i2c_set_clientdata(client, regmap);
> 
> 
> Dropping this did not help, it says regmap is NULL. Can we drop this? we

If it's NULL coming out, it was NULL going in.

Does it get checked before setting it?

Are you getting it from the right device?

> might still need it for other child peripherals like gpios?
> 
> Also, setting the data through different clients would still overwrite the
> data? I thought it would be written to respective client->dev.

It does, but you are fetching it back out from the parent, right?

  const struct pm8008_data *chip = dev_get_drvdata(pdev->dev.parent);

Which is only one device.

If you want to set the child's data, then that is usually accomplished
using platform_data (you can do this using the MFD API - see struct
mfd_cell), not driver_data.

> > > > > In qcom-pm8008-regulator.c I tried to get the regmap using
> > > > > 
> > > > > dev_get_regmap(pdev->dev.parent, "regulators");
> > > > I haven't looked at this API before.  I suggest that this would be
> > > > used *instead* of passing the regmap pointer via driver_data.
> > > > 
> > > > It looks like you're using different devices to init your regmaps;
> > > > 'client' and 'regulator_client' (derived from client->adapter).
> > > > 
> > > > "regulators" is registered using regulators_regmap which was *not*
> > > > init'ed with pdev->dev.parent (same as client->dev), so trying to
> > > > dev_get_regmap() with that device pointer will not work.
> > > Okay, So I will leave the driver as is then?
> > Right, let's take a step back and try to clarify a few things here.
> > 
> > What is the purpose of the two regmaps that you're creating here?
> 
> The pm8008 chip is an I2C based pmic which has 2 address spaces 0x8 and 0x9.
> 
> > Where will each of them be used?
> 
> Under the 0x8 address space peripherals like gpio, temp-alarm etc will be
> present and under the 0x9 regulators are present.
>
> > Regmaps created in MFD are usually either used only locally, here in
> > the parent driver or shared amongst *multiple* children.  If that is
> > not the case for regulators_regmap, which looks suspiciously like it's
> > only used in the Regulator driver, then why not initialise the regmap
> > there instead?  Rather than pointlessly creating it here and passing
> > it via the driver_data pointer.
> 
> 
> Initially we implemented below design
> 
> [V4,5/6] arm64: dts: qcom: pm8008: Add base dts file - Patchwork
> (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1637314953-4215-6-git-send-email-quic_c_skakit@quicinc.com/>
> 
> As per Mark's suggestions I've dropped the compatible for regulator driver
> and registered the regulators through mfd driver.

If the regmap is _only_ used in the regulator driver, it should be
initialised there.

I suggest you move all of this regmap set-up into the Regulator
driver and have done with it.

> [V4,2/6] dt-bindings: regulator: Add pm8008 regulator bindings - Patchwork
> (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1637314953-4215-3-git-send-email-quic_c_skakit@quicinc.com/>
> 
> Later as per the discussions here [1] and [2], I've added this patch to use
> i2c_new_dummy_device() API to register the regulator devices as child
> devices to pm8008@8 node and made the DT changes suggested.
> 
> [1] [V9,4/6] regulator: Add a regulator driver for the PM8008 PMIC -
> Patchwork (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1649166633-25872-5-git-send-email-quic_c_skakit@quicinc.com/>
> 
> [2] [V10,7/9] regulator: Add a regulator driver for the PM8008 PMIC -
> Patchwork (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1649939418-19861-8-git-send-email-quic_c_skakit@quicinc.com/>
> 
> To implement this approach, I had to initialize the regulator_regmap in the
> mfd probe and pass it to the regulator driver either through driver data
> struct or a global variable. Other mfd drivers with similar implementation
> are following the same. please let me know if you have further queries
> regarding this.

It's fine for the regulator driver to be registered from here, but the
child should do its own regmap initialisation.

> > Once I know more about your intentions, I can help you devise a plan.
Satya Priya Kakitapalli (Temp) July 4, 2022, 12:59 p.m. UTC | #18
On 7/4/2022 6:19 PM, Lee Jones wrote:
> On Mon, 04 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> On 7/1/2022 2:42 PM, Lee Jones wrote:
>>> On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>
>>>> On 7/1/2022 1:24 PM, Lee Jones wrote:
>>>>> On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>
>>>>>> On 6/30/2022 4:04 PM, Lee Jones wrote:
>>>>>>> On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>
>>>>>>>> On 6/29/2022 8:48 PM, Lee Jones wrote:
>>>>>>>>> On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>
>>>>>>>>>> On 6/28/2022 1:12 PM, Lee Jones wrote:
>>>>>>>>>>> On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>
>>>>>>>>>>>> On 6/27/2022 1:11 PM, Lee Jones wrote:
>>>>>>>>>>>>> On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi Lee,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>>> On 6/20/2022 1:50 PM, Lee Jones wrote:
>>>>>>>>>>>>>>>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>>>>>>>>>>>>>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>>>>>>>>>>>>>>>> client present at a different address space, instead of
>>>>>>>>>>>>>>>>>>> defining a separate DT node. This avoids calling the probe
>>>>>>>>>>>>>>>>>>> twice for the same chip, once for each client pm8008-infra
>>>>>>>>>>>>>>>>>>> and pm8008-regulator.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>>>>>>>>>>>>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>>>>>>>>>>>>>>>> pass the regmap to the regulator driver.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Signed-off-by: Satya Priya<quic_c_skakit@quicinc.com>
>>>>>>>>>>>>>>>>>>> Reviewed-by: Stephen Boyd<swboyd@chromium.org>
>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>> Changes in V15:
>>>>>>>>>>>>>>>>>>>           - None.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Changes in V14:
>>>>>>>>>>>>>>>>>>>           - None.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Changes in V13:
>>>>>>>>>>>>>>>>>>>           - None.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>           drivers/mfd/qcom-pm8008.c       | 34
>>>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++--
>>>>>>>>>>>>>>>>>>>           include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>>>>>>>>>>>>>>>           2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>>>>>>>>>>>>>>>           create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>> index 569ffd50..55e2a8e 100644
>>>>>>>>>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>> @@ -9,6 +9,7 @@
>>>>>>>>>>>>>>>>>>>           #include <linux/interrupt.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/irq.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/irqdomain.h>
>>>>>>>>>>>>>>>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/module.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/of_device.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/of_platform.h>
>>>>>>>>>>>>>>>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>>>>>>>>>>>>>>>           struct pm8008_data {
>>>>>>>>>>>>>>>>>>>               struct device *dev;
>>>>>>>>>>>>>>>>>>> +    struct regmap *regulators_regmap;
>>>>>>>>>>>>>>>>>>>               int irq;
>>>>>>>>>>>>>>>>>>>               struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>>>>>>>>           };
>>>>>>>>>>>>>>>>>>> @@ -150,6 +152,12 @@ static struct regmap_config
>>>>>>>>>>>>>>>>>>> qcom_mfd_regmap_cfg = {
>>>>>>>>>>>>>>>>>>>               .max_register    = 0xFFFF,
>>>>>>>>>>>>>>>>>>>           };
>>>>>>>>>>>>>>>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>>>> +    return chip->regulators_regmap;
>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>>>>>>>> Seems like abstraction for the sake of abstraction.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Why not do the dereference inside the regulator driver?
>>>>>>>>>>>>>>>>> To derefer this in the regulator driver, we need to have the
>>>>>>>>>>>>>>>>> pm8008_data
>>>>>>>>>>>>>>>>> struct definition in the qcom_pm8008 header file.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> I think it doesn't look great to have only that structure in
>>>>>>>>>>>>>>>>> header and all
>>>>>>>>>>>>>>>>> other structs and enum in the mfd driver.
>>>>>>>>>>>>>>>> Then why pass 'pm8008_data' at all?
>>>>>>>>>>>>>>> There is one more option, instead of passing the pm8008_data, we could
>>>>>>>>>>>>>>> pass the pdev->dev.parent and get the pm8008 chip data directly in the
>>>>>>>>>>>>>>> pm8008_get_regmap() like below
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> struct regmap *pm8008_get_regmap(const struct device *dev)
>>>>>>>>>>>>>>>         {
>>>>>>>>>>>>>>>             const struct pm8008_data *chip = dev_get_drvdata(dev);
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>             return chip->regulators_regmap;
>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> By doing this we can avoid having declaration of pm8008_data also in the
>>>>>>>>>>>>>>> header. Please let me know if this looks good.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Could you please confirm on this?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> What's preventing you from passing 'regmap'?
>>>>>>>>>>>>>>> I didn't get what you meant here, could you please elaborate a bit?
>>>>>>>>>>>>> Ah yes.  I authored you a patch, but became distracted. Here:
>>>>>>>>>>>>>
>>>>>>>>>>>>> -----8<--------------------8<-------
>>>>>>>>>>>>>
>>>>>>>>>>>>> From: Lee Jones<lee.jones@linaro.org>
>>>>>>>>>>>>>
>>>>>>>>>>>>> mfd: pm8008: Remove driver data structure pm8008_data
>>>>>>>>>>>>> Maintaining a local driver data structure that is never shared
>>>>>>>>>>>>> outside of the core device is an unnecessary complexity.  Half of the
>>>>>>>>>>>>> attributes were not used outside of a single function, one of which
>>>>>>>>>>>>> was not used at all.  The remaining 2 are generic and can be passed
>>>>>>>>>>>>> around as required.
>>>>>>>>>>>> Okay, but we still need to store the regulators_regmap, which is required in
>>>>>>>>>>>> the pm8008 regulator driver. Could we use a global variable for it?
>>>>>>>>>>> Look down ...
>>>>>>>>>>>
>>>>>>>>>>>>> Signed-off-by: Lee Jones<lee.jones@linaro.org>
>>>>>>>>>>>>> ---
>>>>>>>>>>>>>         drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
>>>>>>>>>>>>>         1 file changed, 20 insertions(+), 33 deletions(-)
>>>>>>>>>>>>>
>>>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> index c472d7f8103c4..4b8ff947762f2 100644
>>>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> @@ -54,13 +54,6 @@ enum {
>>>>>>>>>>>>>         #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
>>>>>>>>>>>>> -struct pm8008_data {
>>>>>>>>>>>>> -	struct device *dev;
>>>>>>>>>>>>> -	struct regmap *regmap;
>>>>>>>>>>>>> -	int irq;
>>>>>>>>>>>>> -	struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>> -};
>>>>>>>>>>>>> -
>>>>>>>>>>>>>         static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
>>>>>>>>>>>>>         static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
>>>>>>>>>>>>>         static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
>>>>>>>>>>>>> @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>>>>>>>>>>>>         	.max_register	= 0xFFFF,
>>>>>>>>>>>>>         };
>>>>>>>>>>>>> -static int pm8008_init(struct pm8008_data *chip)
>>>>>>>>>>>>> +static int pm8008_init(struct regmap *regmap)
>>>>>>>>>>>>>         {
>>>>>>>>>>>>>         	int rc;
>>>>>>>>>>>>> @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
>>>>>>>>>>>>>         	 * This is required to enable the writing of TYPE registers in
>>>>>>>>>>>>>         	 * regmap_irq_sync_unlock().
>>>>>>>>>>>>>         	 */
>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>> -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
>>>>>>>>>>>>> -			 BIT(0));
>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>         	if (rc)
>>>>>>>>>>>>>         		return rc;
>>>>>>>>>>>>>         	/* Do the same for GPIO1 and GPIO2 peripherals */
>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>> -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>         	if (rc)
>>>>>>>>>>>>>         		return rc;
>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>> -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>         	return rc;
>>>>>>>>>>>>>         }
>>>>>>>>>>>>> -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>> +static int pm8008_probe_irq_peripherals(struct device *dev,
>>>>>>>>>>>>> +					struct regmap *regmap,
>>>>>>>>>>>>>         					int client_irq)
>>>>>>>>>>>>>         {
>>>>>>>>>>>>>         	int rc, i;
>>>>>>>>>>>>>         	struct regmap_irq_type *type;
>>>>>>>>>>>>>         	struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>> -	rc = pm8008_init(chip);
>>>>>>>>>>>>> +	rc = pm8008_init(regmap);
>>>>>>>>>>>>>         	if (rc) {
>>>>>>>>>>>>> -		dev_err(chip->dev, "Init failed: %d\n", rc);
>>>>>>>>>>>>> +		dev_err(dev, "Init failed: %d\n", rc);
>>>>>>>>>>>>>         		return rc;
>>>>>>>>>>>>>         	}
>>>>>>>>>>>>> @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>>         				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
>>>>>>>>>>>>>         	}
>>>>>>>>>>>>> -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
>>>>>>>>>>>>> +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
>>>>>>>>>>>>>         			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
>>>>>>>>>>>>>         	if (rc) {
>>>>>>>>>>>>> -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>>>>>>> +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>>>>>>>         		return rc;
>>>>>>>>>>>>>         	}
>>>>>>>>>>>>> @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>>         static int pm8008_probe(struct i2c_client *client)
>>>>>>>>>>>>>         {
>>>>>>>>>>>>>         	int rc;
>>>>>>>>>>>>> -	struct pm8008_data *chip;
>>>>>>>>>>>>> -
>>>>>>>>>>>>> -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
>>>>>>>>>>>>> -	if (!chip)
>>>>>>>>>>>>> -		return -ENOMEM;
>>>>>>>>>>>>> +	struct device *dev;
>>>>>>>>>>>>> +	struct regmap *regmap;
>>>>>>>>>>>>> -	chip->dev = &client->dev;
>>>>>>>>>>>>> -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>>>>>>>> -	if (!chip->regmap)
>>>>>>>>>>>>> +	dev = &client->dev;
>>>>>>>>>>>>> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>>>>>>>> +	if (!regmap)
>>>>>>>>>>>>>         		return -ENODEV;
>>>>>>>>>>>>> -	i2c_set_clientdata(client, chip);
>>>>>>>>>>>>> +	i2c_set_clientdata(client, regmap);
>>>>>>>>>>> Here ^
>>>>>>>>>> I have added a dummy device and set the client data by passing regmap, see
>>>>>>>>>> below:
>>>>>>>>>>
>>>>>>>>>> +       regulators_client = i2c_new_dummy_device(client->adapter,
>>>>>>>>>> client->addr + 1);
>>>>>>>>>> +       if (IS_ERR(regulators_client)) {
>>>>>>>>>> +               dev_err(dev, "can't attach client\n");
>>>>>>>>>> +               return PTR_ERR(regulators_client);
>>>>>>>>>> +       }
>>>>>>>>>> +
>>>>>>>>>> +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
>>>>>>>>>> &qcom_mfd_regmap_cfg[1]);
>>>>>>>>>> +       if (!regmap)
>>>>>>>>>> +               return -ENODEV;
>>>>>>>>>> +
>>>>>>>>>> +       i2c_set_clientdata(client, regulators_regmap);
>>>>>>>>>>
>>>>>>>>>> Now if i try to get this regmap from regulator driver by doing
>>>>>>>>>>
>>>>>>>>>> struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
>>>>>>>>>>
>>>>>>>>>> it still gets me the regmap of pm8008@8 device and not the regulator device
>>>>>>>>>> regmap (0x9). Not sure if I'm missing something here.
>>>>>>>>> So you need to pass 2 regmap pointers?
>>>>>>>>>
>>>>>>>>> If you need to pass more than one item to the child devices, you do
>>>>>>>>> need to use a struct for that.
>>>>>>>> I need to pass only one regmap out of the two, but i am not able to retrieve
>>>>>>>> the correct regmap simply by doing i2c_set_clientdata
>>>>>>>>
>>>>>>>> probably because we are having all the child nodes under same DT node and
>>>>>>>> thus not able to distinguish based on the dev pointer
>>>>>>> You can only pull out (get) the pointer that you put in (set).
>>>>>>>
>>>>>>> Unless you over-wrote it later in the thread of execution, you are
>>>>>>> pulling out whatever regulators_regmap happens to be.
>>>>>>>
>>>>>>> Is qcom_mfd_regmap_cfg[1] definitely the one you want?
>>>>>> Yes, I need qcom_mfd_regmap_cfg[1]
>>>>>>
>>>>>> Pasting code snippet for reference:
>>>>>>
>>>>>> static struct regmap_config qcom_mfd_regmap_cfg[2] = {
>>>>>>         {
>>>>>>
>>>>>>             .name = "infra",
>>>>>>             .reg_bits   = 16,
>>>>>>             .val_bits   = 8,
>>>>>>             .max_register   = 0xFFFF,
>>>>>>         },
>>>>>>         {
>>>>>>             .name = "regulators",
>>>>>>             .reg_bits   = 16,
>>>>>>             .val_bits   = 8,
>>>>>>             .max_register   = 0xFFFF,
>>>>>>         },
>>>>>>
>>>>>> };
>>>>>>
>>>>>>
>>>>>> Inside pm8008_probe:
>>>>>>
>>>>>>
>>>>>>         regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
>>>>>>         if (!regmap)
>>>>>>             return -ENODEV;
>>>>>>
>>>>>>         i2c_set_clientdata(client, regmap);
>>>>>>
>>>>>>
>>>>>>         regulators_client = i2c_new_dummy_device(client->adapter, client->addr
>>>>>> + 1);
>>>>>>         if (IS_ERR(regulators_client)) {
>>>>>>             dev_err(dev, "can't attach client\n");
>>>>>>             return PTR_ERR(regulators_client);
>>>>>>         }
>>>>>>
>>>>>>         regulators_regmap = devm_regmap_init_i2c(regulators_client,
>>>>>> &qcom_mfd_regmap_cfg[1]);
>>>>>>         if (!regmap)
>>>>>>             return -ENODEV;
>>>>>>
>>>>>>         i2c_set_clientdata(regulators_client, regulators_regmap);
>>>>> You can't call this twice.
>>>>>
>>>>> Doing so with over-write regmap with regulators_regmap.
>>>>>
>>>>> You said you only needed one?
>>>>>
>>>>>      "I need to pass only one regmap out of the two, but i am not able to retrieve"
>>>> I thought you asked whether we have to pass two regmaps to the child
>>>> regulator driver.
>>> Yes, that's what I was asking.
>>>
>>> So you only need to pass 'regulators_regmap' (derived from
>>> "regulators") right?
>>
>> Yes
>>
>>
>>> In that case, keep:
>>>
>>>     i2c_set_clientdata(regulators_client, regulators_regmap);
>>>
>>> ... and drop:
>>>
>>>     i2c_set_clientdata(client, regmap);
>>
>> Dropping this did not help, it says regmap is NULL. Can we drop this? we
> If it's NULL coming out, it was NULL going in.
>
> Does it get checked before setting it?
>
> Are you getting it from the right device?
>
>> might still need it for other child peripherals like gpios?
>>
>> Also, setting the data through different clients would still overwrite the
>> data? I thought it would be written to respective client->dev.
> It does, but you are fetching it back out from the parent, right?
>
>    const struct pm8008_data *chip = dev_get_drvdata(pdev->dev.parent);
>
> Which is only one device.
>
> If you want to set the child's data, then that is usually accomplished
> using platform_data (you can do this using the MFD API - see struct
> mfd_cell), not driver_data.
>
>>>>>> In qcom-pm8008-regulator.c I tried to get the regmap using
>>>>>>
>>>>>> dev_get_regmap(pdev->dev.parent, "regulators");
>>>>> I haven't looked at this API before.  I suggest that this would be
>>>>> used *instead* of passing the regmap pointer via driver_data.
>>>>>
>>>>> It looks like you're using different devices to init your regmaps;
>>>>> 'client' and 'regulator_client' (derived from client->adapter).
>>>>>
>>>>> "regulators" is registered using regulators_regmap which was *not*
>>>>> init'ed with pdev->dev.parent (same as client->dev), so trying to
>>>>> dev_get_regmap() with that device pointer will not work.
>>>> Okay, So I will leave the driver as is then?
>>> Right, let's take a step back and try to clarify a few things here.
>>>
>>> What is the purpose of the two regmaps that you're creating here?
>> The pm8008 chip is an I2C based pmic which has 2 address spaces 0x8 and 0x9.
>>
>>> Where will each of them be used?
>> Under the 0x8 address space peripherals like gpio, temp-alarm etc will be
>> present and under the 0x9 regulators are present.
>>
>>> Regmaps created in MFD are usually either used only locally, here in
>>> the parent driver or shared amongst *multiple* children.  If that is
>>> not the case for regulators_regmap, which looks suspiciously like it's
>>> only used in the Regulator driver, then why not initialise the regmap
>>> there instead?  Rather than pointlessly creating it here and passing
>>> it via the driver_data pointer.
>>
>> Initially we implemented below design
>>
>> [V4,5/6] arm64: dts: qcom: pm8008: Add base dts file - Patchwork
>> (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1637314953-4215-6-git-send-email-quic_c_skakit@quicinc.com/>
>>
>> As per Mark's suggestions I've dropped the compatible for regulator driver
>> and registered the regulators through mfd driver.
> If the regmap is _only_ used in the regulator driver, it should be
> initialised there.
>
> I suggest you move all of this regmap set-up into the Regulator
> driver and have done with it.
>
>> [V4,2/6] dt-bindings: regulator: Add pm8008 regulator bindings - Patchwork
>> (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1637314953-4215-3-git-send-email-quic_c_skakit@quicinc.com/>
>>
>> Later as per the discussions here [1] and [2], I've added this patch to use
>> i2c_new_dummy_device() API to register the regulator devices as child
>> devices to pm8008@8 node and made the DT changes suggested.
>>
>> [1] [V9,4/6] regulator: Add a regulator driver for the PM8008 PMIC -
>> Patchwork (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1649166633-25872-5-git-send-email-quic_c_skakit@quicinc.com/>
>>
>> [2] [V10,7/9] regulator: Add a regulator driver for the PM8008 PMIC -
>> Patchwork (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1649939418-19861-8-git-send-email-quic_c_skakit@quicinc.com/>
>>
>> To implement this approach, I had to initialize the regulator_regmap in the
>> mfd probe and pass it to the regulator driver either through driver data
>> struct or a global variable. Other mfd drivers with similar implementation
>> are following the same. please let me know if you have further queries
>> regarding this.
> It's fine for the regulator driver to be registered from here, but the
> child should do its own regmap initialisation.


Okay, but to initialize the regmap in regulator driver, I will have to 
pass the regulator_client through the pm8008_data struct right?


>>> Once I know more about your intentions, I can help you devise a plan.
Satya Priya Kakitapalli (Temp) July 11, 2022, 10:31 a.m. UTC | #19
On 7/4/2022 6:19 PM, Lee Jones wrote:
> On Mon, 04 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> On 7/1/2022 2:42 PM, Lee Jones wrote:
>>> On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>
>>>> On 7/1/2022 1:24 PM, Lee Jones wrote:
>>>>> On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>
>>>>>> On 6/30/2022 4:04 PM, Lee Jones wrote:
>>>>>>> On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>
>>>>>>>> On 6/29/2022 8:48 PM, Lee Jones wrote:
>>>>>>>>> On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>
>>>>>>>>>> On 6/28/2022 1:12 PM, Lee Jones wrote:
>>>>>>>>>>> On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>
>>>>>>>>>>>> On 6/27/2022 1:11 PM, Lee Jones wrote:
>>>>>>>>>>>>> On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi Lee,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>>> On 6/20/2022 1:50 PM, Lee Jones wrote:
>>>>>>>>>>>>>>>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>>>>>>>>>>>>>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>>>>>>>>>>>>>>>> client present at a different address space, instead of
>>>>>>>>>>>>>>>>>>> defining a separate DT node. This avoids calling the probe
>>>>>>>>>>>>>>>>>>> twice for the same chip, once for each client pm8008-infra
>>>>>>>>>>>>>>>>>>> and pm8008-regulator.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>>>>>>>>>>>>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>>>>>>>>>>>>>>>> pass the regmap to the regulator driver.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Signed-off-by: Satya Priya<quic_c_skakit@quicinc.com>
>>>>>>>>>>>>>>>>>>> Reviewed-by: Stephen Boyd<swboyd@chromium.org>
>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>> Changes in V15:
>>>>>>>>>>>>>>>>>>>           - None.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Changes in V14:
>>>>>>>>>>>>>>>>>>>           - None.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Changes in V13:
>>>>>>>>>>>>>>>>>>>           - None.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>           drivers/mfd/qcom-pm8008.c       | 34
>>>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++--
>>>>>>>>>>>>>>>>>>>           include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>>>>>>>>>>>>>>>           2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>>>>>>>>>>>>>>>           create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>> index 569ffd50..55e2a8e 100644
>>>>>>>>>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>> @@ -9,6 +9,7 @@
>>>>>>>>>>>>>>>>>>>           #include <linux/interrupt.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/irq.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/irqdomain.h>
>>>>>>>>>>>>>>>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/module.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/of_device.h>
>>>>>>>>>>>>>>>>>>>           #include <linux/of_platform.h>
>>>>>>>>>>>>>>>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>>>>>>>>>>>>>>>           struct pm8008_data {
>>>>>>>>>>>>>>>>>>>               struct device *dev;
>>>>>>>>>>>>>>>>>>> +    struct regmap *regulators_regmap;
>>>>>>>>>>>>>>>>>>>               int irq;
>>>>>>>>>>>>>>>>>>>               struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>>>>>>>>           };
>>>>>>>>>>>>>>>>>>> @@ -150,6 +152,12 @@ static struct regmap_config
>>>>>>>>>>>>>>>>>>> qcom_mfd_regmap_cfg = {
>>>>>>>>>>>>>>>>>>>               .max_register    = 0xFFFF,
>>>>>>>>>>>>>>>>>>>           };
>>>>>>>>>>>>>>>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>>>> +    return chip->regulators_regmap;
>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>>>>>>>> Seems like abstraction for the sake of abstraction.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Why not do the dereference inside the regulator driver?
>>>>>>>>>>>>>>>>> To derefer this in the regulator driver, we need to have the
>>>>>>>>>>>>>>>>> pm8008_data
>>>>>>>>>>>>>>>>> struct definition in the qcom_pm8008 header file.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> I think it doesn't look great to have only that structure in
>>>>>>>>>>>>>>>>> header and all
>>>>>>>>>>>>>>>>> other structs and enum in the mfd driver.
>>>>>>>>>>>>>>>> Then why pass 'pm8008_data' at all?
>>>>>>>>>>>>>>> There is one more option, instead of passing the pm8008_data, we could
>>>>>>>>>>>>>>> pass the pdev->dev.parent and get the pm8008 chip data directly in the
>>>>>>>>>>>>>>> pm8008_get_regmap() like below
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> struct regmap *pm8008_get_regmap(const struct device *dev)
>>>>>>>>>>>>>>>         {
>>>>>>>>>>>>>>>             const struct pm8008_data *chip = dev_get_drvdata(dev);
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>             return chip->regulators_regmap;
>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> By doing this we can avoid having declaration of pm8008_data also in the
>>>>>>>>>>>>>>> header. Please let me know if this looks good.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Could you please confirm on this?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> What's preventing you from passing 'regmap'?
>>>>>>>>>>>>>>> I didn't get what you meant here, could you please elaborate a bit?
>>>>>>>>>>>>> Ah yes.  I authored you a patch, but became distracted. Here:
>>>>>>>>>>>>>
>>>>>>>>>>>>> -----8<--------------------8<-------
>>>>>>>>>>>>>
>>>>>>>>>>>>> From: Lee Jones<lee.jones@linaro.org>
>>>>>>>>>>>>>
>>>>>>>>>>>>> mfd: pm8008: Remove driver data structure pm8008_data
>>>>>>>>>>>>> Maintaining a local driver data structure that is never shared
>>>>>>>>>>>>> outside of the core device is an unnecessary complexity.  Half of the
>>>>>>>>>>>>> attributes were not used outside of a single function, one of which
>>>>>>>>>>>>> was not used at all.  The remaining 2 are generic and can be passed
>>>>>>>>>>>>> around as required.
>>>>>>>>>>>> Okay, but we still need to store the regulators_regmap, which is required in
>>>>>>>>>>>> the pm8008 regulator driver. Could we use a global variable for it?
>>>>>>>>>>> Look down ...
>>>>>>>>>>>
>>>>>>>>>>>>> Signed-off-by: Lee Jones<lee.jones@linaro.org>
>>>>>>>>>>>>> ---
>>>>>>>>>>>>>         drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
>>>>>>>>>>>>>         1 file changed, 20 insertions(+), 33 deletions(-)
>>>>>>>>>>>>>
>>>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> index c472d7f8103c4..4b8ff947762f2 100644
>>>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>> @@ -54,13 +54,6 @@ enum {
>>>>>>>>>>>>>         #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
>>>>>>>>>>>>> -struct pm8008_data {
>>>>>>>>>>>>> -	struct device *dev;
>>>>>>>>>>>>> -	struct regmap *regmap;
>>>>>>>>>>>>> -	int irq;
>>>>>>>>>>>>> -	struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>> -};
>>>>>>>>>>>>> -
>>>>>>>>>>>>>         static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
>>>>>>>>>>>>>         static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
>>>>>>>>>>>>>         static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
>>>>>>>>>>>>> @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>>>>>>>>>>>>         	.max_register	= 0xFFFF,
>>>>>>>>>>>>>         };
>>>>>>>>>>>>> -static int pm8008_init(struct pm8008_data *chip)
>>>>>>>>>>>>> +static int pm8008_init(struct regmap *regmap)
>>>>>>>>>>>>>         {
>>>>>>>>>>>>>         	int rc;
>>>>>>>>>>>>> @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
>>>>>>>>>>>>>         	 * This is required to enable the writing of TYPE registers in
>>>>>>>>>>>>>         	 * regmap_irq_sync_unlock().
>>>>>>>>>>>>>         	 */
>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>> -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
>>>>>>>>>>>>> -			 BIT(0));
>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>         	if (rc)
>>>>>>>>>>>>>         		return rc;
>>>>>>>>>>>>>         	/* Do the same for GPIO1 and GPIO2 peripherals */
>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>> -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>         	if (rc)
>>>>>>>>>>>>>         		return rc;
>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>> -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>         	return rc;
>>>>>>>>>>>>>         }
>>>>>>>>>>>>> -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>> +static int pm8008_probe_irq_peripherals(struct device *dev,
>>>>>>>>>>>>> +					struct regmap *regmap,
>>>>>>>>>>>>>         					int client_irq)
>>>>>>>>>>>>>         {
>>>>>>>>>>>>>         	int rc, i;
>>>>>>>>>>>>>         	struct regmap_irq_type *type;
>>>>>>>>>>>>>         	struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>> -	rc = pm8008_init(chip);
>>>>>>>>>>>>> +	rc = pm8008_init(regmap);
>>>>>>>>>>>>>         	if (rc) {
>>>>>>>>>>>>> -		dev_err(chip->dev, "Init failed: %d\n", rc);
>>>>>>>>>>>>> +		dev_err(dev, "Init failed: %d\n", rc);
>>>>>>>>>>>>>         		return rc;
>>>>>>>>>>>>>         	}
>>>>>>>>>>>>> @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>>         				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
>>>>>>>>>>>>>         	}
>>>>>>>>>>>>> -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
>>>>>>>>>>>>> +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
>>>>>>>>>>>>>         			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
>>>>>>>>>>>>>         	if (rc) {
>>>>>>>>>>>>> -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>>>>>>> +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>>>>>>>         		return rc;
>>>>>>>>>>>>>         	}
>>>>>>>>>>>>> @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>>         static int pm8008_probe(struct i2c_client *client)
>>>>>>>>>>>>>         {
>>>>>>>>>>>>>         	int rc;
>>>>>>>>>>>>> -	struct pm8008_data *chip;
>>>>>>>>>>>>> -
>>>>>>>>>>>>> -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
>>>>>>>>>>>>> -	if (!chip)
>>>>>>>>>>>>> -		return -ENOMEM;
>>>>>>>>>>>>> +	struct device *dev;
>>>>>>>>>>>>> +	struct regmap *regmap;
>>>>>>>>>>>>> -	chip->dev = &client->dev;
>>>>>>>>>>>>> -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>>>>>>>> -	if (!chip->regmap)
>>>>>>>>>>>>> +	dev = &client->dev;
>>>>>>>>>>>>> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>>>>>>>> +	if (!regmap)
>>>>>>>>>>>>>         		return -ENODEV;
>>>>>>>>>>>>> -	i2c_set_clientdata(client, chip);
>>>>>>>>>>>>> +	i2c_set_clientdata(client, regmap);
>>>>>>>>>>> Here ^
>>>>>>>>>> I have added a dummy device and set the client data by passing regmap, see
>>>>>>>>>> below:
>>>>>>>>>>
>>>>>>>>>> +       regulators_client = i2c_new_dummy_device(client->adapter,
>>>>>>>>>> client->addr + 1);
>>>>>>>>>> +       if (IS_ERR(regulators_client)) {
>>>>>>>>>> +               dev_err(dev, "can't attach client\n");
>>>>>>>>>> +               return PTR_ERR(regulators_client);
>>>>>>>>>> +       }
>>>>>>>>>> +
>>>>>>>>>> +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
>>>>>>>>>> &qcom_mfd_regmap_cfg[1]);
>>>>>>>>>> +       if (!regmap)
>>>>>>>>>> +               return -ENODEV;
>>>>>>>>>> +
>>>>>>>>>> +       i2c_set_clientdata(client, regulators_regmap);
>>>>>>>>>>
>>>>>>>>>> Now if i try to get this regmap from regulator driver by doing
>>>>>>>>>>
>>>>>>>>>> struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
>>>>>>>>>>
>>>>>>>>>> it still gets me the regmap of pm8008@8 device and not the regulator device
>>>>>>>>>> regmap (0x9). Not sure if I'm missing something here.
>>>>>>>>> So you need to pass 2 regmap pointers?
>>>>>>>>>
>>>>>>>>> If you need to pass more than one item to the child devices, you do
>>>>>>>>> need to use a struct for that.
>>>>>>>> I need to pass only one regmap out of the two, but i am not able to retrieve
>>>>>>>> the correct regmap simply by doing i2c_set_clientdata
>>>>>>>>
>>>>>>>> probably because we are having all the child nodes under same DT node and
>>>>>>>> thus not able to distinguish based on the dev pointer
>>>>>>> You can only pull out (get) the pointer that you put in (set).
>>>>>>>
>>>>>>> Unless you over-wrote it later in the thread of execution, you are
>>>>>>> pulling out whatever regulators_regmap happens to be.
>>>>>>>
>>>>>>> Is qcom_mfd_regmap_cfg[1] definitely the one you want?
>>>>>> Yes, I need qcom_mfd_regmap_cfg[1]
>>>>>>
>>>>>> Pasting code snippet for reference:
>>>>>>
>>>>>> static struct regmap_config qcom_mfd_regmap_cfg[2] = {
>>>>>>         {
>>>>>>
>>>>>>             .name = "infra",
>>>>>>             .reg_bits   = 16,
>>>>>>             .val_bits   = 8,
>>>>>>             .max_register   = 0xFFFF,
>>>>>>         },
>>>>>>         {
>>>>>>             .name = "regulators",
>>>>>>             .reg_bits   = 16,
>>>>>>             .val_bits   = 8,
>>>>>>             .max_register   = 0xFFFF,
>>>>>>         },
>>>>>>
>>>>>> };
>>>>>>
>>>>>>
>>>>>> Inside pm8008_probe:
>>>>>>
>>>>>>
>>>>>>         regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
>>>>>>         if (!regmap)
>>>>>>             return -ENODEV;
>>>>>>
>>>>>>         i2c_set_clientdata(client, regmap);
>>>>>>
>>>>>>
>>>>>>         regulators_client = i2c_new_dummy_device(client->adapter, client->addr
>>>>>> + 1);
>>>>>>         if (IS_ERR(regulators_client)) {
>>>>>>             dev_err(dev, "can't attach client\n");
>>>>>>             return PTR_ERR(regulators_client);
>>>>>>         }
>>>>>>
>>>>>>         regulators_regmap = devm_regmap_init_i2c(regulators_client,
>>>>>> &qcom_mfd_regmap_cfg[1]);
>>>>>>         if (!regmap)
>>>>>>             return -ENODEV;
>>>>>>
>>>>>>         i2c_set_clientdata(regulators_client, regulators_regmap);
>>>>> You can't call this twice.
>>>>>
>>>>> Doing so with over-write regmap with regulators_regmap.
>>>>>
>>>>> You said you only needed one?
>>>>>
>>>>>      "I need to pass only one regmap out of the two, but i am not able to retrieve"
>>>> I thought you asked whether we have to pass two regmaps to the child
>>>> regulator driver.
>>> Yes, that's what I was asking.
>>>
>>> So you only need to pass 'regulators_regmap' (derived from
>>> "regulators") right?
>>
>> Yes
>>
>>
>>> In that case, keep:
>>>
>>>     i2c_set_clientdata(regulators_client, regulators_regmap);
>>>
>>> ... and drop:
>>>
>>>     i2c_set_clientdata(client, regmap);
>>
>> Dropping this did not help, it says regmap is NULL. Can we drop this? we
> If it's NULL coming out, it was NULL going in.
>
> Does it get checked before setting it?
>
> Are you getting it from the right device?
>
>> might still need it for other child peripherals like gpios?
>>
>> Also, setting the data through different clients would still overwrite the
>> data? I thought it would be written to respective client->dev.
> It does, but you are fetching it back out from the parent, right?
>
>    const struct pm8008_data *chip = dev_get_drvdata(pdev->dev.parent);
>
> Which is only one device.
>
> If you want to set the child's data, then that is usually accomplished
> using platform_data (you can do this using the MFD API - see struct
> mfd_cell), not driver_data.
>
>>>>>> In qcom-pm8008-regulator.c I tried to get the regmap using
>>>>>>
>>>>>> dev_get_regmap(pdev->dev.parent, "regulators");
>>>>> I haven't looked at this API before.  I suggest that this would be
>>>>> used *instead* of passing the regmap pointer via driver_data.
>>>>>
>>>>> It looks like you're using different devices to init your regmaps;
>>>>> 'client' and 'regulator_client' (derived from client->adapter).
>>>>>
>>>>> "regulators" is registered using regulators_regmap which was *not*
>>>>> init'ed with pdev->dev.parent (same as client->dev), so trying to
>>>>> dev_get_regmap() with that device pointer will not work.
>>>> Okay, So I will leave the driver as is then?
>>> Right, let's take a step back and try to clarify a few things here.
>>>
>>> What is the purpose of the two regmaps that you're creating here?
>> The pm8008 chip is an I2C based pmic which has 2 address spaces 0x8 and 0x9.
>>
>>> Where will each of them be used?
>> Under the 0x8 address space peripherals like gpio, temp-alarm etc will be
>> present and under the 0x9 regulators are present.
>>
>>> Regmaps created in MFD are usually either used only locally, here in
>>> the parent driver or shared amongst *multiple* children.  If that is
>>> not the case for regulators_regmap, which looks suspiciously like it's
>>> only used in the Regulator driver, then why not initialise the regmap
>>> there instead?  Rather than pointlessly creating it here and passing
>>> it via the driver_data pointer.
>>
>> Initially we implemented below design
>>
>> [V4,5/6] arm64: dts: qcom: pm8008: Add base dts file - Patchwork
>> (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1637314953-4215-6-git-send-email-quic_c_skakit@quicinc.com/>
>>
>> As per Mark's suggestions I've dropped the compatible for regulator driver
>> and registered the regulators through mfd driver.
> If the regmap is _only_ used in the regulator driver, it should be
> initialised there.
>
> I suggest you move all of this regmap set-up into the Regulator
> driver and have done with it.

Hi Lee,


Are you suggesting we should use i2c_new_dummy_device() to register the 
0x9 device and then use mfd_cell struct to register the LDOs(it's 
children)?


  static const struct mfd_cell pm8008_regulator_dev = {
          .of_compatible = "qcom,pm8008-regulator",
  };


Inside probe:

    regulators_client = i2c_new_dummy_device(client->adapter, 
client->addr + 1);

     if (IS_ERR(regulators_client)) {
          dev_err(dev, "can't attach client\n");
          return PTR_ERR(regulators_client);
      }

      pm8008_regulator_dev.platform_data = 
dev_get_platdata(&regulators_client->dev);

      rc = devm_mfd_add_devices(&regulators_client->dev, 0, 
pm8008_regulator_dev, 7, NULL, 0, NULL);
      if (rc) {
          dev_err(chip->dev, "Failed to add regulator device: %d\n", rc);
          return rc;
      }

but still i am not clear on how this works and how do we get the 
platform data in the regulator driver. Could you please help me to 
proceed further


>> [V4,2/6] dt-bindings: regulator: Add pm8008 regulator bindings - Patchwork
>> (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1637314953-4215-3-git-send-email-quic_c_skakit@quicinc.com/>
>>
>> Later as per the discussions here [1] and [2], I've added this patch to use
>> i2c_new_dummy_device() API to register the regulator devices as child
>> devices to pm8008@8 node and made the DT changes suggested.
>>
>> [1] [V9,4/6] regulator: Add a regulator driver for the PM8008 PMIC -
>> Patchwork (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1649166633-25872-5-git-send-email-quic_c_skakit@quicinc.com/>
>>
>> [2] [V10,7/9] regulator: Add a regulator driver for the PM8008 PMIC -
>> Patchwork (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1649939418-19861-8-git-send-email-quic_c_skakit@quicinc.com/>
>>
>> To implement this approach, I had to initialize the regulator_regmap in the
>> mfd probe and pass it to the regulator driver either through driver data
>> struct or a global variable. Other mfd drivers with similar implementation
>> are following the same. please let me know if you have further queries
>> regarding this.
> It's fine for the regulator driver to be registered from here, but the
> child should do its own regmap initialisation.
>
>>> Once I know more about your intentions, I can help you devise a plan.
Lee Jones July 12, 2022, 12:47 p.m. UTC | #20
On Mon, 11 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 7/4/2022 6:19 PM, Lee Jones wrote:
> > On Mon, 04 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > > On 7/1/2022 2:42 PM, Lee Jones wrote:
> > > > On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > 
> > > > > On 7/1/2022 1:24 PM, Lee Jones wrote:
> > > > > > On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > 
> > > > > > > On 6/30/2022 4:04 PM, Lee Jones wrote:
> > > > > > > > On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > 
> > > > > > > > > On 6/29/2022 8:48 PM, Lee Jones wrote:
> > > > > > > > > > On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > 
> > > > > > > > > > > On 6/28/2022 1:12 PM, Lee Jones wrote:
> > > > > > > > > > > > On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > 
> > > > > > > > > > > > > On 6/27/2022 1:11 PM, Lee Jones wrote:
> > > > > > > > > > > > > > On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Hi Lee,
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > > > > > On 6/20/2022 1:50 PM, Lee Jones wrote:
> > > > > > > > > > > > > > > > > On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > On 6/17/2022 2:27 AM, Lee Jones wrote:
> > > > > > > > > > > > > > > > > > > On Tue, 14 Jun 2022, Satya Priya wrote:
> > > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > > > Use i2c_new_dummy_device() to register pm8008-regulator
> > > > > > > > > > > > > > > > > > > > client present at a different address space, instead of
> > > > > > > > > > > > > > > > > > > > defining a separate DT node. This avoids calling the probe
> > > > > > > > > > > > > > > > > > > > twice for the same chip, once for each client pm8008-infra
> > > > > > > > > > > > > > > > > > > > and pm8008-regulator.
> > > > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > > > As a part of this define pm8008_regmap_init() to do regmap
> > > > > > > > > > > > > > > > > > > > init for both the clients and define pm8008_get_regmap() to
> > > > > > > > > > > > > > > > > > > > pass the regmap to the regulator driver.
> > > > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > > > Signed-off-by: Satya Priya<quic_c_skakit@quicinc.com>
> > > > > > > > > > > > > > > > > > > > Reviewed-by: Stephen Boyd<swboyd@chromium.org>
> > > > > > > > > > > > > > > > > > > > ---
> > > > > > > > > > > > > > > > > > > > Changes in V15:
> > > > > > > > > > > > > > > > > > > >           - None.
> > > > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > > > Changes in V14:
> > > > > > > > > > > > > > > > > > > >           - None.
> > > > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > > > Changes in V13:
> > > > > > > > > > > > > > > > > > > >           - None.
> > > > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > > >           drivers/mfd/qcom-pm8008.c       | 34
> > > > > > > > > > > > > > > > > > > > ++++++++++++++++++++++++++++++++--
> > > > > > > > > > > > > > > > > > > >           include/linux/mfd/qcom_pm8008.h |  9 +++++++++
> > > > > > > > > > > > > > > > > > > >           2 files changed, 41 insertions(+), 2 deletions(-)
> > > > > > > > > > > > > > > > > > > >           create mode 100644 include/linux/mfd/qcom_pm8008.h
> > > > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > > > > > index 569ffd50..55e2a8e 100644
> > > > > > > > > > > > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > > > > > > > @@ -9,6 +9,7 @@
> > > > > > > > > > > > > > > > > > > >           #include <linux/interrupt.h>
> > > > > > > > > > > > > > > > > > > >           #include <linux/irq.h>
> > > > > > > > > > > > > > > > > > > >           #include <linux/irqdomain.h>
> > > > > > > > > > > > > > > > > > > > +#include <linux/mfd/qcom_pm8008.h>
> > > > > > > > > > > > > > > > > > > >           #include <linux/module.h>
> > > > > > > > > > > > > > > > > > > >           #include <linux/of_device.h>
> > > > > > > > > > > > > > > > > > > >           #include <linux/of_platform.h>
> > > > > > > > > > > > > > > > > > > > @@ -57,6 +58,7 @@ enum {
> > > > > > > > > > > > > > > > > > > >           struct pm8008_data {
> > > > > > > > > > > > > > > > > > > >               struct device *dev;
> > > > > > > > > > > > > > > > > > > > +    struct regmap *regulators_regmap;
> > > > > > > > > > > > > > > > > > > >               int irq;
> > > > > > > > > > > > > > > > > > > >               struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > > > > > > > > > >           };
> > > > > > > > > > > > > > > > > > > > @@ -150,6 +152,12 @@ static struct regmap_config
> > > > > > > > > > > > > > > > > > > > qcom_mfd_regmap_cfg = {
> > > > > > > > > > > > > > > > > > > >               .max_register    = 0xFFFF,
> > > > > > > > > > > > > > > > > > > >           };
> > > > > > > > > > > > > > > > > > > > +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
> > > > > > > > > > > > > > > > > > > > +{
> > > > > > > > > > > > > > > > > > > > +    return chip->regulators_regmap;
> > > > > > > > > > > > > > > > > > > > +}
> > > > > > > > > > > > > > > > > > > > +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > > > > > > > > > > Seems like abstraction for the sake of abstraction.
> > > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > > Why not do the dereference inside the regulator driver?
> > > > > > > > > > > > > > > > > > To derefer this in the regulator driver, we need to have the
> > > > > > > > > > > > > > > > > > pm8008_data
> > > > > > > > > > > > > > > > > > struct definition in the qcom_pm8008 header file.
> > > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > > I think it doesn't look great to have only that structure in
> > > > > > > > > > > > > > > > > > header and all
> > > > > > > > > > > > > > > > > > other structs and enum in the mfd driver.
> > > > > > > > > > > > > > > > > Then why pass 'pm8008_data' at all?
> > > > > > > > > > > > > > > > There is one more option, instead of passing the pm8008_data, we could
> > > > > > > > > > > > > > > > pass the pdev->dev.parent and get the pm8008 chip data directly in the
> > > > > > > > > > > > > > > > pm8008_get_regmap() like below
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > struct regmap *pm8008_get_regmap(const struct device *dev)
> > > > > > > > > > > > > > > >         {
> > > > > > > > > > > > > > > >             const struct pm8008_data *chip = dev_get_drvdata(dev);
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > >             return chip->regulators_regmap;
> > > > > > > > > > > > > > > > }
> > > > > > > > > > > > > > > > EXPORT_SYMBOL_GPL(pm8008_get_regmap);
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > By doing this we can avoid having declaration of pm8008_data also in the
> > > > > > > > > > > > > > > > header. Please let me know if this looks good.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Could you please confirm on this?
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > What's preventing you from passing 'regmap'?
> > > > > > > > > > > > > > > > I didn't get what you meant here, could you please elaborate a bit?
> > > > > > > > > > > > > > Ah yes.  I authored you a patch, but became distracted. Here:
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > -----8<--------------------8<-------
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > From: Lee Jones<lee.jones@linaro.org>
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > mfd: pm8008: Remove driver data structure pm8008_data
> > > > > > > > > > > > > > Maintaining a local driver data structure that is never shared
> > > > > > > > > > > > > > outside of the core device is an unnecessary complexity.  Half of the
> > > > > > > > > > > > > > attributes were not used outside of a single function, one of which
> > > > > > > > > > > > > > was not used at all.  The remaining 2 are generic and can be passed
> > > > > > > > > > > > > > around as required.
> > > > > > > > > > > > > Okay, but we still need to store the regulators_regmap, which is required in
> > > > > > > > > > > > > the pm8008 regulator driver. Could we use a global variable for it?
> > > > > > > > > > > > Look down ...
> > > > > > > > > > > > 
> > > > > > > > > > > > > > Signed-off-by: Lee Jones<lee.jones@linaro.org>
> > > > > > > > > > > > > > ---
> > > > > > > > > > > > > >         drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
> > > > > > > > > > > > > >         1 file changed, 20 insertions(+), 33 deletions(-)
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > index c472d7f8103c4..4b8ff947762f2 100644
> > > > > > > > > > > > > > --- a/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > +++ b/drivers/mfd/qcom-pm8008.c
> > > > > > > > > > > > > > @@ -54,13 +54,6 @@ enum {
> > > > > > > > > > > > > >         #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
> > > > > > > > > > > > > > -struct pm8008_data {
> > > > > > > > > > > > > > -	struct device *dev;
> > > > > > > > > > > > > > -	struct regmap *regmap;
> > > > > > > > > > > > > > -	int irq;
> > > > > > > > > > > > > > -	struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > > > > -};
> > > > > > > > > > > > > > -
> > > > > > > > > > > > > >         static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
> > > > > > > > > > > > > >         static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
> > > > > > > > > > > > > >         static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
> > > > > > > > > > > > > > @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
> > > > > > > > > > > > > >         	.max_register	= 0xFFFF,
> > > > > > > > > > > > > >         };
> > > > > > > > > > > > > > -static int pm8008_init(struct pm8008_data *chip)
> > > > > > > > > > > > > > +static int pm8008_init(struct regmap *regmap)
> > > > > > > > > > > > > >         {
> > > > > > > > > > > > > >         	int rc;
> > > > > > > > > > > > > > @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
> > > > > > > > > > > > > >         	 * This is required to enable the writing of TYPE registers in
> > > > > > > > > > > > > >         	 * regmap_irq_sync_unlock().
> > > > > > > > > > > > > >         	 */
> > > > > > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > > > > > -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
> > > > > > > > > > > > > > -			 BIT(0));
> > > > > > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > > > >         	if (rc)
> > > > > > > > > > > > > >         		return rc;
> > > > > > > > > > > > > >         	/* Do the same for GPIO1 and GPIO2 peripherals */
> > > > > > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > > > > > -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > > > >         	if (rc)
> > > > > > > > > > > > > >         		return rc;
> > > > > > > > > > > > > > -	rc = regmap_write(chip->regmap,
> > > > > > > > > > > > > > -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > > > > +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
> > > > > > > > > > > > > >         	return rc;
> > > > > > > > > > > > > >         }
> > > > > > > > > > > > > > -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > > > > > > +static int pm8008_probe_irq_peripherals(struct device *dev,
> > > > > > > > > > > > > > +					struct regmap *regmap,
> > > > > > > > > > > > > >         					int client_irq)
> > > > > > > > > > > > > >         {
> > > > > > > > > > > > > >         	int rc, i;
> > > > > > > > > > > > > >         	struct regmap_irq_type *type;
> > > > > > > > > > > > > >         	struct regmap_irq_chip_data *irq_data;
> > > > > > > > > > > > > > -	rc = pm8008_init(chip);
> > > > > > > > > > > > > > +	rc = pm8008_init(regmap);
> > > > > > > > > > > > > >         	if (rc) {
> > > > > > > > > > > > > > -		dev_err(chip->dev, "Init failed: %d\n", rc);
> > > > > > > > > > > > > > +		dev_err(dev, "Init failed: %d\n", rc);
> > > > > > > > > > > > > >         		return rc;
> > > > > > > > > > > > > >         	}
> > > > > > > > > > > > > > @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > > > > > >         				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
> > > > > > > > > > > > > >         	}
> > > > > > > > > > > > > > -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
> > > > > > > > > > > > > > +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
> > > > > > > > > > > > > >         			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
> > > > > > > > > > > > > >         	if (rc) {
> > > > > > > > > > > > > > -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > > > > > > > > > +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
> > > > > > > > > > > > > >         		return rc;
> > > > > > > > > > > > > >         	}
> > > > > > > > > > > > > > @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
> > > > > > > > > > > > > >         static int pm8008_probe(struct i2c_client *client)
> > > > > > > > > > > > > >         {
> > > > > > > > > > > > > >         	int rc;
> > > > > > > > > > > > > > -	struct pm8008_data *chip;
> > > > > > > > > > > > > > -
> > > > > > > > > > > > > > -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > > > > > > > > > > > > > -	if (!chip)
> > > > > > > > > > > > > > -		return -ENOMEM;
> > > > > > > > > > > > > > +	struct device *dev;
> > > > > > > > > > > > > > +	struct regmap *regmap;
> > > > > > > > > > > > > > -	chip->dev = &client->dev;
> > > > > > > > > > > > > > -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > > > > > > > > > -	if (!chip->regmap)
> > > > > > > > > > > > > > +	dev = &client->dev;
> > > > > > > > > > > > > > +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
> > > > > > > > > > > > > > +	if (!regmap)
> > > > > > > > > > > > > >         		return -ENODEV;
> > > > > > > > > > > > > > -	i2c_set_clientdata(client, chip);
> > > > > > > > > > > > > > +	i2c_set_clientdata(client, regmap);
> > > > > > > > > > > > Here ^
> > > > > > > > > > > I have added a dummy device and set the client data by passing regmap, see
> > > > > > > > > > > below:
> > > > > > > > > > > 
> > > > > > > > > > > +       regulators_client = i2c_new_dummy_device(client->adapter,
> > > > > > > > > > > client->addr + 1);
> > > > > > > > > > > +       if (IS_ERR(regulators_client)) {
> > > > > > > > > > > +               dev_err(dev, "can't attach client\n");
> > > > > > > > > > > +               return PTR_ERR(regulators_client);
> > > > > > > > > > > +       }
> > > > > > > > > > > +
> > > > > > > > > > > +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
> > > > > > > > > > > &qcom_mfd_regmap_cfg[1]);
> > > > > > > > > > > +       if (!regmap)
> > > > > > > > > > > +               return -ENODEV;
> > > > > > > > > > > +
> > > > > > > > > > > +       i2c_set_clientdata(client, regulators_regmap);
> > > > > > > > > > > 
> > > > > > > > > > > Now if i try to get this regmap from regulator driver by doing
> > > > > > > > > > > 
> > > > > > > > > > > struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
> > > > > > > > > > > 
> > > > > > > > > > > it still gets me the regmap of pm8008@8 device and not the regulator device
> > > > > > > > > > > regmap (0x9). Not sure if I'm missing something here.
> > > > > > > > > > So you need to pass 2 regmap pointers?
> > > > > > > > > > 
> > > > > > > > > > If you need to pass more than one item to the child devices, you do
> > > > > > > > > > need to use a struct for that.
> > > > > > > > > I need to pass only one regmap out of the two, but i am not able to retrieve
> > > > > > > > > the correct regmap simply by doing i2c_set_clientdata
> > > > > > > > > 
> > > > > > > > > probably because we are having all the child nodes under same DT node and
> > > > > > > > > thus not able to distinguish based on the dev pointer
> > > > > > > > You can only pull out (get) the pointer that you put in (set).
> > > > > > > > 
> > > > > > > > Unless you over-wrote it later in the thread of execution, you are
> > > > > > > > pulling out whatever regulators_regmap happens to be.
> > > > > > > > 
> > > > > > > > Is qcom_mfd_regmap_cfg[1] definitely the one you want?
> > > > > > > Yes, I need qcom_mfd_regmap_cfg[1]
> > > > > > > 
> > > > > > > Pasting code snippet for reference:
> > > > > > > 
> > > > > > > static struct regmap_config qcom_mfd_regmap_cfg[2] = {
> > > > > > >         {
> > > > > > > 
> > > > > > >             .name = "infra",
> > > > > > >             .reg_bits   = 16,
> > > > > > >             .val_bits   = 8,
> > > > > > >             .max_register   = 0xFFFF,
> > > > > > >         },
> > > > > > >         {
> > > > > > >             .name = "regulators",
> > > > > > >             .reg_bits   = 16,
> > > > > > >             .val_bits   = 8,
> > > > > > >             .max_register   = 0xFFFF,
> > > > > > >         },
> > > > > > > 
> > > > > > > };
> > > > > > > 
> > > > > > > 
> > > > > > > Inside pm8008_probe:
> > > > > > > 
> > > > > > > 
> > > > > > >         regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
> > > > > > >         if (!regmap)
> > > > > > >             return -ENODEV;
> > > > > > > 
> > > > > > >         i2c_set_clientdata(client, regmap);
> > > > > > > 
> > > > > > > 
> > > > > > >         regulators_client = i2c_new_dummy_device(client->adapter, client->addr
> > > > > > > + 1);
> > > > > > >         if (IS_ERR(regulators_client)) {
> > > > > > >             dev_err(dev, "can't attach client\n");
> > > > > > >             return PTR_ERR(regulators_client);
> > > > > > >         }
> > > > > > > 
> > > > > > >         regulators_regmap = devm_regmap_init_i2c(regulators_client,
> > > > > > > &qcom_mfd_regmap_cfg[1]);
> > > > > > >         if (!regmap)
> > > > > > >             return -ENODEV;
> > > > > > > 
> > > > > > >         i2c_set_clientdata(regulators_client, regulators_regmap);
> > > > > > You can't call this twice.
> > > > > > 
> > > > > > Doing so with over-write regmap with regulators_regmap.
> > > > > > 
> > > > > > You said you only needed one?
> > > > > > 
> > > > > >      "I need to pass only one regmap out of the two, but i am not able to retrieve"
> > > > > I thought you asked whether we have to pass two regmaps to the child
> > > > > regulator driver.
> > > > Yes, that's what I was asking.
> > > > 
> > > > So you only need to pass 'regulators_regmap' (derived from
> > > > "regulators") right?
> > > 
> > > Yes
> > > 
> > > 
> > > > In that case, keep:
> > > > 
> > > >     i2c_set_clientdata(regulators_client, regulators_regmap);
> > > > 
> > > > ... and drop:
> > > > 
> > > >     i2c_set_clientdata(client, regmap);
> > > 
> > > Dropping this did not help, it says regmap is NULL. Can we drop this? we
> > If it's NULL coming out, it was NULL going in.
> > 
> > Does it get checked before setting it?
> > 
> > Are you getting it from the right device?
> > 
> > > might still need it for other child peripherals like gpios?
> > > 
> > > Also, setting the data through different clients would still overwrite the
> > > data? I thought it would be written to respective client->dev.
> > It does, but you are fetching it back out from the parent, right?
> > 
> >    const struct pm8008_data *chip = dev_get_drvdata(pdev->dev.parent);
> > 
> > Which is only one device.
> > 
> > If you want to set the child's data, then that is usually accomplished
> > using platform_data (you can do this using the MFD API - see struct
> > mfd_cell), not driver_data.
> > 
> > > > > > > In qcom-pm8008-regulator.c I tried to get the regmap using
> > > > > > > 
> > > > > > > dev_get_regmap(pdev->dev.parent, "regulators");
> > > > > > I haven't looked at this API before.  I suggest that this would be
> > > > > > used *instead* of passing the regmap pointer via driver_data.
> > > > > > 
> > > > > > It looks like you're using different devices to init your regmaps;
> > > > > > 'client' and 'regulator_client' (derived from client->adapter).
> > > > > > 
> > > > > > "regulators" is registered using regulators_regmap which was *not*
> > > > > > init'ed with pdev->dev.parent (same as client->dev), so trying to
> > > > > > dev_get_regmap() with that device pointer will not work.
> > > > > Okay, So I will leave the driver as is then?
> > > > Right, let's take a step back and try to clarify a few things here.
> > > > 
> > > > What is the purpose of the two regmaps that you're creating here?
> > > The pm8008 chip is an I2C based pmic which has 2 address spaces 0x8 and 0x9.
> > > 
> > > > Where will each of them be used?
> > > Under the 0x8 address space peripherals like gpio, temp-alarm etc will be
> > > present and under the 0x9 regulators are present.
> > > 
> > > > Regmaps created in MFD are usually either used only locally, here in
> > > > the parent driver or shared amongst *multiple* children.  If that is
> > > > not the case for regulators_regmap, which looks suspiciously like it's
> > > > only used in the Regulator driver, then why not initialise the regmap
> > > > there instead?  Rather than pointlessly creating it here and passing
> > > > it via the driver_data pointer.
> > > 
> > > Initially we implemented below design
> > > 
> > > [V4,5/6] arm64: dts: qcom: pm8008: Add base dts file - Patchwork
> > > (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1637314953-4215-6-git-send-email-quic_c_skakit@quicinc.com/>
> > > 
> > > As per Mark's suggestions I've dropped the compatible for regulator driver
> > > and registered the regulators through mfd driver.
> > If the regmap is _only_ used in the regulator driver, it should be
> > initialised there.
> > 
> > I suggest you move all of this regmap set-up into the Regulator
> > driver and have done with it.
> 
> Hi Lee,
> 
> 
> Are you suggesting we should use i2c_new_dummy_device() to register the 0x9
> device and then use mfd_cell struct to register the LDOs(it's children)?
> 
> 
>  static const struct mfd_cell pm8008_regulator_dev = {
>          .of_compatible = "qcom,pm8008-regulator",
>  };
> 
> 
> Inside probe:
> 
>    regulators_client = i2c_new_dummy_device(client->adapter, client->addr +
> 1);
> 
>     if (IS_ERR(regulators_client)) {
>          dev_err(dev, "can't attach client\n");
>          return PTR_ERR(regulators_client);
>      }
> 
>      pm8008_regulator_dev.platform_data =
> dev_get_platdata(&regulators_client->dev);
> 
>      rc = devm_mfd_add_devices(&regulators_client->dev, 0,
> pm8008_regulator_dev, 7, NULL, 0, NULL);
>      if (rc) {
>          dev_err(chip->dev, "Failed to add regulator device: %d\n", rc);
>          return rc;
>      }
> 
> but still i am not clear on how this works and how do we get the platform
> data in the regulator driver. Could you please help me to proceed further

Okay, so I've taken some time to read through your previous
submissions to see how we ended up down this rabbit hole.

Essentially, it looks to me like the 2 I2C devices should be kept
separate and the Regulator driver should be registered/probed without
requiring this I2C dummy device hoop jumping exercise.

As Stephen asked in v9 [0], why can't the regulator driver be I2C?

Then it can manage its own resources and all of this craziness can be
avoided.

That's not to say that the v9 submission was the right way to go
either.  Everything in relation to:

  i2c_add_driver(&pm8008_regulators_driver);

... should be moved into the Regulator driver itself.

[0] https://lore.kernel.org/all/CAE-0n53G-atsuwqcgNvi3nvWyiO3P=pSj5zDUMYj0ELVYJE54Q@mail.gmail.com/
Satya Priya Kakitapalli (Temp) July 13, 2022, 5:50 a.m. UTC | #21
On 7/12/2022 6:17 PM, Lee Jones wrote:
> On Mon, 11 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>
>> On 7/4/2022 6:19 PM, Lee Jones wrote:
>>> On Mon, 04 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>
>>>> On 7/1/2022 2:42 PM, Lee Jones wrote:
>>>>> On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>
>>>>>> On 7/1/2022 1:24 PM, Lee Jones wrote:
>>>>>>> On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>
>>>>>>>> On 6/30/2022 4:04 PM, Lee Jones wrote:
>>>>>>>>> On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>
>>>>>>>>>> On 6/29/2022 8:48 PM, Lee Jones wrote:
>>>>>>>>>>> On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>
>>>>>>>>>>>> On 6/28/2022 1:12 PM, Lee Jones wrote:
>>>>>>>>>>>>> On Tue, 28 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> On 6/27/2022 1:11 PM, Lee Jones wrote:
>>>>>>>>>>>>>>> On Mon, 27 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi Lee,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On 6/20/2022 4:37 PM, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>>>>> On 6/20/2022 1:50 PM, Lee Jones wrote:
>>>>>>>>>>>>>>>>>> On Mon, 20 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> On 6/17/2022 2:27 AM, Lee Jones wrote:
>>>>>>>>>>>>>>>>>>>> On Tue, 14 Jun 2022, Satya Priya wrote:
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Use i2c_new_dummy_device() to register pm8008-regulator
>>>>>>>>>>>>>>>>>>>>> client present at a different address space, instead of
>>>>>>>>>>>>>>>>>>>>> defining a separate DT node. This avoids calling the probe
>>>>>>>>>>>>>>>>>>>>> twice for the same chip, once for each client pm8008-infra
>>>>>>>>>>>>>>>>>>>>> and pm8008-regulator.
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> As a part of this define pm8008_regmap_init() to do regmap
>>>>>>>>>>>>>>>>>>>>> init for both the clients and define pm8008_get_regmap() to
>>>>>>>>>>>>>>>>>>>>> pass the regmap to the regulator driver.
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Signed-off-by: Satya Priya<quic_c_skakit@quicinc.com>
>>>>>>>>>>>>>>>>>>>>> Reviewed-by: Stephen Boyd<swboyd@chromium.org>
>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>> Changes in V15:
>>>>>>>>>>>>>>>>>>>>>            - None.
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Changes in V14:
>>>>>>>>>>>>>>>>>>>>>            - None.
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Changes in V13:
>>>>>>>>>>>>>>>>>>>>>            - None.
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>            drivers/mfd/qcom-pm8008.c       | 34
>>>>>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++--
>>>>>>>>>>>>>>>>>>>>>            include/linux/mfd/qcom_pm8008.h |  9 +++++++++
>>>>>>>>>>>>>>>>>>>>>            2 files changed, 41 insertions(+), 2 deletions(-)
>>>>>>>>>>>>>>>>>>>>>            create mode 100644 include/linux/mfd/qcom_pm8008.h
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>>>> index 569ffd50..55e2a8e 100644
>>>>>>>>>>>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>>>>>>>> @@ -9,6 +9,7 @@
>>>>>>>>>>>>>>>>>>>>>            #include <linux/interrupt.h>
>>>>>>>>>>>>>>>>>>>>>            #include <linux/irq.h>
>>>>>>>>>>>>>>>>>>>>>            #include <linux/irqdomain.h>
>>>>>>>>>>>>>>>>>>>>> +#include <linux/mfd/qcom_pm8008.h>
>>>>>>>>>>>>>>>>>>>>>            #include <linux/module.h>
>>>>>>>>>>>>>>>>>>>>>            #include <linux/of_device.h>
>>>>>>>>>>>>>>>>>>>>>            #include <linux/of_platform.h>
>>>>>>>>>>>>>>>>>>>>> @@ -57,6 +58,7 @@ enum {
>>>>>>>>>>>>>>>>>>>>>            struct pm8008_data {
>>>>>>>>>>>>>>>>>>>>>                struct device *dev;
>>>>>>>>>>>>>>>>>>>>> +    struct regmap *regulators_regmap;
>>>>>>>>>>>>>>>>>>>>>                int irq;
>>>>>>>>>>>>>>>>>>>>>                struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>>>>>>>>>>            };
>>>>>>>>>>>>>>>>>>>>> @@ -150,6 +152,12 @@ static struct regmap_config
>>>>>>>>>>>>>>>>>>>>> qcom_mfd_regmap_cfg = {
>>>>>>>>>>>>>>>>>>>>>                .max_register    = 0xFFFF,
>>>>>>>>>>>>>>>>>>>>>            };
>>>>>>>>>>>>>>>>>>>>> +struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
>>>>>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>>>>>> +    return chip->regulators_regmap;
>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>> +EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>>>>>>>>>> Seems like abstraction for the sake of abstraction.
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> Why not do the dereference inside the regulator driver?
>>>>>>>>>>>>>>>>>>> To derefer this in the regulator driver, we need to have the
>>>>>>>>>>>>>>>>>>> pm8008_data
>>>>>>>>>>>>>>>>>>> struct definition in the qcom_pm8008 header file.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> I think it doesn't look great to have only that structure in
>>>>>>>>>>>>>>>>>>> header and all
>>>>>>>>>>>>>>>>>>> other structs and enum in the mfd driver.
>>>>>>>>>>>>>>>>>> Then why pass 'pm8008_data' at all?
>>>>>>>>>>>>>>>>> There is one more option, instead of passing the pm8008_data, we could
>>>>>>>>>>>>>>>>> pass the pdev->dev.parent and get the pm8008 chip data directly in the
>>>>>>>>>>>>>>>>> pm8008_get_regmap() like below
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> struct regmap *pm8008_get_regmap(const struct device *dev)
>>>>>>>>>>>>>>>>>          {
>>>>>>>>>>>>>>>>>              const struct pm8008_data *chip = dev_get_drvdata(dev);
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>              return chip->regulators_regmap;
>>>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>>>> EXPORT_SYMBOL_GPL(pm8008_get_regmap);
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> By doing this we can avoid having declaration of pm8008_data also in the
>>>>>>>>>>>>>>>>> header. Please let me know if this looks good.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Could you please confirm on this?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> What's preventing you from passing 'regmap'?
>>>>>>>>>>>>>>>>> I didn't get what you meant here, could you please elaborate a bit?
>>>>>>>>>>>>>>> Ah yes.  I authored you a patch, but became distracted. Here:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> -----8<--------------------8<-------
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> From: Lee Jones<lee.jones@linaro.org>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> mfd: pm8008: Remove driver data structure pm8008_data
>>>>>>>>>>>>>>> Maintaining a local driver data structure that is never shared
>>>>>>>>>>>>>>> outside of the core device is an unnecessary complexity.  Half of the
>>>>>>>>>>>>>>> attributes were not used outside of a single function, one of which
>>>>>>>>>>>>>>> was not used at all.  The remaining 2 are generic and can be passed
>>>>>>>>>>>>>>> around as required.
>>>>>>>>>>>>>> Okay, but we still need to store the regulators_regmap, which is required in
>>>>>>>>>>>>>> the pm8008 regulator driver. Could we use a global variable for it?
>>>>>>>>>>>>> Look down ...
>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Signed-off-by: Lee Jones<lee.jones@linaro.org>
>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>          drivers/mfd/qcom-pm8008.c | 53 ++++++++++++++++++-----------------------------
>>>>>>>>>>>>>>>          1 file changed, 20 insertions(+), 33 deletions(-)
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>> index c472d7f8103c4..4b8ff947762f2 100644
>>>>>>>>>>>>>>> --- a/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>> +++ b/drivers/mfd/qcom-pm8008.c
>>>>>>>>>>>>>>> @@ -54,13 +54,6 @@ enum {
>>>>>>>>>>>>>>>          #define PM8008_PERIPH_OFFSET(paddr)	(paddr - PM8008_PERIPH_0_BASE)
>>>>>>>>>>>>>>> -struct pm8008_data {
>>>>>>>>>>>>>>> -	struct device *dev;
>>>>>>>>>>>>>>> -	struct regmap *regmap;
>>>>>>>>>>>>>>> -	int irq;
>>>>>>>>>>>>>>> -	struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>>>> -};
>>>>>>>>>>>>>>> -
>>>>>>>>>>>>>>>          static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
>>>>>>>>>>>>>>>          static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
>>>>>>>>>>>>>>>          static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
>>>>>>>>>>>>>>> @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = {
>>>>>>>>>>>>>>>          	.max_register	= 0xFFFF,
>>>>>>>>>>>>>>>          };
>>>>>>>>>>>>>>> -static int pm8008_init(struct pm8008_data *chip)
>>>>>>>>>>>>>>> +static int pm8008_init(struct regmap *regmap)
>>>>>>>>>>>>>>>          {
>>>>>>>>>>>>>>>          	int rc;
>>>>>>>>>>>>>>> @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip)
>>>>>>>>>>>>>>>          	 * This is required to enable the writing of TYPE registers in
>>>>>>>>>>>>>>>          	 * regmap_irq_sync_unlock().
>>>>>>>>>>>>>>>          	 */
>>>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>>>> -			 (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
>>>>>>>>>>>>>>> -			 BIT(0));
>>>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>>>          	if (rc)
>>>>>>>>>>>>>>>          		return rc;
>>>>>>>>>>>>>>>          	/* Do the same for GPIO1 and GPIO2 peripherals */
>>>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>>>> -			 (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>>>          	if (rc)
>>>>>>>>>>>>>>>          		return rc;
>>>>>>>>>>>>>>> -	rc = regmap_write(chip->regmap,
>>>>>>>>>>>>>>> -			 (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>>> +	rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
>>>>>>>>>>>>>>>          	return rc;
>>>>>>>>>>>>>>>          }
>>>>>>>>>>>>>>> -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>>>> +static int pm8008_probe_irq_peripherals(struct device *dev,
>>>>>>>>>>>>>>> +					struct regmap *regmap,
>>>>>>>>>>>>>>>          					int client_irq)
>>>>>>>>>>>>>>>          {
>>>>>>>>>>>>>>>          	int rc, i;
>>>>>>>>>>>>>>>          	struct regmap_irq_type *type;
>>>>>>>>>>>>>>>          	struct regmap_irq_chip_data *irq_data;
>>>>>>>>>>>>>>> -	rc = pm8008_init(chip);
>>>>>>>>>>>>>>> +	rc = pm8008_init(regmap);
>>>>>>>>>>>>>>>          	if (rc) {
>>>>>>>>>>>>>>> -		dev_err(chip->dev, "Init failed: %d\n", rc);
>>>>>>>>>>>>>>> +		dev_err(dev, "Init failed: %d\n", rc);
>>>>>>>>>>>>>>>          		return rc;
>>>>>>>>>>>>>>>          	}
>>>>>>>>>>>>>>> @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>>>>          				IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
>>>>>>>>>>>>>>>          	}
>>>>>>>>>>>>>>> -	rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
>>>>>>>>>>>>>>> +	rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
>>>>>>>>>>>>>>>          			IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
>>>>>>>>>>>>>>>          	if (rc) {
>>>>>>>>>>>>>>> -		dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>>>>>>>>> +		dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
>>>>>>>>>>>>>>>          		return rc;
>>>>>>>>>>>>>>>          	}
>>>>>>>>>>>>>>> @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
>>>>>>>>>>>>>>>          static int pm8008_probe(struct i2c_client *client)
>>>>>>>>>>>>>>>          {
>>>>>>>>>>>>>>>          	int rc;
>>>>>>>>>>>>>>> -	struct pm8008_data *chip;
>>>>>>>>>>>>>>> -
>>>>>>>>>>>>>>> -	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
>>>>>>>>>>>>>>> -	if (!chip)
>>>>>>>>>>>>>>> -		return -ENOMEM;
>>>>>>>>>>>>>>> +	struct device *dev;
>>>>>>>>>>>>>>> +	struct regmap *regmap;
>>>>>>>>>>>>>>> -	chip->dev = &client->dev;
>>>>>>>>>>>>>>> -	chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>>>>>>>>>> -	if (!chip->regmap)
>>>>>>>>>>>>>>> +	dev = &client->dev;
>>>>>>>>>>>>>>> +	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
>>>>>>>>>>>>>>> +	if (!regmap)
>>>>>>>>>>>>>>>          		return -ENODEV;
>>>>>>>>>>>>>>> -	i2c_set_clientdata(client, chip);
>>>>>>>>>>>>>>> +	i2c_set_clientdata(client, regmap);
>>>>>>>>>>>>> Here ^
>>>>>>>>>>>> I have added a dummy device and set the client data by passing regmap, see
>>>>>>>>>>>> below:
>>>>>>>>>>>>
>>>>>>>>>>>> +       regulators_client = i2c_new_dummy_device(client->adapter,
>>>>>>>>>>>> client->addr + 1);
>>>>>>>>>>>> +       if (IS_ERR(regulators_client)) {
>>>>>>>>>>>> +               dev_err(dev, "can't attach client\n");
>>>>>>>>>>>> +               return PTR_ERR(regulators_client);
>>>>>>>>>>>> +       }
>>>>>>>>>>>> +
>>>>>>>>>>>> +       regulators_regmap = devm_regmap_init_i2c(regulators_client,
>>>>>>>>>>>> &qcom_mfd_regmap_cfg[1]);
>>>>>>>>>>>> +       if (!regmap)
>>>>>>>>>>>> +               return -ENODEV;
>>>>>>>>>>>> +
>>>>>>>>>>>> +       i2c_set_clientdata(client, regulators_regmap);
>>>>>>>>>>>>
>>>>>>>>>>>> Now if i try to get this regmap from regulator driver by doing
>>>>>>>>>>>>
>>>>>>>>>>>> struct regmap *regmap = dev_get_drvdata(pdev->dev.parent);
>>>>>>>>>>>>
>>>>>>>>>>>> it still gets me the regmap of pm8008@8 device and not the regulator device
>>>>>>>>>>>> regmap (0x9). Not sure if I'm missing something here.
>>>>>>>>>>> So you need to pass 2 regmap pointers?
>>>>>>>>>>>
>>>>>>>>>>> If you need to pass more than one item to the child devices, you do
>>>>>>>>>>> need to use a struct for that.
>>>>>>>>>> I need to pass only one regmap out of the two, but i am not able to retrieve
>>>>>>>>>> the correct regmap simply by doing i2c_set_clientdata
>>>>>>>>>>
>>>>>>>>>> probably because we are having all the child nodes under same DT node and
>>>>>>>>>> thus not able to distinguish based on the dev pointer
>>>>>>>>> You can only pull out (get) the pointer that you put in (set).
>>>>>>>>>
>>>>>>>>> Unless you over-wrote it later in the thread of execution, you are
>>>>>>>>> pulling out whatever regulators_regmap happens to be.
>>>>>>>>>
>>>>>>>>> Is qcom_mfd_regmap_cfg[1] definitely the one you want?
>>>>>>>> Yes, I need qcom_mfd_regmap_cfg[1]
>>>>>>>>
>>>>>>>> Pasting code snippet for reference:
>>>>>>>>
>>>>>>>> static struct regmap_config qcom_mfd_regmap_cfg[2] = {
>>>>>>>>          {
>>>>>>>>
>>>>>>>>              .name = "infra",
>>>>>>>>              .reg_bits   = 16,
>>>>>>>>              .val_bits   = 8,
>>>>>>>>              .max_register   = 0xFFFF,
>>>>>>>>          },
>>>>>>>>          {
>>>>>>>>              .name = "regulators",
>>>>>>>>              .reg_bits   = 16,
>>>>>>>>              .val_bits   = 8,
>>>>>>>>              .max_register   = 0xFFFF,
>>>>>>>>          },
>>>>>>>>
>>>>>>>> };
>>>>>>>>
>>>>>>>>
>>>>>>>> Inside pm8008_probe:
>>>>>>>>
>>>>>>>>
>>>>>>>>          regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg[0]);
>>>>>>>>          if (!regmap)
>>>>>>>>              return -ENODEV;
>>>>>>>>
>>>>>>>>          i2c_set_clientdata(client, regmap);
>>>>>>>>
>>>>>>>>
>>>>>>>>          regulators_client = i2c_new_dummy_device(client->adapter, client->addr
>>>>>>>> + 1);
>>>>>>>>          if (IS_ERR(regulators_client)) {
>>>>>>>>              dev_err(dev, "can't attach client\n");
>>>>>>>>              return PTR_ERR(regulators_client);
>>>>>>>>          }
>>>>>>>>
>>>>>>>>          regulators_regmap = devm_regmap_init_i2c(regulators_client,
>>>>>>>> &qcom_mfd_regmap_cfg[1]);
>>>>>>>>          if (!regmap)
>>>>>>>>              return -ENODEV;
>>>>>>>>
>>>>>>>>          i2c_set_clientdata(regulators_client, regulators_regmap);
>>>>>>> You can't call this twice.
>>>>>>>
>>>>>>> Doing so with over-write regmap with regulators_regmap.
>>>>>>>
>>>>>>> You said you only needed one?
>>>>>>>
>>>>>>>       "I need to pass only one regmap out of the two, but i am not able to retrieve"
>>>>>> I thought you asked whether we have to pass two regmaps to the child
>>>>>> regulator driver.
>>>>> Yes, that's what I was asking.
>>>>>
>>>>> So you only need to pass 'regulators_regmap' (derived from
>>>>> "regulators") right?
>>>> Yes
>>>>
>>>>
>>>>> In that case, keep:
>>>>>
>>>>>      i2c_set_clientdata(regulators_client, regulators_regmap);
>>>>>
>>>>> ... and drop:
>>>>>
>>>>>      i2c_set_clientdata(client, regmap);
>>>> Dropping this did not help, it says regmap is NULL. Can we drop this? we
>>> If it's NULL coming out, it was NULL going in.
>>>
>>> Does it get checked before setting it?
>>>
>>> Are you getting it from the right device?
>>>
>>>> might still need it for other child peripherals like gpios?
>>>>
>>>> Also, setting the data through different clients would still overwrite the
>>>> data? I thought it would be written to respective client->dev.
>>> It does, but you are fetching it back out from the parent, right?
>>>
>>>     const struct pm8008_data *chip = dev_get_drvdata(pdev->dev.parent);
>>>
>>> Which is only one device.
>>>
>>> If you want to set the child's data, then that is usually accomplished
>>> using platform_data (you can do this using the MFD API - see struct
>>> mfd_cell), not driver_data.
>>>
>>>>>>>> In qcom-pm8008-regulator.c I tried to get the regmap using
>>>>>>>>
>>>>>>>> dev_get_regmap(pdev->dev.parent, "regulators");
>>>>>>> I haven't looked at this API before.  I suggest that this would be
>>>>>>> used *instead* of passing the regmap pointer via driver_data.
>>>>>>>
>>>>>>> It looks like you're using different devices to init your regmaps;
>>>>>>> 'client' and 'regulator_client' (derived from client->adapter).
>>>>>>>
>>>>>>> "regulators" is registered using regulators_regmap which was *not*
>>>>>>> init'ed with pdev->dev.parent (same as client->dev), so trying to
>>>>>>> dev_get_regmap() with that device pointer will not work.
>>>>>> Okay, So I will leave the driver as is then?
>>>>> Right, let's take a step back and try to clarify a few things here.
>>>>>
>>>>> What is the purpose of the two regmaps that you're creating here?
>>>> The pm8008 chip is an I2C based pmic which has 2 address spaces 0x8 and 0x9.
>>>>
>>>>> Where will each of them be used?
>>>> Under the 0x8 address space peripherals like gpio, temp-alarm etc will be
>>>> present and under the 0x9 regulators are present.
>>>>
>>>>> Regmaps created in MFD are usually either used only locally, here in
>>>>> the parent driver or shared amongst *multiple* children.  If that is
>>>>> not the case for regulators_regmap, which looks suspiciously like it's
>>>>> only used in the Regulator driver, then why not initialise the regmap
>>>>> there instead?  Rather than pointlessly creating it here and passing
>>>>> it via the driver_data pointer.
>>>> Initially we implemented below design
>>>>
>>>> [V4,5/6] arm64: dts: qcom: pm8008: Add base dts file - Patchwork
>>>> (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1637314953-4215-6-git-send-email-quic_c_skakit@quicinc.com/>
>>>>
>>>> As per Mark's suggestions I've dropped the compatible for regulator driver
>>>> and registered the regulators through mfd driver.
>>> If the regmap is _only_ used in the regulator driver, it should be
>>> initialised there.
>>>
>>> I suggest you move all of this regmap set-up into the Regulator
>>> driver and have done with it.
>> Hi Lee,
>>
>>
>> Are you suggesting we should use i2c_new_dummy_device() to register the 0x9
>> device and then use mfd_cell struct to register the LDOs(it's children)?
>>
>>
>>   static const struct mfd_cell pm8008_regulator_dev = {
>>           .of_compatible = "qcom,pm8008-regulator",
>>   };
>>
>>
>> Inside probe:
>>
>>     regulators_client = i2c_new_dummy_device(client->adapter, client->addr +
>> 1);
>>
>>      if (IS_ERR(regulators_client)) {
>>           dev_err(dev, "can't attach client\n");
>>           return PTR_ERR(regulators_client);
>>       }
>>
>>       pm8008_regulator_dev.platform_data =
>> dev_get_platdata(&regulators_client->dev);
>>
>>       rc = devm_mfd_add_devices(&regulators_client->dev, 0,
>> pm8008_regulator_dev, 7, NULL, 0, NULL);
>>       if (rc) {
>>           dev_err(chip->dev, "Failed to add regulator device: %d\n", rc);
>>           return rc;
>>       }
>>
>> but still i am not clear on how this works and how do we get the platform
>> data in the regulator driver. Could you please help me to proceed further
> Okay, so I've taken some time to read through your previous
> submissions to see how we ended up down this rabbit hole.
>
> Essentially, it looks to me like the 2 I2C devices should be kept
> separate and the Regulator driver should be registered/probed without
> requiring this I2C dummy device hoop jumping exercise.


I have implemented this design based on the suggestions on V9 by Mark 
and Stephen.


> As Stephen asked in v9 [0], why can't the regulator driver be I2C?
>
> Then it can manage its own resources and all of this craziness can be
> avoided.
>
> That's not to say that the v9 submission was the right way to go
> either.  Everything in relation to:
>
>    i2c_add_driver(&pm8008_regulators_driver);
>
> ... should be moved into the Regulator driver itself.


Mark/Stephen,


Could you please share your inputs on this approach?


> [0] https://lore.kernel.org/all/CAE-0n53G-atsuwqcgNvi3nvWyiO3P=pSj5zDUMYj0ELVYJE54Q@mail.gmail.com/
>
Mark Brown July 13, 2022, 1:14 p.m. UTC | #22
On Wed, Jul 13, 2022 at 11:20:43AM +0530, Satya Priya Kakitapalli (Temp) wrote:
> On 7/12/2022 6:17 PM, Lee Jones wrote:
> > On Mon, 11 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > 
> > > On 7/4/2022 6:19 PM, Lee Jones wrote:
> > > > On Mon, 04 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > 
> > > > > On 7/1/2022 2:42 PM, Lee Jones wrote:
> > > > > > On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > 
> > > > > > > On 7/1/2022 1:24 PM, Lee Jones wrote:
> > > > > > > > On Fri, 01 Jul 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > 
> > > > > > > > > On 6/30/2022 4:04 PM, Lee Jones wrote:
> > > > > > > > > > On Thu, 30 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:
> > > > > > > > > > 
> > > > > > > > > > > On 6/29/2022 8:48 PM, Lee Jones wrote:
> > > > > > > > > > > > On Wed, 29 Jun 2022, Satya Priya Kakitapalli (Temp) wrote:

Please delete unneeded context from mails when replying.  Doing this
makes it much easier to find your reply in the message, helping ensure
it won't be missed by people scrolling through the irrelevant quoted
material.

> > That's not to say that the v9 submission was the right way to go
> > either.  Everything in relation to:
> > 
> >    i2c_add_driver(&pm8008_regulators_driver);
> > 
> > ... should be moved into the Regulator driver itself.

> Mark/Stephen,
> 
> 
> Could you please share your inputs on this approach?

I don't have particularly strong opinions.  It does seem like the chip
should be visible as being a single entity in DT if it's a single
physical thing in the schematic and board.
Satya Priya Kakitapalli (Temp) July 22, 2022, 6:31 a.m. UTC | #23
Hi Lee,

> Okay, so I've taken some time to read through your previous
> submissions to see how we ended up down this rabbit hole.
>
> Essentially, it looks to me like the 2 I2C devices should be kept
> separate and the Regulator driver should be registered/probed without
> requiring this I2C dummy device hoop jumping exercise.
>
> As Stephen asked in v9 [0], why can't the regulator driver be I2C?
>
> Then it can manage its own resources and all of this craziness can be
> avoided.
>
> That's not to say that the v9 submission was the right way to go
> either.  Everything in relation to:
>
>    i2c_add_driver(&pm8008_regulators_driver);
>
> ... should be moved into the Regulator driver itself.


So, IIUC, we need to register the regulator driver as an i2c_driver and 
do all the regmap init stuff in its probe, and not touch the mfd 
driver(apart from adding reset-gpios).

Then the DT would be simply:

&pm8008_bus {
     pm8008: pm8008@8 {
         compatible = "qcom,pm8008";
         reg = <0x8>;
         #address-cells = <1>;
         #size-cells = <0>;
         #interrupt-cells = <2>;
     };

     pm8008_regulators: pm8008@9 {
         compatible = "qcom,pm8008-regulators";
         reg = <0x9>;
         #address-cells = <0>;
         #size-cells = <0>;

         pm8008_l1: ldo1@4000 {
             reg = <0x4000>;
             regulator-name = "pm8008_l1";
         };

         pm8008_l2: ldo2@4100 {
             reg = <0x4100>;
             regulator-name = "pm8008_l2";
         };

         pm8008_l3: ldo3@4200 {
             reg = <0x4200>;
             regulator-name = "pm8008_l3";
         };

         pm8008_l4: ldo4@4300 {
             reg = <0x4300>;
             regulator-name = "pm8008_l4";
         };

         pm8008_l5: ldo5@4400 {
             reg = <0x4400>;
             regulator-name = "pm8008_l5";
         };

         pm8008_l6: ldo6@4500 {
             reg = <0x4500>;
             regulator-name = "pm8008_l6";
         };

         pm8008_l7: ldo7@4600 {
             reg = <0x4600>;
             regulator-name = "pm8008_l7";
         };
     };
};


Stephen/Mark, Please do let me know if you are OK with this design.
Stephen Boyd July 27, 2022, 1:19 a.m. UTC | #24
Quoting Satya Priya Kakitapalli (Temp) (2022-07-21 23:31:16)
>
>              regulator-name = "pm8008_l6";
>          };
>
>          pm8008_l7: ldo7@4600 {
>              reg = <0x4600>;
>              regulator-name = "pm8008_l7";
>          };
>      };
> };
>
>
> Stephen/Mark, Please do let me know if you are OK with this design.
>

I was happy with the previous version of the DT node. That had one node
for the "pm8008 chip", which is important because it really is one
package. Why isn't that possible to implement and also register i2c
devices on the i2c bus for the second address?
Lee Jones Aug. 5, 2022, 10:51 a.m. UTC | #25
On Tue, 02 Aug 2022, Satya Priya Kakitapalli (Temp) wrote:

> 
> On 7/27/2022 6:49 AM, Stephen Boyd wrote:
> > Quoting Satya Priya Kakitapalli (Temp) (2022-07-21 23:31:16)
> > >               regulator-name = "pm8008_l6";
> > >           };
> > > 
> > >           pm8008_l7: ldo7@4600 {
> > >               reg = <0x4600>;
> > >               regulator-name = "pm8008_l7";
> > >           };
> > >       };
> > > };
> > > 
> > > 
> > > Stephen/Mark, Please do let me know if you are OK with this design.
> > > 
> > I was happy with the previous version of the DT node. That had one node
> > for the "pm8008 chip", which is important because it really is one
> > package. Why isn't that possible to implement and also register i2c
> > devices on the i2c bus for the second address?

If devices have different addresses, they should have their own nodes, no?

> If we add everything under single DT node i.e., 0x8 device, then, we have to
> use i2c_new_dummy_device() to register 0x9 device, and pass regmap etc to
> child(which Lee is not OK with). Even if I register the regulators as i2c
> devices, I am not sure how we can retrieve the 0x9 regmap in the LDO probe,
> because when I use dev->parent there, it refers to 0x8, as I am adding
> everything under 0x8.
> 
> 
> To implement what Lee suggested here [1], I will have to add two devices
> separately in the DT.
> 
> [V15,6/9] mfd: pm8008: Use i2c_new_dummy_device() API - Patchwork
> (kernel.org) <https://patchwork.kernel.org/project/linux-arm-msm/patch/1655200111-18357-7-git-send-email-quic_c_skakit@quicinc.com/#24933901>
Stephen Boyd Aug. 8, 2022, 7:09 p.m. UTC | #26
Quoting Lee Jones (2022-08-05 03:51:39)
> On Tue, 02 Aug 2022, Satya Priya Kakitapalli (Temp) wrote:
>
> >
> > On 7/27/2022 6:49 AM, Stephen Boyd wrote:
> > > Quoting Satya Priya Kakitapalli (Temp) (2022-07-21 23:31:16)
> > > >               regulator-name = "pm8008_l6";
> > > >           };
> > > >
> > > >           pm8008_l7: ldo7@4600 {
> > > >               reg = <0x4600>;
> > > >               regulator-name = "pm8008_l7";
> > > >           };
> > > >       };
> > > > };
> > > >
> > > >
> > > > Stephen/Mark, Please do let me know if you are OK with this design.
> > > >
> > > I was happy with the previous version of the DT node. That had one node
> > > for the "pm8008 chip", which is important because it really is one
> > > package. Why isn't that possible to implement and also register i2c
> > > devices on the i2c bus for the second address?
>
> If devices have different addresses, they should have their own nodes, no?

There are nodes for the devices at different addresses in the design we
had settled on earlier.

        pm8008: pmic@8 {
                compatible = "qcom,pm8008";
                reg = <0x8>;
                #address-cells = <2>;
                #size-cells = <0>;
                #interrupt-cells = <2>;

                pm8008_l1: ldo1@1,4000 {
                        compatible = "qcom,pm8008-regulator";
                        reg = <0x1 0x4000>;
                        regulator-name = "pm8008_ldo1";
                };

		...

	};

pmic@8 is the i2c device at i2c address 8. ldo1@1,4000 is the i2c device
at address 9 (8 + 1) with control for ldo1 at register offset 0x4000.

I think your concern is more about the fact that the regulator sub-nodes
are platform device drivers instead of i2c device drivers. I'm not an
i2c expert but from what I can tell we only describe one i2c address in
DT and then do something like this to describe the other i2c addresses
when one physical chip responds to multiple addresses on the i2c bus.
See i2c_new_dummy_device() and i2c_new_ancillary_device() kerneldoc for
slightly more background.

It may need some modifications to the i2c core to make the regulator
nodes into i2c devices. I suspect the qcom,pm8008 i2c driver needs to
look at the 'reg' property and translate that to the parent node's reg
property (8) plus the first cell (1) to determine the i2c device's final
i2c address. Then the i2c core needs to register i2c devices that are
bound to the lifetime of the "primary" i2c device (pmic@8). The driver
for the regulator can parse the second cell of the reg property to
determine the register offset within that i2c address to use to control
the regulator. That would make it possible to create an i2c device for
each regulator node, but I don't think that is correct because the
second reg property isn't an i2c address, it's a register offset inside
the i2c address.

It sort of looks like we need to use i2c_new_ancillary_device() here. IF
we did that the DT would look like this:

        pm8008: pmic@8 {
                compatible = "qcom,pm8008";
                reg = <0x8>, <0x9>;
		reg-names = "core", "regulators";
                #address-cells = <2>;
                #size-cells = <0>;
                #interrupt-cells = <2>;

                pm8008_l1: ldo1@1,4000 {
                        compatible = "qcom,pm8008-regulator";
                        reg = <0x1 0x4000>;
                        regulator-name = "pm8008_ldo1";
                };

		...

	};

And a dummy i2c device would be created for i2c address 0x9 bound to the
dummy i2c driver when we called i2c_new_ancillary_device() with
"regulators" for the name. The binding of the dummy driver is preventing
us from binding another i2c driver to the i2c address. Why can't we call
i2c_new_client_device() but avoid binding a dummy driver to it like
i2c_new_ancillary_device() does? If that can be done, then the single
i2c device at 0x9 can be a pm8008-regulators (plural) device that probes
a single i2c driver that parses the subnodes looking for regulator
nodes.

Note: There is really one i2c device at address 0x9, that corresponds to
the regulators, but in DT we need to have one node per regulator so we
can configure constraints.
Satya Priya Kakitapalli (Temp) Aug. 16, 2022, 3:41 a.m. UTC | #27
Hi Lee,


Could you please share your thoughts on this?


On 8/9/2022 12:39 AM, Stephen Boyd wrote:
> Quoting Lee Jones (2022-08-05 03:51:39)
>
>>>> I was happy with the previous version of the DT node. That had one node
>>>> for the "pm8008 chip", which is important because it really is one
>>>> package. Why isn't that possible to implement and also register i2c
>>>> devices on the i2c bus for the second address?
>> If devices have different addresses, they should have their own nodes, no?
> There are nodes for the devices at different addresses in the design we
> had settled on earlier.
>
>          pm8008: pmic@8 {
>                  compatible = "qcom,pm8008";
>                  reg = <0x8>;
>                  #address-cells = <2>;
>                  #size-cells = <0>;
>                  #interrupt-cells = <2>;
>
>                  pm8008_l1: ldo1@1,4000 {
>                          compatible = "qcom,pm8008-regulator";
>                          reg = <0x1 0x4000>;
>                          regulator-name = "pm8008_ldo1";
>                  };
>
> 		...
>
> 	};
>
> pmic@8 is the i2c device at i2c address 8. ldo1@1,4000 is the i2c device
> at address 9 (8 + 1) with control for ldo1 at register offset 0x4000.
>
> I think your concern is more about the fact that the regulator sub-nodes
> are platform device drivers instead of i2c device drivers. I'm not an
> i2c expert but from what I can tell we only describe one i2c address in
> DT and then do something like this to describe the other i2c addresses
> when one physical chip responds to multiple addresses on the i2c bus.
> See i2c_new_dummy_device() and i2c_new_ancillary_device() kerneldoc for
> slightly more background.
>
> It may need some modifications to the i2c core to make the regulator
> nodes into i2c devices. I suspect the qcom,pm8008 i2c driver needs to
> look at the 'reg' property and translate that to the parent node's reg
> property (8) plus the first cell (1) to determine the i2c device's final
> i2c address. Then the i2c core needs to register i2c devices that are
> bound to the lifetime of the "primary" i2c device (pmic@8). The driver
> for the regulator can parse the second cell of the reg property to
> determine the register offset within that i2c address to use to control
> the regulator. That would make it possible to create an i2c device for
> each regulator node, but I don't think that is correct because the
> second reg property isn't an i2c address, it's a register offset inside
> the i2c address.
>
> It sort of looks like we need to use i2c_new_ancillary_device() here. IF
> we did that the DT would look like this:
>
>          pm8008: pmic@8 {
>                  compatible = "qcom,pm8008";
>                  reg = <0x8>, <0x9>;
> 		reg-names = "core", "regulators";
>                  #address-cells = <2>;
>                  #size-cells = <0>;
>                  #interrupt-cells = <2>;
>
>                  pm8008_l1: ldo1@1,4000 {
>                          compatible = "qcom,pm8008-regulator";
>                          reg = <0x1 0x4000>;
>                          regulator-name = "pm8008_ldo1";
>                  };
>
> 		...
>
> 	};
>
> And a dummy i2c device would be created for i2c address 0x9 bound to the
> dummy i2c driver when we called i2c_new_ancillary_device() with
> "regulators" for the name. The binding of the dummy driver is preventing
> us from binding another i2c driver to the i2c address. Why can't we call
> i2c_new_client_device() but avoid binding a dummy driver to it like
> i2c_new_ancillary_device() does? If that can be done, then the single
> i2c device at 0x9 can be a pm8008-regulators (plural) device that probes
> a single i2c driver that parses the subnodes looking for regulator
> nodes.
>
> Note: There is really one i2c device at address 0x9, that corresponds to
> the regulators, but in DT we need to have one node per regulator so we
> can configure constraints.
Lee Jones Sept. 28, 2022, 10:20 a.m. UTC | #28
On Mon, 08 Aug 2022, Stephen Boyd wrote:

> Quoting Lee Jones (2022-08-05 03:51:39)
> > On Tue, 02 Aug 2022, Satya Priya Kakitapalli (Temp) wrote:
> >
> > >
> > > On 7/27/2022 6:49 AM, Stephen Boyd wrote:
> > > > Quoting Satya Priya Kakitapalli (Temp) (2022-07-21 23:31:16)
> > > > >               regulator-name = "pm8008_l6";
> > > > >           };
> > > > >
> > > > >           pm8008_l7: ldo7@4600 {
> > > > >               reg = <0x4600>;
> > > > >               regulator-name = "pm8008_l7";
> > > > >           };
> > > > >       };
> > > > > };
> > > > >
> > > > >
> > > > > Stephen/Mark, Please do let me know if you are OK with this design.
> > > > >
> > > > I was happy with the previous version of the DT node. That had one node
> > > > for the "pm8008 chip", which is important because it really is one
> > > > package. Why isn't that possible to implement and also register i2c
> > > > devices on the i2c bus for the second address?
> >
> > If devices have different addresses, they should have their own nodes, no?
> 
> There are nodes for the devices at different addresses in the design we
> had settled on earlier.
> 
>         pm8008: pmic@8 {
>                 compatible = "qcom,pm8008";
>                 reg = <0x8>;
>                 #address-cells = <2>;
>                 #size-cells = <0>;
>                 #interrupt-cells = <2>;
> 
>                 pm8008_l1: ldo1@1,4000 {
>                         compatible = "qcom,pm8008-regulator";
>                         reg = <0x1 0x4000>;
>                         regulator-name = "pm8008_ldo1";
>                 };
> 
> 		...
> 
> 	};
> 
> pmic@8 is the i2c device at i2c address 8. ldo1@1,4000 is the i2c device
> at address 9 (8 + 1) with control for ldo1 at register offset 0x4000.
> 
> I think your concern is more about the fact that the regulator sub-nodes
> are platform device drivers instead of i2c device drivers. I'm not an
> i2c expert but from what I can tell we only describe one i2c address in
> DT and then do something like this to describe the other i2c addresses
> when one physical chip responds to multiple addresses on the i2c bus.
> See i2c_new_dummy_device() and i2c_new_ancillary_device() kerneldoc for
> slightly more background.
> 
> It may need some modifications to the i2c core to make the regulator
> nodes into i2c devices. I suspect the qcom,pm8008 i2c driver needs to
> look at the 'reg' property and translate that to the parent node's reg
> property (8) plus the first cell (1) to determine the i2c device's final
> i2c address. Then the i2c core needs to register i2c devices that are
> bound to the lifetime of the "primary" i2c device (pmic@8). The driver
> for the regulator can parse the second cell of the reg property to
> determine the register offset within that i2c address to use to control
> the regulator. That would make it possible to create an i2c device for
> each regulator node, but I don't think that is correct because the
> second reg property isn't an i2c address, it's a register offset inside
> the i2c address.
> 
> It sort of looks like we need to use i2c_new_ancillary_device() here. IF
> we did that the DT would look like this:
> 
>         pm8008: pmic@8 {
>                 compatible = "qcom,pm8008";
>                 reg = <0x8>, <0x9>;
> 		reg-names = "core", "regulators";
>                 #address-cells = <2>;
>                 #size-cells = <0>;
>                 #interrupt-cells = <2>;
> 
>                 pm8008_l1: ldo1@1,4000 {
>                         compatible = "qcom,pm8008-regulator";
>                         reg = <0x1 0x4000>;
>                         regulator-name = "pm8008_ldo1";
>                 };
> 
> 		...
> 
> 	};
> 
> And a dummy i2c device would be created for i2c address 0x9 bound to the
> dummy i2c driver when we called i2c_new_ancillary_device() with
> "regulators" for the name. The binding of the dummy driver is preventing
> us from binding another i2c driver to the i2c address. Why can't we call
> i2c_new_client_device() but avoid binding a dummy driver to it like
> i2c_new_ancillary_device() does? If that can be done, then the single
> i2c device at 0x9 can be a pm8008-regulators (plural) device that probes
> a single i2c driver that parses the subnodes looking for regulator
> nodes.
> 
> Note: There is really one i2c device at address 0x9, that corresponds to
> the regulators, but in DT we need to have one node per regulator so we
> can configure constraints.

Wouldn't it make more sense to simply separate the instantiation of
the 2 I2C devices?  Similar to what you suggested [0] in v9.  That way
they can handle their own resources and we can avoid all of the I2C
dummy / shared Regmap passing faff.

[0] https://lore.kernel.org/all/CAE-0n53G-atsuwqcgNvi3nvWyiO3P=pSj5zDUMYj0ELVYJE54Q@mail.gmail.com/
Stephen Boyd Sept. 29, 2022, 1:20 a.m. UTC | #29
Quoting Lee Jones (2022-09-28 03:20:30)
> Wouldn't it make more sense to simply separate the instantiation of
> the 2 I2C devices?  Similar to what you suggested [0] in v9.  That way
> they can handle their own resources and we can avoid all of the I2C
> dummy / shared Regmap passing faff.
>
> [0] https://lore.kernel.org/all/CAE-0n53G-atsuwqcgNvi3nvWyiO3P=pSj5zDUMYj0ELVYJE54Q@mail.gmail.com/
>

You can continue reading the thread[1]. My understanding is it's one
chip that responds on two i2c addresses, thus we don't describe that as
two i2c device nodes in DT. Instead we describe one node and use the
dummy API to make the second i2c device.

[1] https://lore.kernel.org/all/Yk3NkNK3e+fgj4eG@sirena.org.uk/
Lee Jones Sept. 29, 2022, 6:01 p.m. UTC | #30
On Wed, 28 Sep 2022, Stephen Boyd wrote:

> Quoting Lee Jones (2022-09-28 03:20:30)
> > Wouldn't it make more sense to simply separate the instantiation of
> > the 2 I2C devices?  Similar to what you suggested [0] in v9.  That way
> > they can handle their own resources and we can avoid all of the I2C
> > dummy / shared Regmap passing faff.
> >
> > [0] https://lore.kernel.org/all/CAE-0n53G-atsuwqcgNvi3nvWyiO3P=pSj5zDUMYj0ELVYJE54Q@mail.gmail.com/
> >
> 
> You can continue reading the thread[1]. My understanding is it's one
> chip that responds on two i2c addresses, thus we don't describe that as
> two i2c device nodes in DT. Instead we describe one node and use the
> dummy API to make the second i2c device.
> 
> [1] https://lore.kernel.org/all/Yk3NkNK3e+fgj4eG@sirena.org.uk/

As Mark says, it's probably 2 separate dies that have been encased in
the same IC and are otherwise unconnected.  Not sure I understand the
comment about not requiring another 'struct device'.  It will still
require that whether it's a platform device or an I2C device, right?
Stephen Boyd Oct. 3, 2022, 6:47 p.m. UTC | #31
Quoting Lee Jones (2022-09-29 11:01:41)
> On Wed, 28 Sep 2022, Stephen Boyd wrote:
>
> > Quoting Lee Jones (2022-09-28 03:20:30)
> > > Wouldn't it make more sense to simply separate the instantiation of
> > > the 2 I2C devices?  Similar to what you suggested [0] in v9.  That way
> > > they can handle their own resources and we can avoid all of the I2C
> > > dummy / shared Regmap passing faff.
> > >
> > > [0] https://lore.kernel.org/all/CAE-0n53G-atsuwqcgNvi3nvWyiO3P=pSj5zDUMYj0ELVYJE54Q@mail.gmail.com/
> > >
> >
> > You can continue reading the thread[1]. My understanding is it's one
> > chip that responds on two i2c addresses, thus we don't describe that as
> > two i2c device nodes in DT. Instead we describe one node and use the
> > dummy API to make the second i2c device.
> >
> > [1] https://lore.kernel.org/all/Yk3NkNK3e+fgj4eG@sirena.org.uk/
>
> As Mark says, it's probably 2 separate dies that have been encased in
> the same IC and are otherwise unconnected.  Not sure I understand the
> comment about not requiring another 'struct device'.  It will still
> require that whether it's a platform device or an I2C device, right?
>

Yes a 'struct device' will be required for each i2c address no matter
what happens.

It is also useful to describe the hardware as one device node in case
there is a shared reset signal or power supply. That allows us to have
one driver probe the DT node and deassert the reset/power the chip on. I
think this device has one reset signal, so we really need to do this and
not treat them as completely independent i2c devices (the 0x8 and 0x9
addresses).

Can we move forward with my plan to have another i2c device made for
'pm8008-regulators' and have that driver be an i2c driver that probes an
i2c device manually created in the pm8008 driver? I think that would
handle the reset ordering problem because the pm8008 driver can deassert
the reset and also handle the regmap passing stuff by letting the i2c
device at 0x9 make its own regmap.
Lee Jones Oct. 4, 2022, 11:41 a.m. UTC | #32
On Mon, 03 Oct 2022, Stephen Boyd wrote:

> Quoting Lee Jones (2022-09-29 11:01:41)
> > On Wed, 28 Sep 2022, Stephen Boyd wrote:
> >
> > > Quoting Lee Jones (2022-09-28 03:20:30)
> > > > Wouldn't it make more sense to simply separate the instantiation of
> > > > the 2 I2C devices?  Similar to what you suggested [0] in v9.  That way
> > > > they can handle their own resources and we can avoid all of the I2C
> > > > dummy / shared Regmap passing faff.
> > > >
> > > > [0] https://lore.kernel.org/all/CAE-0n53G-atsuwqcgNvi3nvWyiO3P=pSj5zDUMYj0ELVYJE54Q@mail.gmail.com/
> > > >
> > >
> > > You can continue reading the thread[1]. My understanding is it's one
> > > chip that responds on two i2c addresses, thus we don't describe that as
> > > two i2c device nodes in DT. Instead we describe one node and use the
> > > dummy API to make the second i2c device.
> > >
> > > [1] https://lore.kernel.org/all/Yk3NkNK3e+fgj4eG@sirena.org.uk/
> >
> > As Mark says, it's probably 2 separate dies that have been encased in
> > the same IC and are otherwise unconnected.  Not sure I understand the
> > comment about not requiring another 'struct device'.  It will still
> > require that whether it's a platform device or an I2C device, right?
> >
> 
> Yes a 'struct device' will be required for each i2c address no matter
> what happens.
> 
> It is also useful to describe the hardware as one device node in case
> there is a shared reset signal or power supply. That allows us to have
> one driver probe the DT node and deassert the reset/power the chip on. I
> think this device has one reset signal, so we really need to do this and
> not treat them as completely independent i2c devices (the 0x8 and 0x9
> addresses).
> 
> Can we move forward with my plan to have another i2c device made for
> 'pm8008-regulators' and have that driver be an i2c driver that probes an
> i2c device manually created in the pm8008 driver? I think that would
> handle the reset ordering problem because the pm8008 driver can deassert
> the reset and also handle the regmap passing stuff by letting the i2c
> device at 0x9 make its own regmap.

Sure, why not.  I'm pretty done talking about this now. :)

Please work with Satya to cobble something together.
diff mbox series

Patch

diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
index 569ffd50..55e2a8e 100644
--- a/drivers/mfd/qcom-pm8008.c
+++ b/drivers/mfd/qcom-pm8008.c
@@ -9,6 +9,7 @@ 
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
+#include <linux/mfd/qcom_pm8008.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
@@ -57,6 +58,7 @@  enum {
 
 struct pm8008_data {
 	struct device *dev;
+	struct regmap *regulators_regmap;
 	int irq;
 	struct regmap_irq_chip_data *irq_data;
 };
@@ -150,6 +152,12 @@  static struct regmap_config qcom_mfd_regmap_cfg = {
 	.max_register	= 0xFFFF,
 };
 
+struct regmap *pm8008_get_regmap(const struct pm8008_data *chip)
+{
+	return chip->regulators_regmap;
+}
+EXPORT_SYMBOL_GPL(pm8008_get_regmap);
+
 static int pm8008_init(struct regmap *regmap)
 {
 	int rc;
@@ -217,11 +225,25 @@  static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
 	return 0;
 }
 
+static struct regmap *pm8008_regmap_init(struct i2c_client *client,
+							struct pm8008_data *chip)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
+	if (!regmap)
+		return NULL;
+
+	i2c_set_clientdata(client, chip);
+	return regmap;
+}
+
 static int pm8008_probe(struct i2c_client *client)
 {
 	int rc;
 	struct pm8008_data *chip;
 	struct gpio_desc *reset_gpio;
+	struct i2c_client *regulators_client;
 	struct regmap *regmap;
 
 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
@@ -229,11 +251,19 @@  static int pm8008_probe(struct i2c_client *client)
 		return -ENOMEM;
 
 	chip->dev = &client->dev;
-	regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
+	regmap = pm8008_regmap_init(client, chip);
 	if (!regmap)
 		return -ENODEV;
 
-	i2c_set_clientdata(client, chip);
+	regulators_client = i2c_new_dummy_device(client->adapter, client->addr + 1);
+	if (IS_ERR(regulators_client)) {
+		dev_err(&client->dev, "can't attach client\n");
+		return PTR_ERR(regulators_client);
+	}
+
+	chip->regulators_regmap = pm8008_regmap_init(regulators_client, chip);
+	if (!chip->regulators_regmap)
+		return -ENODEV;
 
 	reset_gpio = devm_gpiod_get(chip->dev, "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(reset_gpio))
diff --git a/include/linux/mfd/qcom_pm8008.h b/include/linux/mfd/qcom_pm8008.h
new file mode 100644
index 0000000..3814bff
--- /dev/null
+++ b/include/linux/mfd/qcom_pm8008.h
@@ -0,0 +1,9 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+#ifndef __QCOM_PM8008_H__
+#define __QCOM_PM8008_H__
+
+struct pm8008_data;
+struct regmap *pm8008_get_regmap(const struct pm8008_data *chip);
+
+#endif