[PATCH 24/34] iio: inkern: move to fwnode properties

Andy Shevchenko andy.shevchenko at gmail.com
Fri Jun 10 08:19:33 PDT 2022


On Fri, Jun 10, 2022 at 10:48 AM Nuno Sá <nuno.sa at analog.com> wrote:
>
> This moves the IIO in kernel interface to use fwnode properties and thus
> be firmware agnostic.
>
> Note that the interface is still not firmware agnostic. At this point we
> have both OF and fwnode interfaces so that we don't break any user. On
> top of this we also want to have a per driver conversion and that is the
> main reason we have both of_xlate() and fwnode_xlate() support.

Reviewed-by: Andy Shevchenko <andy.shevchenko at gmail.com>
Thanks!

A few nit-picks below, though.

> Signed-off-by: Nuno Sá <nuno.sa at analog.com>
> ---
>  drivers/iio/inkern.c         | 145 +++++++++++++++++++----------------
>  include/linux/iio/consumer.h |  36 +++++----
>  include/linux/iio/iio.h      |   5 ++
>  3 files changed, 105 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index dde47324b826..1d519b0cacea 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -5,6 +5,7 @@
>   */
>  #include <linux/err.h>
>  #include <linux/export.h>
> +#include <linux/property.h>
>  #include <linux/slab.h>
>  #include <linux/mutex.h>
>  #include <linux/of.h>
> @@ -117,15 +118,13 @@ static const struct iio_chan_spec
>         return chan;
>  }
>
> -#ifdef CONFIG_OF
> -
>  static int iio_dev_node_match(struct device *dev, const void *data)
>  {
> -       return dev->of_node == data && dev->type == &iio_device_type;
> +       return device_match_fwnode(dev, data) && dev->type == &iio_device_type;
>  }
>
>  /**
> - * __of_iio_simple_xlate - translate iiospec to the IIO channel index
> + * __fwnode_iio_simple_xlate - translate iiospec to the IIO channel index
>   * @indio_dev: pointer to the iio_dev structure
>   * @iiospec:   IIO specifier as found in the device tree
>   *
> @@ -134,14 +133,14 @@ static int iio_dev_node_match(struct device *dev, const void *data)
>   * whether IIO index is less than num_channels (that is specified in the
>   * iio_dev).
>   */
> -static int __of_iio_simple_xlate(struct iio_dev *indio_dev,
> -                               const struct of_phandle_args *iiospec)
> +static int __fwnode_iio_simple_xlate(struct iio_dev *indio_dev,
> +                                    const struct fwnode_reference_args *iiospec)
>  {
> -       if (!iiospec->args_count)
> +       if (!iiospec->nargs)
>                 return 0;
>
>         if (iiospec->args[0] >= indio_dev->num_channels) {
> -               dev_err(&indio_dev->dev, "invalid channel index %u\n",
> +               dev_err(&indio_dev->dev, "invalid channel index %llu\n",
>                         iiospec->args[0]);
>                 return -EINVAL;
>         }
> @@ -149,34 +148,56 @@ static int __of_iio_simple_xlate(struct iio_dev *indio_dev,
>         return iiospec->args[0];
>  }
>
> -static int __of_iio_channel_get(struct iio_channel *channel,
> -                               struct device_node *np, int index)
> +/*
> + * Simple helper to copy fwnode_reference_args into of_phandle_args so we
> + * can pass it to of_xlate(). Ultimate goal is to drop this together with
> + * of_xlate().
> + */
> +static int __fwnode_to_of_xlate(struct iio_dev *indio_dev,
> +                               const struct fwnode_reference_args *iiospec)
> +{
> +       struct of_phandle_args of_args;
> +       unsigned int i;
> +
> +       of_args.args_count = iiospec->nargs;
> +       of_args.np = to_of_node(iiospec->fwnode);
> +
> +       for (i = 0; i < MAX_PHANDLE_ARGS; i++)
> +               of_args.args[i] = i < iiospec->nargs ? iiospec->args[i] : 0;
> +
> +       return indio_dev->info->of_xlate(indio_dev, &of_args);
> +}

Ah, now I realized that it's a bit more complicated than just to_of_node() :-)

> +static int __fwnode_iio_channel_get(struct iio_channel *channel,
> +                                   struct fwnode_handle *fwnode, int index)
>  {
>         struct device *idev;
>         struct iio_dev *indio_dev;
>         int err;
> -       struct of_phandle_args iiospec;
> +       struct fwnode_reference_args iiospec;

At the same point you can move it up in the block to make a long line first.

> -       err = of_parse_phandle_with_args(np, "io-channels",
> -                                        "#io-channel-cells",
> -                                        index, &iiospec);
> +       err = fwnode_property_get_reference_args(fwnode, "io-channels",
> +                                                "#io-channel-cells", 0,
> +                                                index, &iiospec);
>         if (err)
>                 return err;
>
> -       idev = bus_find_device(&iio_bus_type, NULL, iiospec.np,
> +       idev = bus_find_device(&iio_bus_type, NULL, iiospec.fwnode,
>                                iio_dev_node_match);

Wondering if this
https://elixir.bootlin.com/linux/v5.19-rc1/C/ident/bus_find_device_by_fwnode
can be utilized (yes, I noticed iio_device_type above).

>         if (idev == NULL) {
> -               of_node_put(iiospec.np);
> +               fwnode_handle_put(iiospec.fwnode);
>                 return -EPROBE_DEFER;
>         }
>
>         indio_dev = dev_to_iio_dev(idev);
>         channel->indio_dev = indio_dev;
>         if (indio_dev->info->of_xlate)
> -               index = indio_dev->info->of_xlate(indio_dev, &iiospec);
> +               index = __fwnode_to_of_xlate(indio_dev, &iiospec);
> +       else if (indio_dev->info->fwnode_xlate)
> +               index = indio_dev->info->fwnode_xlate(indio_dev, &iiospec);
>         else
> -               index = __of_iio_simple_xlate(indio_dev, &iiospec);
> -       of_node_put(iiospec.np);
> +               index = __fwnode_iio_simple_xlate(indio_dev, &iiospec);
> +       fwnode_handle_put(iiospec.fwnode);
>         if (index < 0)
>                 goto err_put;
>         channel->channel = &indio_dev->channels[index];
> @@ -188,7 +209,8 @@ static int __of_iio_channel_get(struct iio_channel *channel,
>         return index;
>  }
>
> -static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
> +static struct iio_channel *fwnode_iio_channel_get(struct fwnode_handle *fwnode,
> +                                                 int index)
>  {
>         struct iio_channel *channel;
>         int err;
> @@ -200,7 +222,7 @@ static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
>         if (channel == NULL)
>                 return ERR_PTR(-ENOMEM);
>
> -       err = __of_iio_channel_get(channel, np, index);
> +       err = __fwnode_iio_channel_get(channel, fwnode, index);
>         if (err)
>                 goto err_free_channel;
>
> @@ -211,9 +233,9 @@ static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
>         return ERR_PTR(err);
>  }
>
> -struct iio_channel *__of_iio_channel_get_by_name(struct device_node *np,
> -                                                const char *name,
> -                                                bool *parent_lookup)
> +struct iio_channel *
> +__fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, const char *name,
> +                                bool *parent_lookup)
>  {
>         struct iio_channel *chan;
>         int index = 0;
> @@ -221,32 +243,34 @@ struct iio_channel *__of_iio_channel_get_by_name(struct device_node *np,
>         /*
>          * For named iio channels, first look up the name in the
>          * "io-channel-names" property.  If it cannot be found, the
> -        * index will be an error code, and of_iio_channel_get()
> +        * index will be an error code, and fwnode_iio_channel_get()
>          * will fail.
>          */
>         if (name)
> -               index = of_property_match_string(np, "io-channel-names", name);
> +               index = fwnode_property_match_string(fwnode, "io-channel-names",
> +                                                    name);
>
> -       chan = of_iio_channel_get(np, index);
> +       chan = fwnode_iio_channel_get(fwnode, index);
>         if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER) {
>                 *parent_lookup = false;
>         } else if (name && index >= 0) {
> -               pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n",
> -                      np, name ? name : "", index);
> +               pr_err("ERROR: could not get IIO channel %pfw:%s(%i)\n",
> +                      fwnode, name ? name : "", index);

Since you are touching this line can you switch to name ?: "" and
possibly move some parameters to the above line?

>                 *parent_lookup = false;
>         }
>
>         return chan;
>  }
>
> -struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
> -                                              const char *name)
> +struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode,
> +                                                  const char *name)
>  {
>         struct iio_channel *chan;
> +       struct fwnode_handle *parent;
>         bool parent_lookup = true;
>
>         /* Walk up the tree of devices looking for a matching iio channel */
> -       chan = __of_iio_channel_get_by_name(np, name, &parent_lookup);
> +       chan = __fwnode_iio_channel_get_by_name(fwnode, name, &parent_lookup);
>         if (!parent_lookup)
>                 return chan;
>
> @@ -255,33 +279,34 @@ struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
>          * If the parent node has a "io-channel-ranges" property,
>          * then we can try one of its channels.
>          */
> -       np = np->parent;
> -       while (np) {
> -               if (!of_get_property(np, "io-channel-ranges", NULL))
> +       fwnode_for_each_parent_node(fwnode, parent) {
> +               if (!fwnode_property_present(parent, "io-channel-ranges")) {
> +                       fwnode_handle_put(parent);
>                         return chan;

break; ?

(Yes, I understand pros and cons of each variant, up to you)

> +               }
>
> -               chan = __of_iio_channel_get_by_name(np, name, &parent_lookup);
> -               if (!parent_lookup)
> +               chan = __fwnode_iio_channel_get_by_name(parent, name, &parent_lookup);
> +               if (!parent_lookup) {
> +                       fwnode_handle_put(parent);
>                         return chan;

Ditto.

> -               np = np->parent;
> +               }
>         }
>
>         return chan;
>  }
> -EXPORT_SYMBOL_GPL(of_iio_channel_get_by_name);
> +EXPORT_SYMBOL_GPL(fwnode_iio_channel_get_by_name);

Wondering if we may move this to the IIO namespace.

> -static struct iio_channel *of_iio_channel_get_all(struct device *dev)
> +static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev)
>  {
> +       struct fwnode_handle *fwnode = dev_fwnode(dev);
>         struct iio_channel *chans;
>         int i, mapind, nummaps = 0;
>         int ret;
>
>         do {
> -               ret = of_parse_phandle_with_args(dev->of_node,
> -                                                "io-channels",
> -                                                "#io-channel-cells",
> -                                                nummaps, NULL);
> +               ret = fwnode_property_get_reference_args(fwnode, "io-channels",
> +                                                        "#io-channel-cells", 0,
> +                                                        nummaps, NULL);
>                 if (ret < 0)
>                         break;
>         } while (++nummaps);
> @@ -294,10 +319,9 @@ static struct iio_channel *of_iio_channel_get_all(struct device *dev)
>         if (chans == NULL)
>                 return ERR_PTR(-ENOMEM);
>
> -       /* Search for OF matches */
> +       /* Search for FW matches */
>         for (mapind = 0; mapind < nummaps; mapind++) {
> -               ret = __of_iio_channel_get(&chans[mapind], dev->of_node,
> -                                          mapind);
> +               ret = __fwnode_iio_channel_get(&chans[mapind], fwnode, mapind);
>                 if (ret)
>                         goto error_free_chans;
>         }
> @@ -310,15 +334,6 @@ static struct iio_channel *of_iio_channel_get_all(struct device *dev)
>         return ERR_PTR(ret);
>  }
>
> -#else /* CONFIG_OF */
> -
> -static inline struct iio_channel *of_iio_channel_get_all(struct device *dev)
> -{
> -       return ERR_PTR(-ENODEV);
> -}
> -
> -#endif /* CONFIG_OF */
> -
>  static struct iio_channel *iio_channel_get_sys(const char *name,
>                                                const char *channel_name)
>  {
> @@ -379,8 +394,8 @@ struct iio_channel *iio_channel_get(struct device *dev,
>         struct iio_channel *channel;
>
>         if (dev) {
> -               channel = of_iio_channel_get_by_name(dev->of_node,
> -                                                    channel_name);
> +               channel = fwnode_iio_channel_get_by_name(dev_fwnode(dev),
> +                                                        channel_name);
>                 if (!IS_ERR(channel) || PTR_ERR(channel) == -EPROBE_DEFER)
>                         return channel;
>         }
> @@ -421,14 +436,14 @@ struct iio_channel *devm_iio_channel_get(struct device *dev,
>  }
>  EXPORT_SYMBOL_GPL(devm_iio_channel_get);
>
> -struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev,
> -                                                   struct device_node *np,
> -                                                   const char *channel_name)
> +struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev,
> +                                                       struct fwnode_handle *fwnode,
> +                                                       const char *channel_name)
>  {
>         struct iio_channel *channel;
>         int ret;
>
> -       channel = of_iio_channel_get_by_name(np, channel_name);
> +       channel = fwnode_iio_channel_get_by_name(fwnode, channel_name);
>         if (IS_ERR(channel))
>                 return channel;
>
> @@ -438,7 +453,7 @@ struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev,
>
>         return channel;
>  }
> -EXPORT_SYMBOL_GPL(devm_of_iio_channel_get_by_name);
> +EXPORT_SYMBOL_GPL(devm_fwnode_iio_channel_get_by_name);
>
>  struct iio_channel *iio_channel_get_all(struct device *dev)
>  {
> @@ -452,7 +467,7 @@ struct iio_channel *iio_channel_get_all(struct device *dev)
>         if (dev == NULL)
>                 return ERR_PTR(-EINVAL);
>
> -       chans = of_iio_channel_get_all(dev);
> +       chans = fwnode_iio_channel_get_all(dev);
>         if (!IS_ERR(chans) || PTR_ERR(chans) == -EPROBE_DEFER)
>                 return chans;
>
> diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
> index 5fa5957586cf..a96a714b5fdc 100644
> --- a/include/linux/iio/consumer.h
> +++ b/include/linux/iio/consumer.h
> @@ -9,11 +9,13 @@
>
>  #include <linux/types.h>
>  #include <linux/iio/types.h>

> +#include <linux/of.h>

Ordering. IIO has special meaning here, that's why it's last.

>  struct iio_dev;
>  struct iio_chan_spec;
>  struct device;
>  struct device_node;
> +struct fwnode_handle;
>
>  /**
>   * struct iio_channel - everything needed for a consumer to use a channel
> @@ -99,26 +101,20 @@ void iio_channel_release_all(struct iio_channel *chan);
>  struct iio_channel *devm_iio_channel_get_all(struct device *dev);
>
>  /**
> - * of_iio_channel_get_by_name() - get description of all that is needed to access channel.
> - * @np:                        Pointer to consumer device tree node
> + * fwnode_iio_channel_get_by_name() - get description of all that is needed to access channel.
> + * @fwnode:            Pointer to consumer Firmware node
>   * @consumer_channel:  Unique name to identify the channel on the consumer
>   *                     side. This typically describes the channels use within
>   *                     the consumer. E.g. 'battery_voltage'
>   */
> -#ifdef CONFIG_OF
> -struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, const char *name);
> -#else
> -static inline struct iio_channel *
> -of_iio_channel_get_by_name(struct device_node *np, const char *name)
> -{
> -       return NULL;
> -}
> -#endif
> +struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode,
> +                                                  const char *name);
>
>  /**
> - * devm_of_iio_channel_get_by_name() - Resource managed version of of_iio_channel_get_by_name().
> + * devm_fwnode_iio_channel_get_by_name() - Resource managed version of
> + *                                        fwnode_iio_channel_get_by_name().
>   * @dev:               Pointer to consumer device.
> - * @np:                        Pointer to consumer device tree node
> + * @fwnode:            Pointer to consumer Firmware node
>   * @consumer_channel:  Unique name to identify the channel on the consumer
>   *                     side. This typically describes the channels use within
>   *                     the consumer. E.g. 'battery_voltage'
> @@ -129,9 +125,17 @@ of_iio_channel_get_by_name(struct device_node *np, const char *name)
>   * The allocated iio channel is automatically released when the device is
>   * unbound.
>   */
> -struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev,
> -                                                   struct device_node *np,
> -                                                   const char *consumer_channel);
> +struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev,
> +                                                       struct fwnode_handle *fwnode,
> +                                                       const char *consumer_channel);
> +
> +static inline struct iio_channel
> +*devm_of_iio_channel_get_by_name(struct device *dev, struct device_node *np,
> +                                const char *consumer_channel)
> +{
> +       return devm_fwnode_iio_channel_get_by_name(dev, of_fwnode_handle(np),
> +                                                  consumer_channel);
> +}
>
>  struct iio_cb_buffer;
>  /**
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index d9b4a9ca9a0f..494abb63406e 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -18,6 +18,7 @@
>   */
>
>  struct of_phandle_args;
> +struct fwnode_reference_args;
>
>  enum iio_shared_by {
>         IIO_SEPARATE,
> @@ -429,6 +430,8 @@ struct iio_trigger; /* forward declaration */
>   *                     provide a custom of_xlate function that reads the
>   *                     *args* and returns the appropriate index in registered
>   *                     IIO channels array.
> + * @fwnode_xlate:      fwnode based function pointer to obtain channel specifier index.
> + *                     Functionally the same as @of_xlate.
>   * @hwfifo_set_watermark: function pointer to set the current hardware
>   *                     fifo watermark level; see hwfifo_* entries in
>   *                     Documentation/ABI/testing/sysfs-bus-iio for details on
> @@ -510,6 +513,8 @@ struct iio_info {
>                                   unsigned *readval);
>         int (*of_xlate)(struct iio_dev *indio_dev,
>                         const struct of_phandle_args *iiospec);
> +       int (*fwnode_xlate)(struct iio_dev *indio_dev,
> +                           const struct fwnode_reference_args *iiospec);
>         int (*hwfifo_set_watermark)(struct iio_dev *indio_dev, unsigned val);
>         int (*hwfifo_flush_to_buffer)(struct iio_dev *indio_dev,
>                                       unsigned count);

-- 
With Best Regards,
Andy Shevchenko



More information about the Linux-mediatek mailing list