mbox series

[v5,00/10] platform/chrome: Introduce DT hardware prober

Message ID 20240822092006.3134096-1-wenst@chromium.org
Headers show
Series platform/chrome: Introduce DT hardware prober | expand

Message

Chen-Yu Tsai Aug. 22, 2024, 9:19 a.m. UTC
Hi everyone,

This is v5 of my "of: Introduce hardware prober driver" [1] series.
v5 mainly addresses comments from Andy.

v2 continued Doug's "of: device: Support 2nd sources of probeable but
undiscoverable devices" [2] series, but follows the scheme suggested by
Rob, marking all second source component device nodes as "fail-needs-probe",
and having a hardware prober driver enable the one of them.


Changes since v4:
- Link to v4: 
  https://lore.kernel.org/all/20240808095931.2649657-1-wenst@chromium.org/
- Patch 1 "of: dynamic: Add of_changeset_update_prop_string"
  - Use modern designated initializer for |prop|
- Patch 2 "regulator: Move OF-specific regulator lookup code to of_regulator.c"
  - New patch only moving code
- Patch 3 "regulator: Split up _regulator_get()"
  - New patch splitting existing code into smaller functions
- Patch 4 "regulator: Do pure DT regulator lookup in of_regulator_bulk_get_all()"
  - Was "regulator: Add regulator_of_get_optional() for pure DT" in v4
  - Add OF-specific _of_regulator_get() function
  - Rename regulator_of_get_optional() to of_regulator_get_optional() for
    consistency
  - Make of_regulator_get_optional() static, as it is only used internally
  - Convert of_regulator_bulk_get_all()
- Patch 5 "gpiolib: Add gpio_property_name_length()"
  - New patch, split out from patch 7/8
- Patch 6 "i2c: Introduce OF component probe function"
  - Split code into helper functions
  - Use scoped helpers and __free() to reduce error path
- Patch 7 "i2c: of-prober: Add regulator support"
  - Split out GPIO handling as patch 8
  - Rewrote using of_regulator_bulk_get_all()
  - Replaced "regulators" with "regulator supplies" in debug messages
- Patch 8 "i2c: of-prober: Add GPIO support"
  - New patch split out from patch 7
  - Moved GPIO property name check to common function in gpiolib.c in new
    patch
  - Moved i2c_of_probe_free_gpios() into for_each_child_of_node_scoped()
  - Rewrote in gpiod_*_array-esque fashion
- Patch 9 "platform/chrome: Introduce device tree hardware prober"
  - Fix Kconfig dependency
  - Update copyright year
  - Drop "linux/of.h" header
  - Include "linux/errno.h"
  - Move |int ret| declaration to top of block
  - Return -ENODEV on no match instead of 0
  - Unregister platform driver and device unconditionally after previous
    change
- Patch 10 "arm64: dts: mediatek: mt8173-elm-hana: Mark touchscreens and
	    trackpads as fail"
  - Rebased

Changes since v3:
- Patch 1 "of: dynamic: Add of_changeset_update_prop_string"
  - Use new __of_prop_free() helper (helper was added by Rob in 2024/04)
  - Add new line before header declaration
- Patch 2 "regulator: Add regulator_of_get_optional() for pure DT"
  - New patch
- Patch 3 "i2c: Introduce OF component probe function"
  - Complete kernel-doc
  - Return different error if I2C controller is disabled
  - Expand comment to explain assumptions and constraints
  - Split for-loop finding target node and operations on target node
  - Add missing i2c_put_adapter()
  - Move prober code to separate file
- Patch 4 "i2c: of-prober: Add GPIO and regulator support"
  - New patch
- Patch 5 "platform/chrome: Introduce device tree hardware prober"
  - Include linux/init.h
  - Rewrite for loop in driver probe function as suggested by Andy
  - Make prober driver buildable as module
  - Ignore prober errors other than probe deferral
- Patch 6 "arm64: dts: mediatek: mt8173-elm-hana: Mark touchscreens and trackpads as fail"
  - Rebased

Patch "arm64: dts: mediatek: mt8173-elm-hana: Add G2touch G7500 touchscreen"
was merged separately and thus removed from this series.

Changes since v2:
- Added of_changeset_update_prop_string()
- Moved generic I2C code to the I2C core
- Moved remaining platform specific code to platform/chrome/
- Switched to of_node_is_available() to check if node is enabled.
- Switched to OF changeset API to update status property
- I2C probe helper function now accepts "struct device *dev" instead to
  reduce line length and dereferences
- Moved "ret = 0" to just before for_each_child_of_node(i2c_node, node)
- Depend on rather than select CONFIG_I2C
- Copied machine check to driver init function
- Explicitly mentioned "device tree" or OF in driver name, description
  and Kconfig symbol
- Dropped filename from inside the file
- Made loop variable size_t (instead of unsigned int as Andy asked)
- Switched to PLATFORM_DEVID_NONE instead of raw -1
- Switched to standard goto error path pattern in hw_prober_driver_init()
- Dropped device class from status property

Patches removed from v3 and saved for later:
- of: base: Add of_device_is_fail
- of: hw_prober: Support Chromebook SKU ID based component selection
- dt-bindings: arm: mediatek: Remove SKU specific compatibles for Google Krane
- arm64: dts: mediatek: mt8183-kukui: Merge Krane device trees

For the I2C component (touchscreens and trackpads) case from the
original series, the hardware prober driver finds the particular
class of device in the device tree, gets its parent I2C adapter,
and tries to initiate a simple I2C read for each device under that
I2C bus. When it finds one that responds, it considers that one
present, marks it as "okay", and returns, letting the driver core
actually probe the device.

This works fine in most cases since these components are connected
via a ribbon cable and always have the same resources. The prober
will also grab these resources and enable them.

The other case, selecting a display panel to use based on the SKU ID
from the firmware, hit a bit of an issue with fixing the OF graph.
It has been left out since v3.

Patch 1 adds of_changeset_update_prop_string(), as requested by Rob.

Patches 2 through 4 reorganize the OF-specific regulator core code and
reworks the existing of_regulator_bulk_get_all() function to look up
regulator supplies solely using device tree nodes.

Patch 5 adds a function to the GPIO library that checks whether a
given string (property name) matches the GPIO property pattern, and
if it does, returns the length of the GPIO name.

Patch 6 implements probing the I2C bus for presence of components as
a helper function in the I2C core.

Patch 7 implements regulator supply support for the I2C component
prober.

Patch 8 implements GPIO support for the I2C component prober.

Patch 9 adds a ChromeOS specific DT hardware prober. This initial
version targets the Hana Chromebooks, probing its I2C trackpads and
touchscreens.

Patch 10 modifies the Hana device tree and marks the touchscreens
and trackpads as "fail-needs-probe", ready for the driver to probe.


The patch and build time dependencies for this series is now quite
complicated:

  of_regulator.c cleanups [1] -> regulator patches here ----
							   |
							   v
  gpio patch in -next [2] -> gpiolib patch here  -----> i2c of-prober --
								       |
                      platform/chrome device tree hardware prober <----- 
 
The regulator patches in this series depend on other cleanup patches [1]
I sent earlier. The gpiolib patch depends on a commit in -next [2]
changing the GPIO suffixes array. Patches 6 through 8 introducting i2c
of-prober depend on the first 5 patches. Patch 9, The chrome prober,
depends on patches 6 through 8.

I think it might be easier if the respective maintainers take the first
five patches for -rc1, and patches 6 through 9 go through either the i2c
or chrome trees either very late in the merge window or right after it.
Patch 10 can go in only after everything else is in. This should be
better than having an immutable branch on top of some commit in -next
for three other trees to consume.


Thanks
ChenYu

[1] https://lore.kernel.org/all/20240822072047.3097740-1-wenst@chromium.org/
[2] commit 4b91188dced8 ("gpiolib: Replace gpio_suffix_count with NULL-terminated array")

Chen-Yu Tsai (10):
  of: dynamic: Add of_changeset_update_prop_string
  regulator: Move OF-specific regulator lookup code to of_regulator.c
  regulator: Split up _regulator_get()
  regulator: Do pure DT regulator lookup in of_regulator_bulk_get_all()
  gpiolib: Add gpio_property_name_length()
  i2c: Introduce OF component probe function
  i2c: of-prober: Add regulator support
  i2c: of-prober: Add GPIO support
  platform/chrome: Introduce device tree hardware prober
  arm64: dts: mediatek: mt8173-elm-hana: Mark touchscreens and trackpads
    as fail

 .../boot/dts/mediatek/mt8173-elm-hana.dtsi    |  13 +
 arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi  |   4 +-
 drivers/gpio/gpiolib.c                        |  44 ++
 drivers/i2c/Makefile                          |   1 +
 drivers/i2c/i2c-core-of-prober.c              | 391 ++++++++++++++++++
 drivers/of/dynamic.c                          |  44 ++
 drivers/platform/chrome/Kconfig               |  11 +
 drivers/platform/chrome/Makefile              |   1 +
 .../platform/chrome/chromeos_of_hw_prober.c   | 104 +++++
 drivers/regulator/core.c                      | 139 +++----
 drivers/regulator/internal.h                  |  15 +-
 drivers/regulator/of_regulator.c              | 142 ++++++-
 include/linux/gpio/consumer.h                 |   2 +
 include/linux/i2c.h                           |   4 +
 include/linux/of.h                            |   4 +
 15 files changed, 820 insertions(+), 99 deletions(-)
 create mode 100644 drivers/i2c/i2c-core-of-prober.c
 create mode 100644 drivers/platform/chrome/chromeos_of_hw_prober.c

Comments

Rob Herring (Arm) Aug. 22, 2024, 12:32 p.m. UTC | #1
On Thu, Aug 22, 2024 at 4:20 AM Chen-Yu Tsai <wenst@chromium.org> wrote:
>
> Add a helper function to add string property updates to an OF changeset.
> This is similar to of_changeset_add_prop_string(), but instead of adding
> the property (and failing if it exists), it will update the property.
>
> This shall be used later in the DT hardware prober.
>
> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
> ---
> Changes since v4:
> - Use modern designated initializer for |prop|
>
> Changes since v3:
> - Use new __of_prop_free() helper
> - Add new line before header declaration
>
> Changes since v2:
> - New patch added in v3
> ---
>  drivers/of/dynamic.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/of.h   |  4 ++++
>  2 files changed, 48 insertions(+)

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Andy Shevchenko Aug. 22, 2024, 2:09 p.m. UTC | #2
On Thu, Aug 22, 2024 at 05:20:00PM +0800, Chen-Yu Tsai wrote:
> This adds regulator management to the I2C OF component prober.
> Components that the prober intends to probe likely require their
> regulator supplies be enabled, and GPIOs be toggled to enable them or
> bring them out of reset before they will respond to probe attempts.
> GPIOs will be handled in the next patch.
> 
> Without specific knowledge of each component's resource names or
> power sequencing requirements, the prober can only enable the
> regulator supplies all at once, and toggle the GPIOs all at once.
> Luckily, reset pins tend to be active low, while enable pins tend to
> be active high, so setting the raw status of all GPIO pins to high
> should work. The wait time before and after resources are enabled
> are collected from existing drivers and device trees.
> 
> The prober collects resources from all possible components and enables
> them together, instead of enabling resources and probing each component
> one by one. The latter approach does not provide any boot time benefits
> over simply enabling each component and letting each driver probe
> sequentially.
> 
> The prober will also deduplicate the resources, since on a component
> swap out or co-layout design, the resources are always the same.
> While duplicate regulator supplies won't cause much issue, shared
> GPIOs don't work reliably, especially with other drivers. For the
> same reason, the prober will release the GPIOs before the successfully
> probed component is actually enabled.

...

>  /*

>   * address responds.
>   *
>   * TODO:
> - * - Support handling common regulators and GPIOs.
> + * - Support handling common GPIOs.

You can split this to two lines in the first place and have less churn in this
patch and the other one.

>   * - Support I2C muxes
>   */

..

> +/* Returns number of regulator supplies found for node, or error. */
> +static int i2c_of_probe_get_regulator(struct device *dev, struct device_node *node,
> +				      struct i2c_of_probe_data *data)
> +{
> +	struct regulator_bulk_data *tmp, *new_regulators;
> +	int ret;
> +
> +	ret = of_regulator_bulk_get_all(dev, node, &tmp);
> +	if (ret <= 0)
> +		return ret;

I would split this and explain 0 case.


> +	if (!data->regulators) {
> +		data->regulators = tmp;
> +		data->regulators_num = ret;
> +		return ret;
> +	};
> +
> +	new_regulators = krealloc(data->regulators,
> +				  sizeof(*tmp) * (data->regulators_num + ret),

krealloc_array()

> +				  GFP_KERNEL);
> +	if (!new_regulators) {
> +		regulator_bulk_free(ret, tmp);
> +		return -ENOMEM;
> +	}
> +
> +	data->regulators = new_regulators;

> +	for (unsigned int i = 0; i < ret; i++)
> +		memcpy(&data->regulators[data->regulators_num++], &tmp[i], sizeof(*tmp));

Seems like copying array to array, no? If so, can't be done in a single memcpy() call?

> +	return ret;
> +}

...

> +static int i2c_of_probe_get_res(struct device *dev, struct device_node *node,
> +				struct i2c_of_probe_data *data)
> +{
> +	struct property *prop;
> +	int ret;
> +
> +	ret = i2c_of_probe_get_regulator(dev, node, data);
> +	if (ret < 0) {
> +		dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node);
> +		goto err_cleanup;
> +	}
> +
> +	return 0;
> +
> +err_cleanup:
> +	i2c_of_probe_free_res(data);
> +	return ret;
> +}

Hmm... why not

static int i2c_of_probe_get_res(struct device *dev, struct device_node *node,
				struct i2c_of_probe_data *data)
{
	struct property *prop;
	int ret;

	ret = i2c_of_probe_get_regulator(dev, node, data);
	if (ret < 0) {
		i2c_of_probe_free_res(data);
		return dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node);
	}

	return 0;
}

...

> +static int i2c_of_probe_enable_res(struct device *dev, struct i2c_of_probe_data *data)
> +{
> +	int ret = 0;

Redundant assignment.

> +	dev_dbg(dev, "Enabling regulator supplies\n");
> +
> +	ret = regulator_bulk_enable(data->regulators_num, data->regulators);
> +	if (ret)
> +		return ret;
> +
> +	/* largest post-power-on pre-reset-deassert delay seen among drivers */
> +	msleep(500);

How would we monitor if any [new] driver wants to use bigger timeout?

> +	return 0;
> +}

...

>  	struct i2c_adapter *i2c;
> +	struct i2c_of_probe_data probe_data = {0};

Reversed xmas tree order?

'0' is not needed.

...

> +	/* Grab resources */
> +	for_each_child_of_node_scoped(i2c_node, node) {
> +		u32 addr;
> +
> +		if (!of_node_name_prefix(node, type))
> +			continue;

Is it third or fourth copy of this code? At some point you probably want

#define for_each_child_of_node_with_prefix_scoped()
	for_each_if(...)

(or equivalent)

> +		if (of_property_read_u32(node, "reg", &addr))
> +			continue;
> +
> +		dev_dbg(dev, "Requesting resources for %pOF\n", node);
> +		ret = i2c_of_probe_get_res(dev, node, &probe_data);
> +		if (ret)
> +			return ret;
> +	}
Andy Shevchenko Aug. 22, 2024, 2:36 p.m. UTC | #3
On Thu, Aug 22, 2024 at 05:19:58PM +0800, Chen-Yu Tsai wrote:
> The I2C device tree component prober needs to get and toggle GPIO lines
> for the components it intends to probe. These components may not use the
> same name for their GPIO lines, so the prober must go through the device
> tree, check each property to see it is a GPIO property, and get the GPIO
> line.
> 
> Instead of duplicating the GPIO suffixes, or exporting them to the
> prober to do pattern matching, simply add and export a new function that
> does the pattern matching and returns the length of the GPIO name. The
> caller can then use that to copy out the name if it needs to.

...

> +/**
> + * gpio_property_name_length - Returns the GPIO name length from a property name
> + * @str:	string to check

It's property name, so, I would name this 'propname'.

> + * This function checks if the given name matches the GPIO property patterns, and
> + * returns the length of the name of the GPIO. The pattern is "*-<GPIO suffix>"
> + * or just "<GPIO suffix>".
> + *
> + * Returns:
> + * The length of the string before '-' if it matches "*-<GPIO suffix>", or

What about "x-y-gpios"? It's unclear what will be the behaviour.

> + * 0 if no name part, just the suffix, or
> + * -EINVAL if the string doesn't match the pattern.
> + */
> +int gpio_property_name_length(const char *str)

gpio_get_... ?

> +{
> +	size_t len;
> +
> +	len = strlen(str);

If it has a thousands characters...?

> +	/* string need to be at minimum len(gpio) */
> +	if (len < 4)
> +		return -EINVAL;

Do we really need it here? See below as well.

> +	/* Check for no-name case: "gpio" / "gpios" */
> +	for (const char *const *p = gpio_suffixes; *p; p++)
> +		if (!strcmp(str, *p))
> +			return 0;

> +	for (size_t i = len - 4; i > 0; i--) {
> +		/* find right-most '-' and check if remainder matches suffix */
> +		if (str[i] != '-')
> +			continue;
> +
> +		for (const char *const *p = gpio_suffixes; *p; p++)
> +			if (!strcmp(str + i + 1, *p))
> +				return i;
> +
> +		return -EINVAL;
> +	}

This can be combined with the above

	for (const char *const *p = gpio_suffixes; *p; p++) {
		/*
		 * Find right-most '-' and check if remainder matches suffix.
		 * If no separator found, check for no-name cases.
		 */
		dash = strrchr(propname, '-');
		if (!strcmp(dash ? dash + 1 : propname, *p))
			return i;
	}

> +	return -EINVAL;
> +}
Chen-Yu Tsai Aug. 23, 2024, 7:50 a.m. UTC | #4
On Thu, Aug 22, 2024 at 10:37 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Aug 22, 2024 at 05:19:58PM +0800, Chen-Yu Tsai wrote:
> > The I2C device tree component prober needs to get and toggle GPIO lines
> > for the components it intends to probe. These components may not use the
> > same name for their GPIO lines, so the prober must go through the device
> > tree, check each property to see it is a GPIO property, and get the GPIO
> > line.
> >
> > Instead of duplicating the GPIO suffixes, or exporting them to the
> > prober to do pattern matching, simply add and export a new function that
> > does the pattern matching and returns the length of the GPIO name. The
> > caller can then use that to copy out the name if it needs to.
>
> ...
>
> > +/**
> > + * gpio_property_name_length - Returns the GPIO name length from a property name
> > + * @str:     string to check
>
> It's property name, so, I would name this 'propname'.

Ack.

> > + * This function checks if the given name matches the GPIO property patterns, and
> > + * returns the length of the name of the GPIO. The pattern is "*-<GPIO suffix>"
> > + * or just "<GPIO suffix>".
> > + *
> > + * Returns:
> > + * The length of the string before '-' if it matches "*-<GPIO suffix>", or
>
> What about "x-y-gpios"? It's unclear what will be the behaviour.

I thought it was implied that the '-' mentioned here is the one before the
suffix. I made it more explicit.

> > + * 0 if no name part, just the suffix, or
> > + * -EINVAL if the string doesn't match the pattern.
> > + */
> > +int gpio_property_name_length(const char *str)
>
> gpio_get_... ?

Ack.

> > +{
> > +     size_t len;
> > +
> > +     len = strlen(str);
>
> If it has a thousands characters...?

Shouldn't matter much? I suppose using strrchr() as you suggested
requires one less pass.

> > +     /* string need to be at minimum len(gpio) */
> > +     if (len < 4)
> > +             return -EINVAL;
>
> Do we really need it here? See below as well.
>
> > +     /* Check for no-name case: "gpio" / "gpios" */
> > +     for (const char *const *p = gpio_suffixes; *p; p++)
> > +             if (!strcmp(str, *p))
> > +                     return 0;
>
> > +     for (size_t i = len - 4; i > 0; i--) {
> > +             /* find right-most '-' and check if remainder matches suffix */
> > +             if (str[i] != '-')
> > +                     continue;
> > +
> > +             for (const char *const *p = gpio_suffixes; *p; p++)
> > +                     if (!strcmp(str + i + 1, *p))
> > +                             return i;
> > +
> > +             return -EINVAL;
> > +     }
>
> This can be combined with the above
>
>         for (const char *const *p = gpio_suffixes; *p; p++) {
>                 /*
>                  * Find right-most '-' and check if remainder matches suffix.
>                  * If no separator found, check for no-name cases.
>                  */
>                 dash = strrchr(propname, '-');

I believe this line could be moved out of the for-loop. Otherwise it
looks much more concise compared to my version. I'll omit the comment
though, as it is just rehashing the kerneldoc description, and now
that the function is so short, it shouldn't be hard to read.

I'll add you as "Suggested-by".


Thanks
ChenYu

>                 if (!strcmp(dash ? dash + 1 : propname, *p))
>                         return i;
>         }
>
> > +     return -EINVAL;
> > +}
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Chen-Yu Tsai Aug. 23, 2024, 9:35 a.m. UTC | #5
On Thu, Aug 22, 2024 at 10:09 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Aug 22, 2024 at 05:20:00PM +0800, Chen-Yu Tsai wrote:
> > This adds regulator management to the I2C OF component prober.
> > Components that the prober intends to probe likely require their
> > regulator supplies be enabled, and GPIOs be toggled to enable them or
> > bring them out of reset before they will respond to probe attempts.
> > GPIOs will be handled in the next patch.
> >
> > Without specific knowledge of each component's resource names or
> > power sequencing requirements, the prober can only enable the
> > regulator supplies all at once, and toggle the GPIOs all at once.
> > Luckily, reset pins tend to be active low, while enable pins tend to
> > be active high, so setting the raw status of all GPIO pins to high
> > should work. The wait time before and after resources are enabled
> > are collected from existing drivers and device trees.
> >
> > The prober collects resources from all possible components and enables
> > them together, instead of enabling resources and probing each component
> > one by one. The latter approach does not provide any boot time benefits
> > over simply enabling each component and letting each driver probe
> > sequentially.
> >
> > The prober will also deduplicate the resources, since on a component
> > swap out or co-layout design, the resources are always the same.
> > While duplicate regulator supplies won't cause much issue, shared
> > GPIOs don't work reliably, especially with other drivers. For the
> > same reason, the prober will release the GPIOs before the successfully
> > probed component is actually enabled.
>
> ...
>
> >  /*
>
> >   * address responds.
> >   *
> >   * TODO:
> > - * - Support handling common regulators and GPIOs.
> > + * - Support handling common GPIOs.
>
> You can split this to two lines in the first place and have less churn in this
> patch and the other one.

Ack.

> >   * - Support I2C muxes
> >   */
>
> ..
>
> > +/* Returns number of regulator supplies found for node, or error. */
> > +static int i2c_of_probe_get_regulator(struct device *dev, struct device_node *node,
> > +                                   struct i2c_of_probe_data *data)
> > +{
> > +     struct regulator_bulk_data *tmp, *new_regulators;
> > +     int ret;
> > +
> > +     ret = of_regulator_bulk_get_all(dev, node, &tmp);
> > +     if (ret <= 0)
> > +             return ret;
>
> I would split this and explain 0 case.

Ack.

> > +     if (!data->regulators) {
> > +             data->regulators = tmp;
> > +             data->regulators_num = ret;
> > +             return ret;
> > +     };
> > +
> > +     new_regulators = krealloc(data->regulators,
> > +                               sizeof(*tmp) * (data->regulators_num + ret),
>
> krealloc_array()

Ack. Somehow I didn't find this function while I was rewriting the code.

> > +                               GFP_KERNEL);
> > +     if (!new_regulators) {
> > +             regulator_bulk_free(ret, tmp);
> > +             return -ENOMEM;
> > +     }
> > +
> > +     data->regulators = new_regulators;
>
> > +     for (unsigned int i = 0; i < ret; i++)
> > +             memcpy(&data->regulators[data->regulators_num++], &tmp[i], sizeof(*tmp));
>
> Seems like copying array to array, no? If so, can't be done in a single memcpy() call?

Ack.

> > +     return ret;
> > +}
>
> ...
>
> > +static int i2c_of_probe_get_res(struct device *dev, struct device_node *node,
> > +                             struct i2c_of_probe_data *data)
> > +{
> > +     struct property *prop;
> > +     int ret;
> > +
> > +     ret = i2c_of_probe_get_regulator(dev, node, data);
> > +     if (ret < 0) {
> > +             dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node);
> > +             goto err_cleanup;
> > +     }
> > +
> > +     return 0;
> > +
> > +err_cleanup:
> > +     i2c_of_probe_free_res(data);
> > +     return ret;
> > +}
>
> Hmm... why not
>
> static int i2c_of_probe_get_res(struct device *dev, struct device_node *node,
>                                 struct i2c_of_probe_data *data)
> {
>         struct property *prop;
>         int ret;
>
>         ret = i2c_of_probe_get_regulator(dev, node, data);
>         if (ret < 0) {
>                 i2c_of_probe_free_res(data);
>                 return dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node);
>         }
>
>         return 0;
> }
>
> ...

That would be more churn in the next patch, which introduces another
error condition requiring the same cleanup.

> > +static int i2c_of_probe_enable_res(struct device *dev, struct i2c_of_probe_data *data)
> > +{
> > +     int ret = 0;
>
> Redundant assignment.

Ack.

> > +     dev_dbg(dev, "Enabling regulator supplies\n");
> > +
> > +     ret = regulator_bulk_enable(data->regulators_num, data->regulators);
> > +     if (ret)
> > +             return ret;
> > +
> > +     /* largest post-power-on pre-reset-deassert delay seen among drivers */
> > +     msleep(500);
>
> How would we monitor if any [new] driver wants to use bigger timeout?

The assumption is that the person doing the integration should test for
this. This prober doesn't get called everywhere. It needs a driver to
call it, and that driver is written by someone for some specific platform.
Maybe I should explicitly spell that out in the function description?
Or even make it a parameter?

Also, having an arbitrarily large number here doesn't help platforms that
want to minimize boot time. On that front I'm also thinking about whether
it is possible to do a handover to the actual driver so that the latter
doesn't have to go through the whole power sequence again.

> > +     return 0;
> > +}
>
> ...
>
> >       struct i2c_adapter *i2c;
> > +     struct i2c_of_probe_data probe_data = {0};
>
> Reversed xmas tree order?

OK...

> '0' is not needed.

Ack.

> ...
>
> > +     /* Grab resources */
> > +     for_each_child_of_node_scoped(i2c_node, node) {
> > +             u32 addr;
> > +
> > +             if (!of_node_name_prefix(node, type))
> > +                     continue;
>
> Is it third or fourth copy of this code? At some point you probably want
>
> #define for_each_child_of_node_with_prefix_scoped()
>         for_each_if(...)
>
> (or equivalent)

Ack.


Thank you for the review.

ChenYu

> > +             if (of_property_read_u32(node, "reg", &addr))
> > +                     continue;
> > +
> > +             dev_dbg(dev, "Requesting resources for %pOF\n", node);
> > +             ret = i2c_of_probe_get_res(dev, node, &probe_data);
> > +             if (ret)
> > +                     return ret;
> > +     }
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Andy Shevchenko Aug. 23, 2024, 1:46 p.m. UTC | #6
On Fri, Aug 23, 2024 at 03:50:55PM +0800, Chen-Yu Tsai wrote:
> On Thu, Aug 22, 2024 at 10:37 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Thu, Aug 22, 2024 at 05:19:58PM +0800, Chen-Yu Tsai wrote:

...

> > > +     len = strlen(str);
> >
> > If it has a thousands characters...?
> 
> Shouldn't matter much? I suppose using strrchr() as you suggested
> requires one less pass.

Yes, this is the point.

...

> > This can be combined with the above
> >
> >         for (const char *const *p = gpio_suffixes; *p; p++) {
> >                 /*
> >                  * Find right-most '-' and check if remainder matches suffix.
> >                  * If no separator found, check for no-name cases.
> >                  */
> >                 dash = strrchr(propname, '-');
> 
> I believe this line could be moved out of the for-loop. Otherwise it
> looks much more concise compared to my version. I'll omit the comment
> though, as it is just rehashing the kerneldoc description, and now
> that the function is so short, it shouldn't be hard to read.

Agree. And I put comment inside the loop, while it should be outside. But then,
as you said, the function becomes so little that kernel-doc above does the job,
hence no comment in the code needed.

> I'll add you as "Suggested-by".

Fine with me.

> >                 if (!strcmp(dash ? dash + 1 : propname, *p))
> >                         return i;
> >         }
Andy Shevchenko Aug. 23, 2024, 1:56 p.m. UTC | #7
On Fri, Aug 23, 2024 at 05:35:59PM +0800, Chen-Yu Tsai wrote:
> On Thu, Aug 22, 2024 at 10:09 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Thu, Aug 22, 2024 at 05:20:00PM +0800, Chen-Yu Tsai wrote:

...

> > Hmm... why not
> >
> > static int i2c_of_probe_get_res(struct device *dev, struct device_node *node,
> >                                 struct i2c_of_probe_data *data)
> > {
> >         struct property *prop;
> >         int ret;
> >
> >         ret = i2c_of_probe_get_regulator(dev, node, data);
> >         if (ret < 0) {
> >                 i2c_of_probe_free_res(data);
> >                 return dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node);
> >         }
> >
> >         return 0;
> > }
> 
> That would be more churn in the next patch, which introduces another
> error condition requiring the same cleanup.

OK!

...

> > > +     /* largest post-power-on pre-reset-deassert delay seen among drivers */
> > > +     msleep(500);
> >
> > How would we monitor if any [new] driver wants to use bigger timeout?
> 
> The assumption is that the person doing the integration should test for
> this. This prober doesn't get called everywhere. It needs a driver to
> call it, and that driver is written by someone for some specific platform.
> Maybe I should explicitly spell that out in the function description?
> Or even make it a parameter?
> 
> Also, having an arbitrarily large number here doesn't help platforms that
> want to minimize boot time. On that front I'm also thinking about whether
> it is possible to do a handover to the actual driver so that the latter
> doesn't have to go through the whole power sequence again.

Yeah, I think the best effort is to have a parameter.