diff mbox

[V3] ARM: shmobile: Rework the PMIC IRQ line quirk

Message ID 20180604175911.799-1-marek.vasut+renesas@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Marek Vasut June 4, 2018, 5:59 p.m. UTC
Rather than hard-coding the quirk topology, which stopped scaling,
parse the information from DT. The code looks for all compatible
PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
to the same pin. If so, the code sends a matching sequence to the
PMIC to deassert the IRQ.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Cc: Simon Horman <horms+renesas@verge.net.au>
Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>
Cc: linux-renesas-soc@vger.kernel.org
---
V2: - Replace the DT shared IRQ check loop with memcmp()
    - Send the I2C message to deassert the IRQ line to all PMICs
      in the list with shared IRQ line instead of just one
    - Add comment that this works only in case all the PMICs are
      on the same I2C bus
V3: - Drop the addr = 0x00 init
    - Drop reinit of argsa in rcar_gen2_regulator_quirk
---
 arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c | 114 ++++++++++++++++-----
 1 file changed, 90 insertions(+), 24 deletions(-)

Comments

Simon Horman June 5, 2018, 8:07 a.m. UTC | #1
On Mon, Jun 04, 2018 at 07:59:11PM +0200, Marek Vasut wrote:
> Rather than hard-coding the quirk topology, which stopped scaling,
> parse the information from DT. The code looks for all compatible
> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
> to the same pin. If so, the code sends a matching sequence to the
> PMIC to deassert the IRQ.
> 
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
> Cc: Geert Uytterhoeven <geert+renesas@glider.be>
> Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> Cc: Simon Horman <horms+renesas@verge.net.au>
> Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Cc: linux-renesas-soc@vger.kernel.org
> ---
> V2: - Replace the DT shared IRQ check loop with memcmp()
>     - Send the I2C message to deassert the IRQ line to all PMICs
>       in the list with shared IRQ line instead of just one
>     - Add comment that this works only in case all the PMICs are
>       on the same I2C bus
> V3: - Drop the addr = 0x00 init
>     - Drop reinit of argsa in rcar_gen2_regulator_quirk
> ---
>  arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c | 114 ++++++++++++++++-----
>  1 file changed, 90 insertions(+), 24 deletions(-)
> 
> diff --git a/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c b/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
> index 93f628acfd94..b919073aa27e 100644
> --- a/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
> +++ b/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
> @@ -31,8 +31,10 @@
>  #include <linux/i2c.h>
>  #include <linux/init.h>
>  #include <linux/io.h>
> +#include <linux/list.h>
>  #include <linux/notifier.h>
>  #include <linux/of.h>
> +#include <linux/of_irq.h>
>  #include <linux/mfd/da9063/registers.h>
>  
>  
> @@ -44,34 +46,45 @@
>  /* start of DA9210 System Control and Event Registers */
>  #define DA9210_REG_MASK_A		0x54
>  
> +struct regulator_quirk {
> +	struct list_head		list;
> +	const struct of_device_id	*id;
> +	struct of_phandle_args		irq_args;
> +	struct i2c_msg			i2c_msg;
> +	bool				shared;	/* IRQ line is shared */
> +};
> +
> +static LIST_HEAD(quirk_list);
>  static void __iomem *irqc;
>  
>  /* first byte sets the memory pointer, following are consecutive reg values */
>  static u8 da9063_irq_clr[] = { DA9063_REG_IRQ_MASK_A, 0xff, 0xff, 0xff, 0xff };
>  static u8 da9210_irq_clr[] = { DA9210_REG_MASK_A, 0xff, 0xff };
>  
> -static struct i2c_msg da9xxx_msgs[3] = {
> -	{
> -		.addr = 0x58,
> -		.len = ARRAY_SIZE(da9063_irq_clr),
> -		.buf = da9063_irq_clr,
> -	}, {
> -		.addr = 0x68,
> -		.len = ARRAY_SIZE(da9210_irq_clr),
> -		.buf = da9210_irq_clr,
> -	}, {
> -		.addr = 0x70,
> -		.len = ARRAY_SIZE(da9210_irq_clr),
> -		.buf = da9210_irq_clr,
> -	},
> +static struct i2c_msg da9063_msgs = {
> +	.len = ARRAY_SIZE(da9063_irq_clr),
> +	.buf = da9063_irq_clr,
> +};
> +
> +static struct i2c_msg da9210_msgs = {
> +	.len = ARRAY_SIZE(da9210_irq_clr),
> +	.buf = da9210_irq_clr,
> +};
> +
> +static const struct of_device_id rcar_gen2_quirk_match[] = {
> +	{ .compatible = "dlg,da9063", .data = &da9063_msgs },
> +	{ .compatible = "dlg,da9210", .data = &da9210_msgs },
> +	{},
>  };
>  
>  static int regulator_quirk_notify(struct notifier_block *nb,
>  				  unsigned long action, void *data)
>  {
> +	struct regulator_quirk *pos, *tmp;
>  	struct device *dev = data;
>  	struct i2c_client *client;
>  	static bool done;
> +	int ret;
>  	u32 mon;
>  
>  	if (done)
> @@ -88,17 +101,20 @@ static int regulator_quirk_notify(struct notifier_block *nb,
>  	client = to_i2c_client(dev);
>  	dev_dbg(dev, "Detected %s\n", client->name);
>  
> -	if ((client->addr == 0x58 && !strcmp(client->name, "da9063")) ||
> -	    (client->addr == 0x68 && !strcmp(client->name, "da9210")) ||
> -	    (client->addr == 0x70 && !strcmp(client->name, "da9210"))) {
> -		int ret, len;
> +	/*
> +	 * Send message to all PMICs that share an IRQ line to deassert it.
> +	 *
> +	 * WARNING: This works only if all the PMICs are on the same I2C bus.
> +	 */
> +	list_for_each_entry(pos, &quirk_list, list) {
> +		if (!pos->shared)
> +			continue;
>  
> -		/* There are two DA9210 on Stout, one on the other boards. */
> -		len = of_machine_is_compatible("renesas,stout") ? 3 : 2;
> +		dev_info(&client->dev, "clearing %s@0x%02x interrupts\n",
> +			 pos->id->compatible, pos->i2c_msg.addr);
>  
> -		dev_info(&client->dev, "clearing da9063/da9210 interrupts\n");
> -		ret = i2c_transfer(client->adapter, da9xxx_msgs, len);
> -		if (ret != len)
> +		ret = i2c_transfer(client->adapter, &pos->i2c_msg, 1);
> +		if (ret != 1)
>  			dev_err(&client->dev, "i2c error %d\n", ret);
>  	}
>  
> @@ -111,6 +127,11 @@ static int regulator_quirk_notify(struct notifier_block *nb,
>  remove:
>  	dev_info(dev, "IRQ2 is not asserted, removing quirk\n");
>  
> +	list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
> +		list_del(&pos->list);
> +		kfree(pos);
> +	}
> +
>  	done = true;
>  	iounmap(irqc);
>  	return 0;
> @@ -122,7 +143,13 @@ static struct notifier_block regulator_quirk_nb = {
>  
>  static int __init rcar_gen2_regulator_quirk(void)
>  {
> -	u32 mon;
> +	struct device_node *np;
> +	const struct of_device_id *id;
> +	struct regulator_quirk *quirk;
> +	struct regulator_quirk *pos;
> +	struct of_phandle_args *argsa, *argsb;
> +	u32 mon, addr;
> +	int ret;
>  
>  	if (!of_machine_is_compatible("renesas,koelsch") &&
>  	    !of_machine_is_compatible("renesas,lager") &&
> @@ -130,6 +157,45 @@ static int __init rcar_gen2_regulator_quirk(void)
>  	    !of_machine_is_compatible("renesas,gose"))
>  		return -ENODEV;
>  
> +	for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
> +		if (!np || !of_device_is_available(np))
> +			break;
> +
> +		quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);
> +
> +		argsa = &quirk->irq_args;
> +		memcpy(&quirk->i2c_msg, id->data, sizeof(quirk->i2c_msg));
> +
> +		ret = of_property_read_u32(np, "reg", &addr);
> +		if (ret)
> +			return ret;
> +
> +		quirk->id = id;
> +		quirk->i2c_msg.addr = addr;
> +		quirk->shared = false;
> +
> +		ret = of_irq_parse_one(np, 0, &quirk->irq_args);

As per my comment on v2,
&quirk->irq_args is assigned to argsa above and used directly here.

> +		if (ret)
> +			return ret;
> +
> +		list_for_each_entry(pos, &quirk_list, list) {
> +			argsb = &pos->irq_args;
> +
> +			if (argsa->args_count != argsb->args_count)
> +				continue;
> +
> +			ret = memcmp(argsa->args, argsb->args,
> +				     argsa->args_count *
> +				     sizeof(argsa->args[0]));
> +			if (!ret) {
> +				pos->shared = true;
> +				quirk->shared = true;
> +			}
> +		}
> +
> +		list_add_tail(&quirk->list, &quirk_list);
> +	}
> +
>  	irqc = ioremap(IRQC_BASE, PAGE_SIZE);
>  	if (!irqc)
>  		return -ENOMEM;
> -- 
> 2.16.2
>
Wolfram Sang June 5, 2018, 9:21 a.m. UTC | #2
Hi Marek,

On Tue, Jun 05, 2018 at 10:07:28AM +0200, Simon Horman wrote:
> On Mon, Jun 04, 2018 at 07:59:11PM +0200, Marek Vasut wrote:
> > Rather than hard-coding the quirk topology, which stopped scaling,
> > parse the information from DT. The code looks for all compatible
> > PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
> > to the same pin. If so, the code sends a matching sequence to the
> > PMIC to deassert the IRQ.
> > 
> > Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
> > Cc: Geert Uytterhoeven <geert+renesas@glider.be>
> > Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> > Cc: Simon Horman <horms+renesas@verge.net.au>
> > Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>

From an I2C point of view:

Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>

Minor nits:

> > @@ -122,7 +143,13 @@ static struct notifier_block regulator_quirk_nb = {
> >  
> >  static int __init rcar_gen2_regulator_quirk(void)
> >  {
> > -	u32 mon;
> > +	struct device_node *np;
> > +	const struct of_device_id *id;
> > +	struct regulator_quirk *quirk;
> > +	struct regulator_quirk *pos;

Merge the last two lines into one?

> > +	struct of_phandle_args *argsa, *argsb;
> > +	u32 mon, addr;
> > +	int ret;
> >  
> >  	if (!of_machine_is_compatible("renesas,koelsch") &&
> >  	    !of_machine_is_compatible("renesas,lager") &&
> > @@ -130,6 +157,45 @@ static int __init rcar_gen2_regulator_quirk(void)
> >  	    !of_machine_is_compatible("renesas,gose"))
> >  		return -ENODEV;
> >  
> > +	for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
> > +		if (!np || !of_device_is_available(np))

Can '!np' actually happen? This is the exit condition of the for-loop,
or am I overlooking something?

Regards,

   Wolfram
Marek Vasut June 5, 2018, 9:46 a.m. UTC | #3
On 06/05/2018 10:07 AM, Simon Horman wrote:
> On Mon, Jun 04, 2018 at 07:59:11PM +0200, Marek Vasut wrote:
>> Rather than hard-coding the quirk topology, which stopped scaling,
>> parse the information from DT. The code looks for all compatible
>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
>> to the same pin. If so, the code sends a matching sequence to the
>> PMIC to deassert the IRQ.
>>
>> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
>> Cc: Geert Uytterhoeven <geert+renesas@glider.be>
>> Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
>> Cc: Simon Horman <horms+renesas@verge.net.au>
>> Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>
>> Cc: linux-renesas-soc@vger.kernel.org
>> ---
>> V2: - Replace the DT shared IRQ check loop with memcmp()
>>     - Send the I2C message to deassert the IRQ line to all PMICs
>>       in the list with shared IRQ line instead of just one
>>     - Add comment that this works only in case all the PMICs are
>>       on the same I2C bus
>> V3: - Drop the addr = 0x00 init
>>     - Drop reinit of argsa in rcar_gen2_regulator_quirk
>> ---
>>  arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c | 114 ++++++++++++++++-----
>>  1 file changed, 90 insertions(+), 24 deletions(-)
>>
>> diff --git a/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c b/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
>> index 93f628acfd94..b919073aa27e 100644
>> --- a/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
>> +++ b/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
>> @@ -31,8 +31,10 @@
>>  #include <linux/i2c.h>
>>  #include <linux/init.h>
>>  #include <linux/io.h>
>> +#include <linux/list.h>
>>  #include <linux/notifier.h>
>>  #include <linux/of.h>
>> +#include <linux/of_irq.h>
>>  #include <linux/mfd/da9063/registers.h>
>>  
>>  
>> @@ -44,34 +46,45 @@
>>  /* start of DA9210 System Control and Event Registers */
>>  #define DA9210_REG_MASK_A		0x54
>>  
>> +struct regulator_quirk {
>> +	struct list_head		list;
>> +	const struct of_device_id	*id;
>> +	struct of_phandle_args		irq_args;
>> +	struct i2c_msg			i2c_msg;
>> +	bool				shared;	/* IRQ line is shared */
>> +};
>> +
>> +static LIST_HEAD(quirk_list);
>>  static void __iomem *irqc;
>>  
>>  /* first byte sets the memory pointer, following are consecutive reg values */
>>  static u8 da9063_irq_clr[] = { DA9063_REG_IRQ_MASK_A, 0xff, 0xff, 0xff, 0xff };
>>  static u8 da9210_irq_clr[] = { DA9210_REG_MASK_A, 0xff, 0xff };
>>  
>> -static struct i2c_msg da9xxx_msgs[3] = {
>> -	{
>> -		.addr = 0x58,
>> -		.len = ARRAY_SIZE(da9063_irq_clr),
>> -		.buf = da9063_irq_clr,
>> -	}, {
>> -		.addr = 0x68,
>> -		.len = ARRAY_SIZE(da9210_irq_clr),
>> -		.buf = da9210_irq_clr,
>> -	}, {
>> -		.addr = 0x70,
>> -		.len = ARRAY_SIZE(da9210_irq_clr),
>> -		.buf = da9210_irq_clr,
>> -	},
>> +static struct i2c_msg da9063_msgs = {
>> +	.len = ARRAY_SIZE(da9063_irq_clr),
>> +	.buf = da9063_irq_clr,
>> +};
>> +
>> +static struct i2c_msg da9210_msgs = {
>> +	.len = ARRAY_SIZE(da9210_irq_clr),
>> +	.buf = da9210_irq_clr,
>> +};
>> +
>> +static const struct of_device_id rcar_gen2_quirk_match[] = {
>> +	{ .compatible = "dlg,da9063", .data = &da9063_msgs },
>> +	{ .compatible = "dlg,da9210", .data = &da9210_msgs },
>> +	{},
>>  };
>>  
>>  static int regulator_quirk_notify(struct notifier_block *nb,
>>  				  unsigned long action, void *data)
>>  {
>> +	struct regulator_quirk *pos, *tmp;
>>  	struct device *dev = data;
>>  	struct i2c_client *client;
>>  	static bool done;
>> +	int ret;
>>  	u32 mon;
>>  
>>  	if (done)
>> @@ -88,17 +101,20 @@ static int regulator_quirk_notify(struct notifier_block *nb,
>>  	client = to_i2c_client(dev);
>>  	dev_dbg(dev, "Detected %s\n", client->name);
>>  
>> -	if ((client->addr == 0x58 && !strcmp(client->name, "da9063")) ||
>> -	    (client->addr == 0x68 && !strcmp(client->name, "da9210")) ||
>> -	    (client->addr == 0x70 && !strcmp(client->name, "da9210"))) {
>> -		int ret, len;
>> +	/*
>> +	 * Send message to all PMICs that share an IRQ line to deassert it.
>> +	 *
>> +	 * WARNING: This works only if all the PMICs are on the same I2C bus.
>> +	 */
>> +	list_for_each_entry(pos, &quirk_list, list) {
>> +		if (!pos->shared)
>> +			continue;
>>  
>> -		/* There are two DA9210 on Stout, one on the other boards. */
>> -		len = of_machine_is_compatible("renesas,stout") ? 3 : 2;
>> +		dev_info(&client->dev, "clearing %s@0x%02x interrupts\n",
>> +			 pos->id->compatible, pos->i2c_msg.addr);
>>  
>> -		dev_info(&client->dev, "clearing da9063/da9210 interrupts\n");
>> -		ret = i2c_transfer(client->adapter, da9xxx_msgs, len);
>> -		if (ret != len)
>> +		ret = i2c_transfer(client->adapter, &pos->i2c_msg, 1);
>> +		if (ret != 1)
>>  			dev_err(&client->dev, "i2c error %d\n", ret);
>>  	}
>>  
>> @@ -111,6 +127,11 @@ static int regulator_quirk_notify(struct notifier_block *nb,
>>  remove:
>>  	dev_info(dev, "IRQ2 is not asserted, removing quirk\n");
>>  
>> +	list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
>> +		list_del(&pos->list);
>> +		kfree(pos);
>> +	}
>> +
>>  	done = true;
>>  	iounmap(irqc);
>>  	return 0;
>> @@ -122,7 +143,13 @@ static struct notifier_block regulator_quirk_nb = {
>>  
>>  static int __init rcar_gen2_regulator_quirk(void)
>>  {
>> -	u32 mon;
>> +	struct device_node *np;
>> +	const struct of_device_id *id;
>> +	struct regulator_quirk *quirk;
>> +	struct regulator_quirk *pos;
>> +	struct of_phandle_args *argsa, *argsb;
>> +	u32 mon, addr;
>> +	int ret;
>>  
>>  	if (!of_machine_is_compatible("renesas,koelsch") &&
>>  	    !of_machine_is_compatible("renesas,lager") &&
>> @@ -130,6 +157,45 @@ static int __init rcar_gen2_regulator_quirk(void)
>>  	    !of_machine_is_compatible("renesas,gose"))
>>  		return -ENODEV;
>>  
>> +	for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
>> +		if (!np || !of_device_is_available(np))
>> +			break;
>> +
>> +		quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);
>> +
>> +		argsa = &quirk->irq_args;
>> +		memcpy(&quirk->i2c_msg, id->data, sizeof(quirk->i2c_msg));
>> +
>> +		ret = of_property_read_u32(np, "reg", &addr);
>> +		if (ret)
>> +			return ret;
>> +
>> +		quirk->id = id;
>> +		quirk->i2c_msg.addr = addr;
>> +		quirk->shared = false;
>> +
>> +		ret = of_irq_parse_one(np, 0, &quirk->irq_args);
> 
> As per my comment on v2,
> &quirk->irq_args is assigned to argsa above and used directly here.
> 

Hum, OK
Marek Vasut June 5, 2018, 9:57 a.m. UTC | #4
On 06/05/2018 11:21 AM, Wolfram Sang wrote:
> Hi Marek,
> 
> On Tue, Jun 05, 2018 at 10:07:28AM +0200, Simon Horman wrote:
>> On Mon, Jun 04, 2018 at 07:59:11PM +0200, Marek Vasut wrote:
>>> Rather than hard-coding the quirk topology, which stopped scaling,
>>> parse the information from DT. The code looks for all compatible
>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
>>> to the same pin. If so, the code sends a matching sequence to the
>>> PMIC to deassert the IRQ.
>>>
>>> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
>>> Cc: Geert Uytterhoeven <geert+renesas@glider.be>
>>> Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
>>> Cc: Simon Horman <horms+renesas@verge.net.au>
>>> Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>
> 
> From an I2C point of view:
> 
> Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> 
> Minor nits:
> 
>>> @@ -122,7 +143,13 @@ static struct notifier_block regulator_quirk_nb = {
>>>  
>>>  static int __init rcar_gen2_regulator_quirk(void)
>>>  {
>>> -	u32 mon;
>>> +	struct device_node *np;
>>> +	const struct of_device_id *id;
>>> +	struct regulator_quirk *quirk;
>>> +	struct regulator_quirk *pos;
> 
> Merge the last two lines into one?
> 
>>> +	struct of_phandle_args *argsa, *argsb;
>>> +	u32 mon, addr;
>>> +	int ret;
>>>  
>>>  	if (!of_machine_is_compatible("renesas,koelsch") &&
>>>  	    !of_machine_is_compatible("renesas,lager") &&
>>> @@ -130,6 +157,45 @@ static int __init rcar_gen2_regulator_quirk(void)
>>>  	    !of_machine_is_compatible("renesas,gose"))
>>>  		return -ENODEV;
>>>  
>>> +	for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
>>> +		if (!np || !of_device_is_available(np))
> 
> Can '!np' actually happen? This is the exit condition of the for-loop,
> or am I overlooking something?

I had to take a look again, no, it's not needed.
Geert Uytterhoeven June 11, 2018, 9:56 a.m. UTC | #5
Hi Marek,

On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> Rather than hard-coding the quirk topology, which stopped scaling,
> parse the information from DT. The code looks for all compatible
> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied

da9063

> to the same pin. If so, the code sends a matching sequence to the
> PMIC to deassert the IRQ.

Note that not all R-Car Gen2 boards have all regulators described in DT yet.
E.g. gose lacks da9210. So that has to be fixed first.

>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
> Cc: Geert Uytterhoeven <geert+renesas@glider.be>
> Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> Cc: Simon Horman <horms+renesas@verge.net.au>
> Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Cc: linux-renesas-soc@vger.kernel.org
> ---
> V2: - Replace the DT shared IRQ check loop with memcmp()
>     - Send the I2C message to deassert the IRQ line to all PMICs
>       in the list with shared IRQ line instead of just one
>     - Add comment that this works only in case all the PMICs are
>       on the same I2C bus
> V3: - Drop the addr = 0x00 init
>     - Drop reinit of argsa in rcar_gen2_regulator_quirk

Thanks for the update!

> --- a/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
> +++ b/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c

> @@ -44,34 +46,45 @@
>  /* start of DA9210 System Control and Event Registers */
>  #define DA9210_REG_MASK_A              0x54
>
> +struct regulator_quirk {
> +       struct list_head                list;
> +       const struct of_device_id       *id;
> +       struct of_phandle_args          irq_args;
> +       struct i2c_msg                  i2c_msg;
> +       bool                            shared; /* IRQ line is shared */
> +};
> +
> +static LIST_HEAD(quirk_list);
>  static void __iomem *irqc;
>
>  /* first byte sets the memory pointer, following are consecutive reg values */
>  static u8 da9063_irq_clr[] = { DA9063_REG_IRQ_MASK_A, 0xff, 0xff, 0xff, 0xff };
>  static u8 da9210_irq_clr[] = { DA9210_REG_MASK_A, 0xff, 0xff };
>
> -static struct i2c_msg da9xxx_msgs[3] = {
> -       {
> -               .addr = 0x58,
> -               .len = ARRAY_SIZE(da9063_irq_clr),
> -               .buf = da9063_irq_clr,
> -       }, {
> -               .addr = 0x68,
> -               .len = ARRAY_SIZE(da9210_irq_clr),
> -               .buf = da9210_irq_clr,
> -       }, {
> -               .addr = 0x70,
> -               .len = ARRAY_SIZE(da9210_irq_clr),
> -               .buf = da9210_irq_clr,
> -       },
> +static struct i2c_msg da9063_msgs = {

da9063_msg? (it's a single message)

> +       .len = ARRAY_SIZE(da9063_irq_clr),
> +       .buf = da9063_irq_clr,
> +};
> +
> +static struct i2c_msg da9210_msgs = {

da9210_msg?

> +       .len = ARRAY_SIZE(da9210_irq_clr),
> +       .buf = da9210_irq_clr,
> +};

> @@ -122,7 +143,13 @@ static struct notifier_block regulator_quirk_nb = {
>
>  static int __init rcar_gen2_regulator_quirk(void)
>  {
> -       u32 mon;
> +       struct device_node *np;
> +       const struct of_device_id *id;
> +       struct regulator_quirk *quirk;
> +       struct regulator_quirk *pos;
> +       struct of_phandle_args *argsa, *argsb;
> +       u32 mon, addr;
> +       int ret;

Some people prefer "Reverse Christmas Tree Ordering", i.e. longest line first.

>
>         if (!of_machine_is_compatible("renesas,koelsch") &&
>             !of_machine_is_compatible("renesas,lager") &&
> @@ -130,6 +157,45 @@ static int __init rcar_gen2_regulator_quirk(void)
>             !of_machine_is_compatible("renesas,gose"))
>                 return -ENODEV;

I think the board checks above can be removed. That will auto-enable the
fix on e.g. Porter (once its regulators have ended up in DTS, of course).

>
> +       for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
> +               if (!np || !of_device_is_available(np))

!np cannot happen

> +                       break;
> +
> +               quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);

Missing NULL check

> +
> +               argsa = &quirk->irq_args;
> +               memcpy(&quirk->i2c_msg, id->data, sizeof(quirk->i2c_msg));
> +
> +               ret = of_property_read_u32(np, "reg", &addr);
> +               if (ret)
> +                       return ret;

I think it's safer to skip this entry and continue, after calling
kfree(quirk), of course.

> +
> +               quirk->id = id;
> +               quirk->i2c_msg.addr = addr;
> +               quirk->shared = false;

No need to clear shared, it was cleared by kzalloc().

> +
> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
> +               if (ret)
> +                       return ret;

kfree(quirk) and continue...

Works fine on Koelsch, so
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Marek Vasut June 11, 2018, 12:08 p.m. UTC | #6
On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
> Hi Marek,

Hi,

> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>> Rather than hard-coding the quirk topology, which stopped scaling,
>> parse the information from DT. The code looks for all compatible
>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
> 
> da9063
> 
>> to the same pin. If so, the code sends a matching sequence to the
>> PMIC to deassert the IRQ.
> 
> Note that not all R-Car Gen2 boards have all regulators described in DT yet.
> E.g. gose lacks da9210. So that has to be fixed first.

[...]

> da9210_msg?

Fixed

> 
>> +       .len = ARRAY_SIZE(da9210_irq_clr),
>> +       .buf = da9210_irq_clr,
>> +};
> 
>> @@ -122,7 +143,13 @@ static struct notifier_block regulator_quirk_nb = {
>>
>>  static int __init rcar_gen2_regulator_quirk(void)
>>  {
>> -       u32 mon;
>> +       struct device_node *np;
>> +       const struct of_device_id *id;
>> +       struct regulator_quirk *quirk;
>> +       struct regulator_quirk *pos;
>> +       struct of_phandle_args *argsa, *argsb;
>> +       u32 mon, addr;
>> +       int ret;
> 
> Some people prefer "Reverse Christmas Tree Ordering", i.e. longest line first.
> 
>>
>>         if (!of_machine_is_compatible("renesas,koelsch") &&
>>             !of_machine_is_compatible("renesas,lager") &&
>> @@ -130,6 +157,45 @@ static int __init rcar_gen2_regulator_quirk(void)
>>             !of_machine_is_compatible("renesas,gose"))
>>                 return -ENODEV;
> 
> I think the board checks above can be removed. That will auto-enable the
> fix on e.g. Porter (once its regulators have ended up in DTS, of course).

Removing the check would also enable it on boards where we don't want
this enabled, so I'd prefer to keep the check to avoid strange surprises.

>>
>> +       for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
>> +               if (!np || !of_device_is_available(np))
> 
> !np cannot happen

Right

>> +                       break;
>> +
>> +               quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);
> 
> Missing NULL check
> 
>> +
>> +               argsa = &quirk->irq_args;
>> +               memcpy(&quirk->i2c_msg, id->data, sizeof(quirk->i2c_msg));
>> +
>> +               ret = of_property_read_u32(np, "reg", &addr);
>> +               if (ret)
>> +                       return ret;
> 
> I think it's safer to skip this entry and continue, after calling
> kfree(quirk), of course.
> 
>> +
>> +               quirk->id = id;
>> +               quirk->i2c_msg.addr = addr;
>> +               quirk->shared = false;
> 
> No need to clear shared, it was cleared by kzalloc().
> 
>> +
>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
>> +               if (ret)
>> +                       return ret;
> 
> kfree(quirk) and continue...
>

I wonder if it shouldn't rather free the entire list and abort ?

> Works fine on Koelsch, so
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds
>
Geert Uytterhoeven June 11, 2018, 1:03 p.m. UTC | #7
Hi Marek,

On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
> > On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >> Rather than hard-coding the quirk topology, which stopped scaling,
> >> parse the information from DT. The code looks for all compatible
> >> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
> >
> > da9063
> >
> >> to the same pin. If so, the code sends a matching sequence to the
> >> PMIC to deassert the IRQ.

> >> @@ -122,7 +143,13 @@ static struct notifier_block regulator_quirk_nb = {
> >>
> >>  static int __init rcar_gen2_regulator_quirk(void)
> >>  {
> >> -       u32 mon;
> >> +       struct device_node *np;
> >> +       const struct of_device_id *id;
> >> +       struct regulator_quirk *quirk;
> >> +       struct regulator_quirk *pos;
> >> +       struct of_phandle_args *argsa, *argsb;
> >> +       u32 mon, addr;
> >> +       int ret;
> >
> > Some people prefer "Reverse Christmas Tree Ordering", i.e. longest line first.
> >
> >>
> >>         if (!of_machine_is_compatible("renesas,koelsch") &&
> >>             !of_machine_is_compatible("renesas,lager") &&
> >> @@ -130,6 +157,45 @@ static int __init rcar_gen2_regulator_quirk(void)
> >>             !of_machine_is_compatible("renesas,gose"))
> >>                 return -ENODEV;
> >
> > I think the board checks above can be removed. That will auto-enable the
> > fix on e.g. Porter (once its regulators have ended up in DTS, of course).
>
> Removing the check would also enable it on boards where we don't want
> this enabled, so I'd prefer to keep the check to avoid strange surprises.

Like, Porter? ;-)

> >> +               ret = of_property_read_u32(np, "reg", &addr);
> >> +               if (ret)
> >> +                       return ret;
> >
> > I think it's safer to skip this entry and continue, after calling
> > kfree(quirk), of course.
> >
> >> +
> >> +               quirk->id = id;
> >> +               quirk->i2c_msg.addr = addr;
> >> +               quirk->shared = false;
> >> +
> >> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
> >> +               if (ret)
> >> +                       return ret;
> >
> > kfree(quirk) and continue...
>
> I wonder if it shouldn't rather free the entire list and abort ?

"Be strict when sending, be liberal when receiving."

Gr{oetje,eeting}s,

                        Geert
Marek Vasut June 11, 2018, 1:35 p.m. UTC | #8
On 06/11/2018 03:03 PM, Geert Uytterhoeven wrote:
> Hi Marek,

Hi,

> On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
>>> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>> Rather than hard-coding the quirk topology, which stopped scaling,
>>>> parse the information from DT. The code looks for all compatible
>>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
>>>
>>> da9063
>>>
>>>> to the same pin. If so, the code sends a matching sequence to the
>>>> PMIC to deassert the IRQ.
> 
>>>> @@ -122,7 +143,13 @@ static struct notifier_block regulator_quirk_nb = {
>>>>
>>>>  static int __init rcar_gen2_regulator_quirk(void)
>>>>  {
>>>> -       u32 mon;
>>>> +       struct device_node *np;
>>>> +       const struct of_device_id *id;
>>>> +       struct regulator_quirk *quirk;
>>>> +       struct regulator_quirk *pos;
>>>> +       struct of_phandle_args *argsa, *argsb;
>>>> +       u32 mon, addr;
>>>> +       int ret;
>>>
>>> Some people prefer "Reverse Christmas Tree Ordering", i.e. longest line first.
>>>
>>>>
>>>>         if (!of_machine_is_compatible("renesas,koelsch") &&
>>>>             !of_machine_is_compatible("renesas,lager") &&
>>>> @@ -130,6 +157,45 @@ static int __init rcar_gen2_regulator_quirk(void)
>>>>             !of_machine_is_compatible("renesas,gose"))
>>>>                 return -ENODEV;
>>>
>>> I think the board checks above can be removed. That will auto-enable the
>>> fix on e.g. Porter (once its regulators have ended up in DTS, of course).
>>
>> Removing the check would also enable it on boards where we don't want
>> this enabled, so I'd prefer to keep the check to avoid strange surprises.
> 
> Like, Porter? ;-)

I'm adding Porter in a separate patch.

>>>> +               ret = of_property_read_u32(np, "reg", &addr);
>>>> +               if (ret)
>>>> +                       return ret;
>>>
>>> I think it's safer to skip this entry and continue, after calling
>>> kfree(quirk), of course.
>>>
>>>> +
>>>> +               quirk->id = id;
>>>> +               quirk->i2c_msg.addr = addr;
>>>> +               quirk->shared = false;
>>>> +
>>>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
>>>> +               if (ret)
>>>> +                       return ret;
>>>
>>> kfree(quirk) and continue...
>>
>> I wonder if it shouldn't rather free the entire list and abort ?
> 
> "Be strict when sending, be liberal when receiving."

Meaning ? I think "the language barrier is protecting me" (TM)
Geert Uytterhoeven June 11, 2018, 1:49 p.m. UTC | #9
Hi Marek,

On Mon, Jun 11, 2018 at 3:39 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> On 06/11/2018 03:03 PM, Geert Uytterhoeven wrote:
> > On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
> >>> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>> Rather than hard-coding the quirk topology, which stopped scaling,
> >>>> parse the information from DT. The code looks for all compatible
> >>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
> >>>> to the same pin. If so, the code sends a matching sequence to the
> >>>> PMIC to deassert the IRQ.

> >>>> +               ret = of_property_read_u32(np, "reg", &addr);
> >>>> +               if (ret)
> >>>> +                       return ret;
> >>>
> >>> I think it's safer to skip this entry and continue, after calling
> >>> kfree(quirk), of course.
> >>>
> >>>> +
> >>>> +               quirk->id = id;
> >>>> +               quirk->i2c_msg.addr = addr;
> >>>> +               quirk->shared = false;
> >>>> +
> >>>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
> >>>> +               if (ret)
> >>>> +                       return ret;
> >>>
> >>> kfree(quirk) and continue...
> >>
> >> I wonder if it shouldn't rather free the entire list and abort ?
> >
> > "Be strict when sending, be liberal when receiving."
>
> Meaning ? I think "the language barrier is protecting me" (TM)

Do the best you can, given the buggy DT you received.
I.e. don't fail completely, just ignore the bad device node, and continue.

Gr{oetje,eeting}s,

                        Geert
Marek Vasut June 11, 2018, 2:04 p.m. UTC | #10
On 06/11/2018 03:49 PM, Geert Uytterhoeven wrote:
> Hi Marek,

Hi,

> On Mon, Jun 11, 2018 at 3:39 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>> On 06/11/2018 03:03 PM, Geert Uytterhoeven wrote:
>>> On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
>>>>> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>> Rather than hard-coding the quirk topology, which stopped scaling,
>>>>>> parse the information from DT. The code looks for all compatible
>>>>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
>>>>>> to the same pin. If so, the code sends a matching sequence to the
>>>>>> PMIC to deassert the IRQ.
> 
>>>>>> +               ret = of_property_read_u32(np, "reg", &addr);
>>>>>> +               if (ret)
>>>>>> +                       return ret;
>>>>>
>>>>> I think it's safer to skip this entry and continue, after calling
>>>>> kfree(quirk), of course.
>>>>>
>>>>>> +
>>>>>> +               quirk->id = id;
>>>>>> +               quirk->i2c_msg.addr = addr;
>>>>>> +               quirk->shared = false;
>>>>>> +
>>>>>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
>>>>>> +               if (ret)
>>>>>> +                       return ret;
>>>>>
>>>>> kfree(quirk) and continue...
>>>>
>>>> I wonder if it shouldn't rather free the entire list and abort ?
>>>
>>> "Be strict when sending, be liberal when receiving."
>>
>> Meaning ? I think "the language barrier is protecting me" (TM)
> 
> Do the best you can, given the buggy DT you received.
> I.e. don't fail completely, just ignore the bad device node, and continue.

But if you ignore node, you might as well ignore one which is shared and
then the system crashes due to IRQ storm anyway. So hum, what can we do ?
Geert Uytterhoeven June 11, 2018, 2:10 p.m. UTC | #11
Hi Marek,

On Mon, Jun 11, 2018 at 4:04 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> On 06/11/2018 03:49 PM, Geert Uytterhoeven wrote:
> > On Mon, Jun 11, 2018 at 3:39 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >> On 06/11/2018 03:03 PM, Geert Uytterhoeven wrote:
> >>> On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
> >>>>> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>>>> Rather than hard-coding the quirk topology, which stopped scaling,
> >>>>>> parse the information from DT. The code looks for all compatible
> >>>>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
> >>>>>> to the same pin. If so, the code sends a matching sequence to the
> >>>>>> PMIC to deassert the IRQ.
> >
> >>>>>> +               ret = of_property_read_u32(np, "reg", &addr);
> >>>>>> +               if (ret)
> >>>>>> +                       return ret;
> >>>>>
> >>>>> I think it's safer to skip this entry and continue, after calling
> >>>>> kfree(quirk), of course.
> >>>>>
> >>>>>> +
> >>>>>> +               quirk->id = id;
> >>>>>> +               quirk->i2c_msg.addr = addr;
> >>>>>> +               quirk->shared = false;
> >>>>>> +
> >>>>>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
> >>>>>> +               if (ret)
> >>>>>> +                       return ret;
> >>>>>
> >>>>> kfree(quirk) and continue...
> >>>>
> >>>> I wonder if it shouldn't rather free the entire list and abort ?
> >>>
> >>> "Be strict when sending, be liberal when receiving."
> >>
> >> Meaning ? I think "the language barrier is protecting me" (TM)
> >
> > Do the best you can, given the buggy DT you received.
> > I.e. don't fail completely, just ignore the bad device node, and continue.
>
> But if you ignore node, you might as well ignore one which is shared and
> then the system crashes due to IRQ storm anyway. So hum, what can we do ?

Correct. If it's a critical node, it will crash regardless.
If it's a non-critical node, you have the choice between aborting and crashing,
or ignoring and keeping the system alive. Your call.

Gr{oetje,eeting}s,

                        Geert
Marek Vasut June 11, 2018, 2:19 p.m. UTC | #12
On 06/11/2018 04:10 PM, Geert Uytterhoeven wrote:
> Hi Marek,

Hi,

> On Mon, Jun 11, 2018 at 4:04 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>> On 06/11/2018 03:49 PM, Geert Uytterhoeven wrote:
>>> On Mon, Jun 11, 2018 at 3:39 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>> On 06/11/2018 03:03 PM, Geert Uytterhoeven wrote:
>>>>> On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
>>>>>>> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>>>> Rather than hard-coding the quirk topology, which stopped scaling,
>>>>>>>> parse the information from DT. The code looks for all compatible
>>>>>>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
>>>>>>>> to the same pin. If so, the code sends a matching sequence to the
>>>>>>>> PMIC to deassert the IRQ.
>>>
>>>>>>>> +               ret = of_property_read_u32(np, "reg", &addr);
>>>>>>>> +               if (ret)
>>>>>>>> +                       return ret;
>>>>>>>
>>>>>>> I think it's safer to skip this entry and continue, after calling
>>>>>>> kfree(quirk), of course.
>>>>>>>
>>>>>>>> +
>>>>>>>> +               quirk->id = id;
>>>>>>>> +               quirk->i2c_msg.addr = addr;
>>>>>>>> +               quirk->shared = false;
>>>>>>>> +
>>>>>>>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
>>>>>>>> +               if (ret)
>>>>>>>> +                       return ret;
>>>>>>>
>>>>>>> kfree(quirk) and continue...
>>>>>>
>>>>>> I wonder if it shouldn't rather free the entire list and abort ?
>>>>>
>>>>> "Be strict when sending, be liberal when receiving."
>>>>
>>>> Meaning ? I think "the language barrier is protecting me" (TM)
>>>
>>> Do the best you can, given the buggy DT you received.
>>> I.e. don't fail completely, just ignore the bad device node, and continue.
>>
>> But if you ignore node, you might as well ignore one which is shared and
>> then the system crashes due to IRQ storm anyway. So hum, what can we do ?
> 
> Correct. If it's a critical node, it will crash regardless.
> If it's a non-critical node, you have the choice between aborting and crashing,
> or ignoring and keeping the system alive. Your call.

But wait, since we control which machines this code runs on , can't we
assure they have valid DTs ? This situation with invalid DT starts to
look a bit hypothetical to me.
Geert Uytterhoeven June 11, 2018, 2:30 p.m. UTC | #13
Hi Marek,

On Mon, Jun 11, 2018 at 4:19 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> On 06/11/2018 04:10 PM, Geert Uytterhoeven wrote:
> > On Mon, Jun 11, 2018 at 4:04 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >> On 06/11/2018 03:49 PM, Geert Uytterhoeven wrote:
> >>> On Mon, Jun 11, 2018 at 3:39 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>> On 06/11/2018 03:03 PM, Geert Uytterhoeven wrote:
> >>>>> On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>>>> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
> >>>>>>> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>>>>>> Rather than hard-coding the quirk topology, which stopped scaling,
> >>>>>>>> parse the information from DT. The code looks for all compatible
> >>>>>>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
> >>>>>>>> to the same pin. If so, the code sends a matching sequence to the
> >>>>>>>> PMIC to deassert the IRQ.
> >>>
> >>>>>>>> +               ret = of_property_read_u32(np, "reg", &addr);
> >>>>>>>> +               if (ret)
> >>>>>>>> +                       return ret;
> >>>>>>>
> >>>>>>> I think it's safer to skip this entry and continue, after calling
> >>>>>>> kfree(quirk), of course.
> >>>>>>>
> >>>>>>>> +
> >>>>>>>> +               quirk->id = id;
> >>>>>>>> +               quirk->i2c_msg.addr = addr;
> >>>>>>>> +               quirk->shared = false;
> >>>>>>>> +
> >>>>>>>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
> >>>>>>>> +               if (ret)
> >>>>>>>> +                       return ret;
> >>>>>>>
> >>>>>>> kfree(quirk) and continue...
> >>>>>>
> >>>>>> I wonder if it shouldn't rather free the entire list and abort ?
> >>>>>
> >>>>> "Be strict when sending, be liberal when receiving."
> >>>>
> >>>> Meaning ? I think "the language barrier is protecting me" (TM)
> >>>
> >>> Do the best you can, given the buggy DT you received.
> >>> I.e. don't fail completely, just ignore the bad device node, and continue.
> >>
> >> But if you ignore node, you might as well ignore one which is shared and
> >> then the system crashes due to IRQ storm anyway. So hum, what can we do ?
> >
> > Correct. If it's a critical node, it will crash regardless.
> > If it's a non-critical node, you have the choice between aborting and crashing,
> > or ignoring and keeping the system alive. Your call.
>
> But wait, since we control which machines this code runs on , can't we
> assure they have valid DTs ? This situation with invalid DT starts to
> look a bit hypothetical to me.

That assumes you keep the list of machines to check, and don't want to fix the
issue automatically when detected (on any R-Car Gen2 or RZ/G1 platform, so
you still need to check for r8a779[0-4] and r8a774[23457]).

Anyway, as we care about booting old DTBs on new kernels (for a while), we
have a few more release cycles to bikeshed ;-)

Gr{oetje,eeting}s,

                        Geert
Marek Vasut June 11, 2018, 3:26 p.m. UTC | #14
On 06/11/2018 04:30 PM, Geert Uytterhoeven wrote:
> Hi Marek,
> 
> On Mon, Jun 11, 2018 at 4:19 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>> On 06/11/2018 04:10 PM, Geert Uytterhoeven wrote:
>>> On Mon, Jun 11, 2018 at 4:04 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>> On 06/11/2018 03:49 PM, Geert Uytterhoeven wrote:
>>>>> On Mon, Jun 11, 2018 at 3:39 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>> On 06/11/2018 03:03 PM, Geert Uytterhoeven wrote:
>>>>>>> On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>>>> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
>>>>>>>>> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>>>>>> Rather than hard-coding the quirk topology, which stopped scaling,
>>>>>>>>>> parse the information from DT. The code looks for all compatible
>>>>>>>>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
>>>>>>>>>> to the same pin. If so, the code sends a matching sequence to the
>>>>>>>>>> PMIC to deassert the IRQ.
>>>>>
>>>>>>>>>> +               ret = of_property_read_u32(np, "reg", &addr);
>>>>>>>>>> +               if (ret)
>>>>>>>>>> +                       return ret;
>>>>>>>>>
>>>>>>>>> I think it's safer to skip this entry and continue, after calling
>>>>>>>>> kfree(quirk), of course.
>>>>>>>>>
>>>>>>>>>> +
>>>>>>>>>> +               quirk->id = id;
>>>>>>>>>> +               quirk->i2c_msg.addr = addr;
>>>>>>>>>> +               quirk->shared = false;
>>>>>>>>>> +
>>>>>>>>>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
>>>>>>>>>> +               if (ret)
>>>>>>>>>> +                       return ret;
>>>>>>>>>
>>>>>>>>> kfree(quirk) and continue...
>>>>>>>>
>>>>>>>> I wonder if it shouldn't rather free the entire list and abort ?
>>>>>>>
>>>>>>> "Be strict when sending, be liberal when receiving."
>>>>>>
>>>>>> Meaning ? I think "the language barrier is protecting me" (TM)
>>>>>
>>>>> Do the best you can, given the buggy DT you received.
>>>>> I.e. don't fail completely, just ignore the bad device node, and continue.
>>>>
>>>> But if you ignore node, you might as well ignore one which is shared and
>>>> then the system crashes due to IRQ storm anyway. So hum, what can we do ?
>>>
>>> Correct. If it's a critical node, it will crash regardless.
>>> If it's a non-critical node, you have the choice between aborting and crashing,
>>> or ignoring and keeping the system alive. Your call.
>>
>> But wait, since we control which machines this code runs on , can't we
>> assure they have valid DTs ? This situation with invalid DT starts to
>> look a bit hypothetical to me.
> 
> That assumes you keep the list of machines to check, and don't want to fix the
> issue automatically when detected (on any R-Car Gen2 or RZ/G1 platform, so
> you still need to check for r8a779[0-4] and r8a774[23457]).

Yes, I want to keep a list of machines to check, to be _sure_ some
machine doesn't randomly blow up.

> Anyway, as we care about booting old DTBs on new kernels (for a while), we
> have a few more release cycles to bikeshed ;-)

I was about to ask if this patch then makes any sense or not.
Geert Uytterhoeven June 13, 2018, 11:28 a.m. UTC | #15
Hi Marek,

On Mon, Jun 11, 2018 at 5:26 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> On 06/11/2018 04:30 PM, Geert Uytterhoeven wrote:
> > On Mon, Jun 11, 2018 at 4:19 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >> On 06/11/2018 04:10 PM, Geert Uytterhoeven wrote:
> >>> On Mon, Jun 11, 2018 at 4:04 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>> On 06/11/2018 03:49 PM, Geert Uytterhoeven wrote:
> >>>>> On Mon, Jun 11, 2018 at 3:39 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>>>> On 06/11/2018 03:03 PM, Geert Uytterhoeven wrote:
> >>>>>>> On Mon, Jun 11, 2018 at 2:15 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>>>>>> On 06/11/2018 11:56 AM, Geert Uytterhoeven wrote:
> >>>>>>>>> On Mon, Jun 4, 2018 at 7:59 PM Marek Vasut <marek.vasut@gmail.com> wrote:
> >>>>>>>>>> Rather than hard-coding the quirk topology, which stopped scaling,
> >>>>>>>>>> parse the information from DT. The code looks for all compatible
> >>>>>>>>>> PMICs -- da9036 and da9210 -- and checks if their IRQ line is tied
> >>>>>>>>>> to the same pin. If so, the code sends a matching sequence to the
> >>>>>>>>>> PMIC to deassert the IRQ.
> >>>>>
> >>>>>>>>>> +               ret = of_property_read_u32(np, "reg", &addr);
> >>>>>>>>>> +               if (ret)
> >>>>>>>>>> +                       return ret;
> >>>>>>>>>
> >>>>>>>>> I think it's safer to skip this entry and continue, after calling
> >>>>>>>>> kfree(quirk), of course.
> >>>>>>>>>
> >>>>>>>>>> +
> >>>>>>>>>> +               quirk->id = id;
> >>>>>>>>>> +               quirk->i2c_msg.addr = addr;
> >>>>>>>>>> +               quirk->shared = false;
> >>>>>>>>>> +
> >>>>>>>>>> +               ret = of_irq_parse_one(np, 0, &quirk->irq_args);
> >>>>>>>>>> +               if (ret)
> >>>>>>>>>> +                       return ret;
> >>>>>>>>>
> >>>>>>>>> kfree(quirk) and continue...
> >>>>>>>>
> >>>>>>>> I wonder if it shouldn't rather free the entire list and abort ?
> >>>>>>>
> >>>>>>> "Be strict when sending, be liberal when receiving."
> >>>>>>
> >>>>>> Meaning ? I think "the language barrier is protecting me" (TM)
> >>>>>
> >>>>> Do the best you can, given the buggy DT you received.
> >>>>> I.e. don't fail completely, just ignore the bad device node, and continue.
> >>>>
> >>>> But if you ignore node, you might as well ignore one which is shared and
> >>>> then the system crashes due to IRQ storm anyway. So hum, what can we do ?
> >>>
> >>> Correct. If it's a critical node, it will crash regardless.
> >>> If it's a non-critical node, you have the choice between aborting and crashing,
> >>> or ignoring and keeping the system alive. Your call.
> >>
> >> But wait, since we control which machines this code runs on , can't we
> >> assure they have valid DTs ? This situation with invalid DT starts to
> >> look a bit hypothetical to me.
> >
> > That assumes you keep the list of machines to check, and don't want to fix the
> > issue automatically when detected (on any R-Car Gen2 or RZ/G1 platform, so
> > you still need to check for r8a779[0-4] and r8a774[23457]).
>
> Yes, I want to keep a list of machines to check, to be _sure_ some
> machine doesn't randomly blow up.

Just checking for the presence of a "renesas,irqc" node should be sufficient.
Using that node would also get rid of the hardcoded IRQC_BASE address.
Note that the code assumes IRQ2. If another IRQ is used, that won't harm
much though (as in: if it didn't blow up before, it won't blow up now).

> > Anyway, as we care about booting old DTBs on new kernels (for a while), we
> > have a few more release cycles to bikeshed ;-)
>
> I was about to ask if this patch then makes any sense or not.

Sure. Less hard-coding is always better.
Especially if it means we can make it work on more machines automatically :-)

Gr{oetje,eeting}s,

                        Geert
Marek Vasut June 13, 2018, 8:53 p.m. UTC | #16
On 06/13/2018 01:28 PM, Geert Uytterhoeven wrote:
> Hi Marek,

Hi,

[...]

>>>> But wait, since we control which machines this code runs on , can't we
>>>> assure they have valid DTs ? This situation with invalid DT starts to
>>>> look a bit hypothetical to me.
>>>
>>> That assumes you keep the list of machines to check, and don't want to fix the
>>> issue automatically when detected (on any R-Car Gen2 or RZ/G1 platform, so
>>> you still need to check for r8a779[0-4] and r8a774[23457]).
>>
>> Yes, I want to keep a list of machines to check, to be _sure_ some
>> machine doesn't randomly blow up.
> 
> Just checking for the presence of a "renesas,irqc" node should be sufficient.

How so? Any other R-Car machine can have the irqc node too. That's
fragile at best.

> Using that node would also get rid of the hardcoded IRQC_BASE address.
> Note that the code assumes IRQ2. If another IRQ is used, that won't harm
> much though (as in: if it didn't blow up before, it won't blow up now).

We could/should fix up the irqc detection though.

>>> Anyway, as we care about booting old DTBs on new kernels (for a while), we
>>> have a few more release cycles to bikeshed ;-)
>>
>> I was about to ask if this patch then makes any sense or not.
> 
> Sure. Less hard-coding is always better.
> Especially if it means we can make it work on more machines automatically :-)

I prefer to be in control of that.
diff mbox

Patch

diff --git a/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c b/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
index 93f628acfd94..b919073aa27e 100644
--- a/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
+++ b/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
@@ -31,8 +31,10 @@ 
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/list.h>
 #include <linux/notifier.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/mfd/da9063/registers.h>
 
 
@@ -44,34 +46,45 @@ 
 /* start of DA9210 System Control and Event Registers */
 #define DA9210_REG_MASK_A		0x54
 
+struct regulator_quirk {
+	struct list_head		list;
+	const struct of_device_id	*id;
+	struct of_phandle_args		irq_args;
+	struct i2c_msg			i2c_msg;
+	bool				shared;	/* IRQ line is shared */
+};
+
+static LIST_HEAD(quirk_list);
 static void __iomem *irqc;
 
 /* first byte sets the memory pointer, following are consecutive reg values */
 static u8 da9063_irq_clr[] = { DA9063_REG_IRQ_MASK_A, 0xff, 0xff, 0xff, 0xff };
 static u8 da9210_irq_clr[] = { DA9210_REG_MASK_A, 0xff, 0xff };
 
-static struct i2c_msg da9xxx_msgs[3] = {
-	{
-		.addr = 0x58,
-		.len = ARRAY_SIZE(da9063_irq_clr),
-		.buf = da9063_irq_clr,
-	}, {
-		.addr = 0x68,
-		.len = ARRAY_SIZE(da9210_irq_clr),
-		.buf = da9210_irq_clr,
-	}, {
-		.addr = 0x70,
-		.len = ARRAY_SIZE(da9210_irq_clr),
-		.buf = da9210_irq_clr,
-	},
+static struct i2c_msg da9063_msgs = {
+	.len = ARRAY_SIZE(da9063_irq_clr),
+	.buf = da9063_irq_clr,
+};
+
+static struct i2c_msg da9210_msgs = {
+	.len = ARRAY_SIZE(da9210_irq_clr),
+	.buf = da9210_irq_clr,
+};
+
+static const struct of_device_id rcar_gen2_quirk_match[] = {
+	{ .compatible = "dlg,da9063", .data = &da9063_msgs },
+	{ .compatible = "dlg,da9210", .data = &da9210_msgs },
+	{},
 };
 
 static int regulator_quirk_notify(struct notifier_block *nb,
 				  unsigned long action, void *data)
 {
+	struct regulator_quirk *pos, *tmp;
 	struct device *dev = data;
 	struct i2c_client *client;
 	static bool done;
+	int ret;
 	u32 mon;
 
 	if (done)
@@ -88,17 +101,20 @@  static int regulator_quirk_notify(struct notifier_block *nb,
 	client = to_i2c_client(dev);
 	dev_dbg(dev, "Detected %s\n", client->name);
 
-	if ((client->addr == 0x58 && !strcmp(client->name, "da9063")) ||
-	    (client->addr == 0x68 && !strcmp(client->name, "da9210")) ||
-	    (client->addr == 0x70 && !strcmp(client->name, "da9210"))) {
-		int ret, len;
+	/*
+	 * Send message to all PMICs that share an IRQ line to deassert it.
+	 *
+	 * WARNING: This works only if all the PMICs are on the same I2C bus.
+	 */
+	list_for_each_entry(pos, &quirk_list, list) {
+		if (!pos->shared)
+			continue;
 
-		/* There are two DA9210 on Stout, one on the other boards. */
-		len = of_machine_is_compatible("renesas,stout") ? 3 : 2;
+		dev_info(&client->dev, "clearing %s@0x%02x interrupts\n",
+			 pos->id->compatible, pos->i2c_msg.addr);
 
-		dev_info(&client->dev, "clearing da9063/da9210 interrupts\n");
-		ret = i2c_transfer(client->adapter, da9xxx_msgs, len);
-		if (ret != len)
+		ret = i2c_transfer(client->adapter, &pos->i2c_msg, 1);
+		if (ret != 1)
 			dev_err(&client->dev, "i2c error %d\n", ret);
 	}
 
@@ -111,6 +127,11 @@  static int regulator_quirk_notify(struct notifier_block *nb,
 remove:
 	dev_info(dev, "IRQ2 is not asserted, removing quirk\n");
 
+	list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
+		list_del(&pos->list);
+		kfree(pos);
+	}
+
 	done = true;
 	iounmap(irqc);
 	return 0;
@@ -122,7 +143,13 @@  static struct notifier_block regulator_quirk_nb = {
 
 static int __init rcar_gen2_regulator_quirk(void)
 {
-	u32 mon;
+	struct device_node *np;
+	const struct of_device_id *id;
+	struct regulator_quirk *quirk;
+	struct regulator_quirk *pos;
+	struct of_phandle_args *argsa, *argsb;
+	u32 mon, addr;
+	int ret;
 
 	if (!of_machine_is_compatible("renesas,koelsch") &&
 	    !of_machine_is_compatible("renesas,lager") &&
@@ -130,6 +157,45 @@  static int __init rcar_gen2_regulator_quirk(void)
 	    !of_machine_is_compatible("renesas,gose"))
 		return -ENODEV;
 
+	for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
+		if (!np || !of_device_is_available(np))
+			break;
+
+		quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);
+
+		argsa = &quirk->irq_args;
+		memcpy(&quirk->i2c_msg, id->data, sizeof(quirk->i2c_msg));
+
+		ret = of_property_read_u32(np, "reg", &addr);
+		if (ret)
+			return ret;
+
+		quirk->id = id;
+		quirk->i2c_msg.addr = addr;
+		quirk->shared = false;
+
+		ret = of_irq_parse_one(np, 0, &quirk->irq_args);
+		if (ret)
+			return ret;
+
+		list_for_each_entry(pos, &quirk_list, list) {
+			argsb = &pos->irq_args;
+
+			if (argsa->args_count != argsb->args_count)
+				continue;
+
+			ret = memcmp(argsa->args, argsb->args,
+				     argsa->args_count *
+				     sizeof(argsa->args[0]));
+			if (!ret) {
+				pos->shared = true;
+				quirk->shared = true;
+			}
+		}
+
+		list_add_tail(&quirk->list, &quirk_list);
+	}
+
 	irqc = ioremap(IRQC_BASE, PAGE_SIZE);
 	if (!irqc)
 		return -ENOMEM;