diff mbox series

USB: typec: tps6598x: use device 'type' field to identify devices

Message ID 20231123210021.463122-1-alex@shruggie.ro (mailing list archive)
State New, archived
Headers show
Series USB: typec: tps6598x: use device 'type' field to identify devices | expand

Commit Message

Alexandru Ardelean Nov. 23, 2023, 9 p.m. UTC
Using the {of_}device_is_compatible function(s) is not too expensive.
But since the driver already needs to match for the 'struct tipd_data'
device parameters (via device_get_match_data()), we can add a simple 'type'
field.

This adds a minor optimization in certain operations, where we the check
for TPS25750 (or Apple CD321X) is a bit faster.

Signed-off-by: Alexandru Ardelean <alex@shruggie.ro>
---
 drivers/usb/typec/tipd/core.c | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)

Comments

Heikki Krogerus Nov. 29, 2023, 2:26 p.m. UTC | #1
Hi,

Sorry to keep you waiting.

On Thu, Nov 23, 2023 at 11:00:21PM +0200, Alexandru Ardelean wrote:
> Using the {of_}device_is_compatible function(s) is not too expensive.
> But since the driver already needs to match for the 'struct tipd_data'
> device parameters (via device_get_match_data()), we can add a simple 'type'
> field.
> 
> This adds a minor optimization in certain operations, where we the check
> for TPS25750 (or Apple CD321X) is a bit faster.
> 
> Signed-off-by: Alexandru Ardelean <alex@shruggie.ro>
> ---
>  drivers/usb/typec/tipd/core.c | 34 ++++++++++++++++++++++------------
>  1 file changed, 22 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
> index fbd23de5c5cb..69d3e11bb30c 100644
> --- a/drivers/usb/typec/tipd/core.c
> +++ b/drivers/usb/typec/tipd/core.c
> @@ -105,7 +105,14 @@ static const char *const modes[] = {
>  
>  struct tps6598x;
>  
> +enum tipd_type {
> +	TIPD_TYPE_TI_TPS6598X,
> +	TIPD_TYPE_APPLE_CD321X,
> +	TIPD_TYPE_TI_TPS25750X,
> +};
> +
>  struct tipd_data {
> +	enum tipd_type type;
>  	irq_handler_t irq_handler;
>  	int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node);
>  	void (*trace_power_status)(u16 status);

Why not just match against the structures themselves?

        if (tps->data == &tps25750_data)
                ...

> @@ -1195,7 +1202,6 @@ tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
>  
>  static int tps6598x_probe(struct i2c_client *client)
>  {
> -	struct device_node *np = client->dev.of_node;
>  	struct tps6598x *tps;
>  	struct fwnode_handle *fwnode;
>  	u32 status;
> @@ -1211,11 +1217,19 @@ static int tps6598x_probe(struct i2c_client *client)
>  	mutex_init(&tps->lock);
>  	tps->dev = &client->dev;
>  
> +	if (dev_fwnode(tps->dev))
> +		tps->data = device_get_match_data(tps->dev);
> +	else
> +		tps->data = i2c_get_match_data(client);
> +
> +	if (!tps->data)
> +		return -EINVAL;
> +
>  	tps->regmap = devm_regmap_init_i2c(client, &tps6598x_regmap_config);
>  	if (IS_ERR(tps->regmap))
>  		return PTR_ERR(tps->regmap);
>  
> -	is_tps25750 = device_is_compatible(tps->dev, "ti,tps25750");
> +	is_tps25750 = (tps->data->type == TIPD_TYPE_TI_TPS25750X);
>  	if (!is_tps25750) {
>  		ret = tps6598x_read32(tps, TPS_REG_VID, &vid);
>  		if (ret < 0 || !vid)
> @@ -1229,7 +1243,7 @@ static int tps6598x_probe(struct i2c_client *client)
>  	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
>  		tps->i2c_protocol = true;
>  
> -	if (np && of_device_is_compatible(np, "apple,cd321x")) {
> +	if (tps->data->type == TIPD_TYPE_APPLE_CD321X) {
>  		/* Switch CD321X chips to the correct system power state */
>  		ret = cd321x_switch_power_state(tps, TPS_SYSTEM_POWER_STATE_S0);
>  		if (ret)
> @@ -1247,13 +1261,6 @@ static int tps6598x_probe(struct i2c_client *client)
>  			TPS_REG_INT_PLUG_EVENT;
>  	}
>  
> -	if (dev_fwnode(tps->dev))
> -		tps->data = device_get_match_data(tps->dev);
> -	else
> -		tps->data = i2c_get_match_data(client);
> -	if (!tps->data)
> -		return -EINVAL;
> -
>  	/* Make sure the controller has application firmware running */
>  	ret = tps6598x_check_mode(tps);
>  	if (ret < 0)
> @@ -1366,7 +1373,7 @@ static void tps6598x_remove(struct i2c_client *client)
>  	usb_role_switch_put(tps->role_sw);
>  
>  	/* Reset PD controller to remove any applied patch */
> -	if (device_is_compatible(tps->dev, "ti,tps25750"))
> +	if (tps->data->type == TIPD_TYPE_TI_TPS25750X)
>  		tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0);
>  }
>  
> @@ -1396,7 +1403,7 @@ static int __maybe_unused tps6598x_resume(struct device *dev)
>  	if (ret < 0)
>  		return ret;
>  
> -	if (device_is_compatible(tps->dev, "ti,tps25750") && ret == TPS_MODE_PTCH) {
> +	if (tps->data->type == TIPD_TYPE_TI_TPS25750X && ret == TPS_MODE_PTCH) {
>  		ret = tps25750_init(tps);
>  		if (ret)
>  			return ret;
> @@ -1419,6 +1426,7 @@ static const struct dev_pm_ops tps6598x_pm_ops = {
>  };
>  
>  static const struct tipd_data cd321x_data = {
> +	.type = TIPD_TYPE_APPLE_CD321X,
>  	.irq_handler = cd321x_interrupt,
>  	.register_port = tps6598x_register_port,
>  	.trace_power_status = trace_tps6598x_power_status,
> @@ -1426,6 +1434,7 @@ static const struct tipd_data cd321x_data = {
>  };
>  
>  static const struct tipd_data tps6598x_data = {
> +	.type = TIPD_TYPE_TI_TPS6598X,
>  	.irq_handler = tps6598x_interrupt,
>  	.register_port = tps6598x_register_port,
>  	.trace_power_status = trace_tps6598x_power_status,
> @@ -1433,6 +1442,7 @@ static const struct tipd_data tps6598x_data = {
>  };
>  
>  static const struct tipd_data tps25750_data = {
> +	.type = TIPD_TYPE_TI_TPS25750X,
>  	.irq_handler = tps25750_interrupt,
>  	.register_port = tps25750_register_port,
>  	.trace_power_status = trace_tps25750_power_status,
> -- 
> 2.42.1

thanks,
Alexandru Ardelean Nov. 29, 2023, 6:45 p.m. UTC | #2
On Wed, Nov 29, 2023 at 4:26 PM Heikki Krogerus
<heikki.krogerus@linux.intel.com> wrote:
>
> Hi,
>
> Sorry to keep you waiting.

No worries.
I know how this works: maintainers do what they can, when they can.

>
> On Thu, Nov 23, 2023 at 11:00:21PM +0200, Alexandru Ardelean wrote:
> > Using the {of_}device_is_compatible function(s) is not too expensive.
> > But since the driver already needs to match for the 'struct tipd_data'
> > device parameters (via device_get_match_data()), we can add a simple 'type'
> > field.
> >
> > This adds a minor optimization in certain operations, where we the check
> > for TPS25750 (or Apple CD321X) is a bit faster.
> >
> > Signed-off-by: Alexandru Ardelean <alex@shruggie.ro>
> > ---
> >  drivers/usb/typec/tipd/core.c | 34 ++++++++++++++++++++++------------
> >  1 file changed, 22 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
> > index fbd23de5c5cb..69d3e11bb30c 100644
> > --- a/drivers/usb/typec/tipd/core.c
> > +++ b/drivers/usb/typec/tipd/core.c
> > @@ -105,7 +105,14 @@ static const char *const modes[] = {
> >
> >  struct tps6598x;
> >
> > +enum tipd_type {
> > +     TIPD_TYPE_TI_TPS6598X,
> > +     TIPD_TYPE_APPLE_CD321X,
> > +     TIPD_TYPE_TI_TPS25750X,
> > +};
> > +
> >  struct tipd_data {
> > +     enum tipd_type type;
> >       irq_handler_t irq_handler;
> >       int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node);
> >       void (*trace_power_status)(u16 status);
>
> Why not just match against the structures themselves?
>
>         if (tps->data == &tps25750_data)

Sure.
This version also works.
I've been more accustomed to the enum version.
Will update.

As a broader context, this patch came along from trying to backport
some patches back to 5.15.
device_is_compatible() is not present i 5.15
of_device_is_compatible is present there.
It seemed like doing a neutral version (between 5.15 and latest
kernel) looks like a good idea.

>                 ...
>
> > @@ -1195,7 +1202,6 @@ tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
> >
> >  static int tps6598x_probe(struct i2c_client *client)
> >  {
> > -     struct device_node *np = client->dev.of_node;
> >       struct tps6598x *tps;
> >       struct fwnode_handle *fwnode;
> >       u32 status;
> > @@ -1211,11 +1217,19 @@ static int tps6598x_probe(struct i2c_client *client)
> >       mutex_init(&tps->lock);
> >       tps->dev = &client->dev;
> >
> > +     if (dev_fwnode(tps->dev))
> > +             tps->data = device_get_match_data(tps->dev);
> > +     else
> > +             tps->data = i2c_get_match_data(client);
> > +
> > +     if (!tps->data)
> > +             return -EINVAL;
> > +
> >       tps->regmap = devm_regmap_init_i2c(client, &tps6598x_regmap_config);
> >       if (IS_ERR(tps->regmap))
> >               return PTR_ERR(tps->regmap);
> >
> > -     is_tps25750 = device_is_compatible(tps->dev, "ti,tps25750");
> > +     is_tps25750 = (tps->data->type == TIPD_TYPE_TI_TPS25750X);
> >       if (!is_tps25750) {
> >               ret = tps6598x_read32(tps, TPS_REG_VID, &vid);
> >               if (ret < 0 || !vid)
> > @@ -1229,7 +1243,7 @@ static int tps6598x_probe(struct i2c_client *client)
> >       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
> >               tps->i2c_protocol = true;
> >
> > -     if (np && of_device_is_compatible(np, "apple,cd321x")) {
> > +     if (tps->data->type == TIPD_TYPE_APPLE_CD321X) {
> >               /* Switch CD321X chips to the correct system power state */
> >               ret = cd321x_switch_power_state(tps, TPS_SYSTEM_POWER_STATE_S0);
> >               if (ret)
> > @@ -1247,13 +1261,6 @@ static int tps6598x_probe(struct i2c_client *client)
> >                       TPS_REG_INT_PLUG_EVENT;
> >       }
> >
> > -     if (dev_fwnode(tps->dev))
> > -             tps->data = device_get_match_data(tps->dev);
> > -     else
> > -             tps->data = i2c_get_match_data(client);
> > -     if (!tps->data)
> > -             return -EINVAL;
> > -
> >       /* Make sure the controller has application firmware running */
> >       ret = tps6598x_check_mode(tps);
> >       if (ret < 0)
> > @@ -1366,7 +1373,7 @@ static void tps6598x_remove(struct i2c_client *client)
> >       usb_role_switch_put(tps->role_sw);
> >
> >       /* Reset PD controller to remove any applied patch */
> > -     if (device_is_compatible(tps->dev, "ti,tps25750"))
> > +     if (tps->data->type == TIPD_TYPE_TI_TPS25750X)
> >               tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0);
> >  }
> >
> > @@ -1396,7 +1403,7 @@ static int __maybe_unused tps6598x_resume(struct device *dev)
> >       if (ret < 0)
> >               return ret;
> >
> > -     if (device_is_compatible(tps->dev, "ti,tps25750") && ret == TPS_MODE_PTCH) {
> > +     if (tps->data->type == TIPD_TYPE_TI_TPS25750X && ret == TPS_MODE_PTCH) {
> >               ret = tps25750_init(tps);
> >               if (ret)
> >                       return ret;
> > @@ -1419,6 +1426,7 @@ static const struct dev_pm_ops tps6598x_pm_ops = {
> >  };
> >
> >  static const struct tipd_data cd321x_data = {
> > +     .type = TIPD_TYPE_APPLE_CD321X,
> >       .irq_handler = cd321x_interrupt,
> >       .register_port = tps6598x_register_port,
> >       .trace_power_status = trace_tps6598x_power_status,
> > @@ -1426,6 +1434,7 @@ static const struct tipd_data cd321x_data = {
> >  };
> >
> >  static const struct tipd_data tps6598x_data = {
> > +     .type = TIPD_TYPE_TI_TPS6598X,
> >       .irq_handler = tps6598x_interrupt,
> >       .register_port = tps6598x_register_port,
> >       .trace_power_status = trace_tps6598x_power_status,
> > @@ -1433,6 +1442,7 @@ static const struct tipd_data tps6598x_data = {
> >  };
> >
> >  static const struct tipd_data tps25750_data = {
> > +     .type = TIPD_TYPE_TI_TPS25750X,
> >       .irq_handler = tps25750_interrupt,
> >       .register_port = tps25750_register_port,
> >       .trace_power_status = trace_tps25750_power_status,
> > --
> > 2.42.1
>
> thanks,
>
> --
> heikki
Roger Quadros Nov. 30, 2023, 9:13 a.m. UTC | #3
Hi,

On 29/11/2023 16:26, Heikki Krogerus wrote:
> Hi,
> 
> Sorry to keep you waiting.
> 
> On Thu, Nov 23, 2023 at 11:00:21PM +0200, Alexandru Ardelean wrote:
>> Using the {of_}device_is_compatible function(s) is not too expensive.
>> But since the driver already needs to match for the 'struct tipd_data'
>> device parameters (via device_get_match_data()), we can add a simple 'type'
>> field.
>>
>> This adds a minor optimization in certain operations, where we the check
>> for TPS25750 (or Apple CD321X) is a bit faster.
>>
>> Signed-off-by: Alexandru Ardelean <alex@shruggie.ro>
>> ---
>>  drivers/usb/typec/tipd/core.c | 34 ++++++++++++++++++++++------------
>>  1 file changed, 22 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
>> index fbd23de5c5cb..69d3e11bb30c 100644
>> --- a/drivers/usb/typec/tipd/core.c
>> +++ b/drivers/usb/typec/tipd/core.c
>> @@ -105,7 +105,14 @@ static const char *const modes[] = {
>>  
>>  struct tps6598x;
>>  
>> +enum tipd_type {
>> +	TIPD_TYPE_TI_TPS6598X,
>> +	TIPD_TYPE_APPLE_CD321X,
>> +	TIPD_TYPE_TI_TPS25750X,
>> +};
>> +
>>  struct tipd_data {
>> +	enum tipd_type type;
>>  	irq_handler_t irq_handler;
>>  	int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node);
>>  	void (*trace_power_status)(u16 status);
> 
> Why not just match against the structures themselves?
> 
>         if (tps->data == &tps25750_data)
>                 ...

Then you need to declare tps25750_data and friends at the top of the file?

A better approach might be to have type agnostic quirk flags for the special
behavior required for different types. This way, multiple devices can share
the same quirk if needed.

e.g.
NEEDS_POWER_UP instead of TIPD_TYPE_APPLE_CD321X
SKIP_VID_READ instead of TIPD_TYPE_TI_TPS25750X
INIT_ON_RESUME instead of TIPD_TYPE_TI_TPS25750X

Also rename cd321x_switch_power_state() to tps6598x_switch_power_state().

> 
>> @@ -1195,7 +1202,6 @@ tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
>>  
>>  static int tps6598x_probe(struct i2c_client *client)
>>  {
>> -	struct device_node *np = client->dev.of_node;
>>  	struct tps6598x *tps;
>>  	struct fwnode_handle *fwnode;
>>  	u32 status;
>> @@ -1211,11 +1217,19 @@ static int tps6598x_probe(struct i2c_client *client)
>>  	mutex_init(&tps->lock);
>>  	tps->dev = &client->dev;
>>  
>> +	if (dev_fwnode(tps->dev))
>> +		tps->data = device_get_match_data(tps->dev);
>> +	else
>> +		tps->data = i2c_get_match_data(client);
>> +
>> +	if (!tps->data)
>> +		return -EINVAL;
>> +
>>  	tps->regmap = devm_regmap_init_i2c(client, &tps6598x_regmap_config);
>>  	if (IS_ERR(tps->regmap))
>>  		return PTR_ERR(tps->regmap);
>>  
>> -	is_tps25750 = device_is_compatible(tps->dev, "ti,tps25750");
>> +	is_tps25750 = (tps->data->type == TIPD_TYPE_TI_TPS25750X);
>>  	if (!is_tps25750) {
>>  		ret = tps6598x_read32(tps, TPS_REG_VID, &vid);
>>  		if (ret < 0 || !vid)
>> @@ -1229,7 +1243,7 @@ static int tps6598x_probe(struct i2c_client *client)
>>  	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
>>  		tps->i2c_protocol = true;
>>  
>> -	if (np && of_device_is_compatible(np, "apple,cd321x")) {
>> +	if (tps->data->type == TIPD_TYPE_APPLE_CD321X) {
>>  		/* Switch CD321X chips to the correct system power state */
>>  		ret = cd321x_switch_power_state(tps, TPS_SYSTEM_POWER_STATE_S0);
>>  		if (ret)
>> @@ -1247,13 +1261,6 @@ static int tps6598x_probe(struct i2c_client *client)
>>  			TPS_REG_INT_PLUG_EVENT;
>>  	}
>>  
>> -	if (dev_fwnode(tps->dev))
>> -		tps->data = device_get_match_data(tps->dev);
>> -	else
>> -		tps->data = i2c_get_match_data(client);
>> -	if (!tps->data)
>> -		return -EINVAL;
>> -
>>  	/* Make sure the controller has application firmware running */
>>  	ret = tps6598x_check_mode(tps);
>>  	if (ret < 0)
>> @@ -1366,7 +1373,7 @@ static void tps6598x_remove(struct i2c_client *client)
>>  	usb_role_switch_put(tps->role_sw);
>>  
>>  	/* Reset PD controller to remove any applied patch */
>> -	if (device_is_compatible(tps->dev, "ti,tps25750"))
>> +	if (tps->data->type == TIPD_TYPE_TI_TPS25750X)
>>  		tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0);
>>  }
>>  
>> @@ -1396,7 +1403,7 @@ static int __maybe_unused tps6598x_resume(struct device *dev)
>>  	if (ret < 0)
>>  		return ret;
>>  
>> -	if (device_is_compatible(tps->dev, "ti,tps25750") && ret == TPS_MODE_PTCH) {
>> +	if (tps->data->type == TIPD_TYPE_TI_TPS25750X && ret == TPS_MODE_PTCH) {
>>  		ret = tps25750_init(tps);
>>  		if (ret)
>>  			return ret;
>> @@ -1419,6 +1426,7 @@ static const struct dev_pm_ops tps6598x_pm_ops = {
>>  };
>>  
>>  static const struct tipd_data cd321x_data = {
>> +	.type = TIPD_TYPE_APPLE_CD321X,
>>  	.irq_handler = cd321x_interrupt,
>>  	.register_port = tps6598x_register_port,
>>  	.trace_power_status = trace_tps6598x_power_status,
>> @@ -1426,6 +1434,7 @@ static const struct tipd_data cd321x_data = {
>>  };
>>  
>>  static const struct tipd_data tps6598x_data = {
>> +	.type = TIPD_TYPE_TI_TPS6598X,
>>  	.irq_handler = tps6598x_interrupt,
>>  	.register_port = tps6598x_register_port,
>>  	.trace_power_status = trace_tps6598x_power_status,
>> @@ -1433,6 +1442,7 @@ static const struct tipd_data tps6598x_data = {
>>  };
>>  
>>  static const struct tipd_data tps25750_data = {
>> +	.type = TIPD_TYPE_TI_TPS25750X,
>>  	.irq_handler = tps25750_interrupt,
>>  	.register_port = tps25750_register_port,
>>  	.trace_power_status = trace_tps25750_power_status,
>> -- 
>> 2.42.1
> 
> thanks,
>
Heikki Krogerus Nov. 30, 2023, 10:54 a.m. UTC | #4
Hi Roger,

> > Why not just match against the structures themselves?
> > 
> >         if (tps->data == &tps25750_data)
> >                 ...
> 
> Then you need to declare tps25750_data and friends at the top of the file?
> 
> A better approach might be to have type agnostic quirk flags for the special
> behavior required for different types. This way, multiple devices can share
> the same quirk if needed.
> 
> e.g.
> NEEDS_POWER_UP instead of TIPD_TYPE_APPLE_CD321X
> SKIP_VID_READ instead of TIPD_TYPE_TI_TPS25750X
> INIT_ON_RESUME instead of TIPD_TYPE_TI_TPS25750X
> 
> Also rename cd321x_switch_power_state() to tps6598x_switch_power_state().

No. Functions like that isolate cd321x specific functionality into an
actual "function" just like they should.

Quirk flags mean that if something breaks, it will almost always break
for everybody (there is no real isolation with quirk flags), and when
things are fixed and when features are added, we are forced to always
"dance" around those quirk flags - you always have to consider them.

Platform/device type checks are just as bad IMO, but in one way they
are better than quirk flags. There is no question about what a
platform check is checking, but quirk flags can so easily become
incomprehensible (just what exactly does it mean when you say
NEEDS_POWER_UP, SKIP_VID_READ and so on (you would need to document
those quirks, which is waste of effort, and in reality nobody will do).

In case of tipd/code.c, it should be converted into a library that
only has the common/shared functionality. CD321, TPS2579x, TPS6598x
and what ever there is, then will have a glue driver that handles
everything that specific for their controller type.

Before this driver is reorganised like that (any volunteers?), we'll
have the PD controller type checks, but quirk flags we will not have.

In general, you should only use quirk flags if there is no other
way to move forward - they are the last resort. They are dangerous,
and even in the best case they reduce the maintenability of the code.

thanks,
Roger Quadros Nov. 30, 2023, 1:30 p.m. UTC | #5
Hi Heikki,

On 30/11/2023 12:54, Heikki Krogerus wrote:
> Hi Roger,
> 
>>> Why not just match against the structures themselves?
>>>
>>>         if (tps->data == &tps25750_data)
>>>                 ...
>>
>> Then you need to declare tps25750_data and friends at the top of the file?
>>
>> A better approach might be to have type agnostic quirk flags for the special
>> behavior required for different types. This way, multiple devices can share
>> the same quirk if needed.
>>
>> e.g.
>> NEEDS_POWER_UP instead of TIPD_TYPE_APPLE_CD321X
>> SKIP_VID_READ instead of TIPD_TYPE_TI_TPS25750X
>> INIT_ON_RESUME instead of TIPD_TYPE_TI_TPS25750X
>>
>> Also rename cd321x_switch_power_state() to tps6598x_switch_power_state().
> 
> No. Functions like that isolate cd321x specific functionality into an
> actual "function" just like they should.
> 
> Quirk flags mean that if something breaks, it will almost always break
> for everybody (there is no real isolation with quirk flags), and when
> things are fixed and when features are added, we are forced to always
> "dance" around those quirk flags - you always have to consider them.
> 
> Platform/device type checks are just as bad IMO, but in one way they
> are better than quirk flags. There is no question about what a
> platform check is checking, but quirk flags can so easily become
> incomprehensible (just what exactly does it mean when you say
> NEEDS_POWER_UP, SKIP_VID_READ and so on (you would need to document
> those quirks, which is waste of effort, and in reality nobody will do).
> 
> In case of tipd/code.c, it should be converted into a library that
> only has the common/shared functionality. CD321, TPS2579x, TPS6598x
> and what ever there is, then will have a glue driver that handles
> everything that specific for their controller type.

Do you mean that you want to treat the 3 devices as different incompatible devices
so each one has a separate driver which warrants for a different DT binding
for each and also Kconfig symbol?

> 
> Before this driver is reorganised like that (any volunteers?), we'll
> have the PD controller type checks, but quirk flags we will not have.
> 
> In general, you should only use quirk flags if there is no other
> way to move forward - they are the last resort. They are dangerous,
> and even in the best case they reduce the maintenability of the code.
> 
> thanks,
>
Heikki Krogerus Dec. 1, 2023, 8:10 a.m. UTC | #6
Hi Roger,

On Thu, Nov 30, 2023 at 03:30:54PM +0200, Roger Quadros wrote:
> Hi Heikki,
> 
> On 30/11/2023 12:54, Heikki Krogerus wrote:
> > Hi Roger,
> > 
> >>> Why not just match against the structures themselves?
> >>>
> >>>         if (tps->data == &tps25750_data)
> >>>                 ...
> >>
> >> Then you need to declare tps25750_data and friends at the top of the file?
> >>
> >> A better approach might be to have type agnostic quirk flags for the special
> >> behavior required for different types. This way, multiple devices can share
> >> the same quirk if needed.
> >>
> >> e.g.
> >> NEEDS_POWER_UP instead of TIPD_TYPE_APPLE_CD321X
> >> SKIP_VID_READ instead of TIPD_TYPE_TI_TPS25750X
> >> INIT_ON_RESUME instead of TIPD_TYPE_TI_TPS25750X
> >>
> >> Also rename cd321x_switch_power_state() to tps6598x_switch_power_state().
> > 
> > No. Functions like that isolate cd321x specific functionality into an
> > actual "function" just like they should.
> > 
> > Quirk flags mean that if something breaks, it will almost always break
> > for everybody (there is no real isolation with quirk flags), and when
> > things are fixed and when features are added, we are forced to always
> > "dance" around those quirk flags - you always have to consider them.
> > 
> > Platform/device type checks are just as bad IMO, but in one way they
> > are better than quirk flags. There is no question about what a
> > platform check is checking, but quirk flags can so easily become
> > incomprehensible (just what exactly does it mean when you say
> > NEEDS_POWER_UP, SKIP_VID_READ and so on (you would need to document
> > those quirks, which is waste of effort, and in reality nobody will do).
> > 
> > In case of tipd/code.c, it should be converted into a library that
> > only has the common/shared functionality. CD321, TPS2579x, TPS6598x
> > and what ever there is, then will have a glue driver that handles
> > everything that specific for their controller type.
> 
> Do you mean that you want to treat the 3 devices as different incompatible devices
> so each one has a separate driver which warrants for a different DT binding
> for each and also Kconfig symbol?

I did not consider that, I was thinking that we would still continue
with just one probe driver for all of these, but now that you
mentioned this, maybe it would actually make sense to have separate
full fledged probing drivers for all of these. Do you think it would
be better like that? Would it be a problem to split the bindings?

thanks,
Roger Quadros Dec. 1, 2023, 10:57 a.m. UTC | #7
+Rob & Krzysztof

On 01/12/2023 10:10, Heikki Krogerus wrote:
> Hi Roger,
> 
> On Thu, Nov 30, 2023 at 03:30:54PM +0200, Roger Quadros wrote:
>> Hi Heikki,
>>
>> On 30/11/2023 12:54, Heikki Krogerus wrote:
>>> Hi Roger,
>>>
>>>>> Why not just match against the structures themselves?
>>>>>
>>>>>         if (tps->data == &tps25750_data)
>>>>>                 ...
>>>>
>>>> Then you need to declare tps25750_data and friends at the top of the file?
>>>>
>>>> A better approach might be to have type agnostic quirk flags for the special
>>>> behavior required for different types. This way, multiple devices can share
>>>> the same quirk if needed.
>>>>
>>>> e.g.
>>>> NEEDS_POWER_UP instead of TIPD_TYPE_APPLE_CD321X
>>>> SKIP_VID_READ instead of TIPD_TYPE_TI_TPS25750X
>>>> INIT_ON_RESUME instead of TIPD_TYPE_TI_TPS25750X
>>>>
>>>> Also rename cd321x_switch_power_state() to tps6598x_switch_power_state().
>>>
>>> No. Functions like that isolate cd321x specific functionality into an
>>> actual "function" just like they should.
>>>
>>> Quirk flags mean that if something breaks, it will almost always break
>>> for everybody (there is no real isolation with quirk flags), and when
>>> things are fixed and when features are added, we are forced to always
>>> "dance" around those quirk flags - you always have to consider them.
>>>
>>> Platform/device type checks are just as bad IMO, but in one way they
>>> are better than quirk flags. There is no question about what a
>>> platform check is checking, but quirk flags can so easily become
>>> incomprehensible (just what exactly does it mean when you say
>>> NEEDS_POWER_UP, SKIP_VID_READ and so on (you would need to document
>>> those quirks, which is waste of effort, and in reality nobody will do).
>>>
>>> In case of tipd/code.c, it should be converted into a library that
>>> only has the common/shared functionality. CD321, TPS2579x, TPS6598x
>>> and what ever there is, then will have a glue driver that handles
>>> everything that specific for their controller type.
>>
>> Do you mean that you want to treat the 3 devices as different incompatible devices
>> so each one has a separate driver which warrants for a different DT binding
>> for each and also Kconfig symbol?
> 
> I did not consider that, I was thinking that we would still continue
> with just one probe driver for all of these, but now that you
> mentioned this, maybe it would actually make sense to have separate
> full fledged probing drivers for all of these. Do you think it would
> be better like that? Would it be a problem to split the bindings?

I'm no DT expert but looks like an overkill to me.
Krzysztof Kozlowski Dec. 1, 2023, 12:12 p.m. UTC | #8
On 01/12/2023 11:57, Roger Quadros wrote:
> +Rob & Krzysztof
> 
> On 01/12/2023 10:10, Heikki Krogerus wrote:
>> Hi Roger,
>>
>> On Thu, Nov 30, 2023 at 03:30:54PM +0200, Roger Quadros wrote:
>>> Hi Heikki,
>>>
>>> On 30/11/2023 12:54, Heikki Krogerus wrote:
>>>> Hi Roger,
>>>>
>>>>>> Why not just match against the structures themselves?
>>>>>>
>>>>>>         if (tps->data == &tps25750_data)
>>>>>>                 ...
>>>>>
>>>>> Then you need to declare tps25750_data and friends at the top of the file?
>>>>>
>>>>> A better approach might be to have type agnostic quirk flags for the special
>>>>> behavior required for different types. This way, multiple devices can share
>>>>> the same quirk if needed.
>>>>>
>>>>> e.g.
>>>>> NEEDS_POWER_UP instead of TIPD_TYPE_APPLE_CD321X
>>>>> SKIP_VID_READ instead of TIPD_TYPE_TI_TPS25750X
>>>>> INIT_ON_RESUME instead of TIPD_TYPE_TI_TPS25750X
>>>>>
>>>>> Also rename cd321x_switch_power_state() to tps6598x_switch_power_state().
>>>>
>>>> No. Functions like that isolate cd321x specific functionality into an
>>>> actual "function" just like they should.
>>>>
>>>> Quirk flags mean that if something breaks, it will almost always break
>>>> for everybody (there is no real isolation with quirk flags), and when
>>>> things are fixed and when features are added, we are forced to always
>>>> "dance" around those quirk flags - you always have to consider them.
>>>>
>>>> Platform/device type checks are just as bad IMO, but in one way they
>>>> are better than quirk flags. There is no question about what a
>>>> platform check is checking, but quirk flags can so easily become
>>>> incomprehensible (just what exactly does it mean when you say
>>>> NEEDS_POWER_UP, SKIP_VID_READ and so on (you would need to document
>>>> those quirks, which is waste of effort, and in reality nobody will do).
>>>>
>>>> In case of tipd/code.c, it should be converted into a library that
>>>> only has the common/shared functionality. CD321, TPS2579x, TPS6598x
>>>> and what ever there is, then will have a glue driver that handles
>>>> everything that specific for their controller type.
>>>
>>> Do you mean that you want to treat the 3 devices as different incompatible devices
>>> so each one has a separate driver which warrants for a different DT binding
>>> for each and also Kconfig symbol?
>>
>> I did not consider that, I was thinking that we would still continue
>> with just one probe driver for all of these, but now that you
>> mentioned this, maybe it would actually make sense to have separate
>> full fledged probing drivers for all of these. Do you think it would
>> be better like that? Would it be a problem to split the bindings?
> 
> I'm no DT expert but looks like an overkill to me.

Splitting or not splitting drivers has nothing to do with bindings. Does
the hardware suddenly change if you decide to do something with drivers?
No, it does not.

Best regards,
Krzysztof
diff mbox series

Patch

diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
index fbd23de5c5cb..69d3e11bb30c 100644
--- a/drivers/usb/typec/tipd/core.c
+++ b/drivers/usb/typec/tipd/core.c
@@ -105,7 +105,14 @@  static const char *const modes[] = {
 
 struct tps6598x;
 
+enum tipd_type {
+	TIPD_TYPE_TI_TPS6598X,
+	TIPD_TYPE_APPLE_CD321X,
+	TIPD_TYPE_TI_TPS25750X,
+};
+
 struct tipd_data {
+	enum tipd_type type;
 	irq_handler_t irq_handler;
 	int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node);
 	void (*trace_power_status)(u16 status);
@@ -1195,7 +1202,6 @@  tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
 
 static int tps6598x_probe(struct i2c_client *client)
 {
-	struct device_node *np = client->dev.of_node;
 	struct tps6598x *tps;
 	struct fwnode_handle *fwnode;
 	u32 status;
@@ -1211,11 +1217,19 @@  static int tps6598x_probe(struct i2c_client *client)
 	mutex_init(&tps->lock);
 	tps->dev = &client->dev;
 
+	if (dev_fwnode(tps->dev))
+		tps->data = device_get_match_data(tps->dev);
+	else
+		tps->data = i2c_get_match_data(client);
+
+	if (!tps->data)
+		return -EINVAL;
+
 	tps->regmap = devm_regmap_init_i2c(client, &tps6598x_regmap_config);
 	if (IS_ERR(tps->regmap))
 		return PTR_ERR(tps->regmap);
 
-	is_tps25750 = device_is_compatible(tps->dev, "ti,tps25750");
+	is_tps25750 = (tps->data->type == TIPD_TYPE_TI_TPS25750X);
 	if (!is_tps25750) {
 		ret = tps6598x_read32(tps, TPS_REG_VID, &vid);
 		if (ret < 0 || !vid)
@@ -1229,7 +1243,7 @@  static int tps6598x_probe(struct i2c_client *client)
 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		tps->i2c_protocol = true;
 
-	if (np && of_device_is_compatible(np, "apple,cd321x")) {
+	if (tps->data->type == TIPD_TYPE_APPLE_CD321X) {
 		/* Switch CD321X chips to the correct system power state */
 		ret = cd321x_switch_power_state(tps, TPS_SYSTEM_POWER_STATE_S0);
 		if (ret)
@@ -1247,13 +1261,6 @@  static int tps6598x_probe(struct i2c_client *client)
 			TPS_REG_INT_PLUG_EVENT;
 	}
 
-	if (dev_fwnode(tps->dev))
-		tps->data = device_get_match_data(tps->dev);
-	else
-		tps->data = i2c_get_match_data(client);
-	if (!tps->data)
-		return -EINVAL;
-
 	/* Make sure the controller has application firmware running */
 	ret = tps6598x_check_mode(tps);
 	if (ret < 0)
@@ -1366,7 +1373,7 @@  static void tps6598x_remove(struct i2c_client *client)
 	usb_role_switch_put(tps->role_sw);
 
 	/* Reset PD controller to remove any applied patch */
-	if (device_is_compatible(tps->dev, "ti,tps25750"))
+	if (tps->data->type == TIPD_TYPE_TI_TPS25750X)
 		tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0);
 }
 
@@ -1396,7 +1403,7 @@  static int __maybe_unused tps6598x_resume(struct device *dev)
 	if (ret < 0)
 		return ret;
 
-	if (device_is_compatible(tps->dev, "ti,tps25750") && ret == TPS_MODE_PTCH) {
+	if (tps->data->type == TIPD_TYPE_TI_TPS25750X && ret == TPS_MODE_PTCH) {
 		ret = tps25750_init(tps);
 		if (ret)
 			return ret;
@@ -1419,6 +1426,7 @@  static const struct dev_pm_ops tps6598x_pm_ops = {
 };
 
 static const struct tipd_data cd321x_data = {
+	.type = TIPD_TYPE_APPLE_CD321X,
 	.irq_handler = cd321x_interrupt,
 	.register_port = tps6598x_register_port,
 	.trace_power_status = trace_tps6598x_power_status,
@@ -1426,6 +1434,7 @@  static const struct tipd_data cd321x_data = {
 };
 
 static const struct tipd_data tps6598x_data = {
+	.type = TIPD_TYPE_TI_TPS6598X,
 	.irq_handler = tps6598x_interrupt,
 	.register_port = tps6598x_register_port,
 	.trace_power_status = trace_tps6598x_power_status,
@@ -1433,6 +1442,7 @@  static const struct tipd_data tps6598x_data = {
 };
 
 static const struct tipd_data tps25750_data = {
+	.type = TIPD_TYPE_TI_TPS25750X,
 	.irq_handler = tps25750_interrupt,
 	.register_port = tps25750_register_port,
 	.trace_power_status = trace_tps25750_power_status,