diff mbox series

[RESEND,v3,2/2] i2c: i2c-mux-gpio: Enable this driver in ACPI land

Message ID 20201118153951.RESEND.v3.2.Idef164c23d326f5e5edecfc5d3eb2a68fcf18be1@changeid
State Accepted
Commit 98b2b712bc8592c4ad212449162e36e47761a46c
Headers show
Series i2c: i2c-mux-gpio: Enable this driver in ACPI land | expand

Commit Message

Evan Green Nov. 18, 2020, 11:40 p.m. UTC
Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state
property translates directly to a fwnode_property_*() call. The child
reg property translates naturally into _ADR in ACPI.

The i2c-parent binding is a relic from the days when the bindings
dictated that all direct children of an I2C controller had to be I2C
devices. These days that's no longer required. The i2c-mux can sit as a
direct child of its parent controller, which is where it makes the most
sense from a hardware description perspective. For the ACPI
implementation we'll assume that's always how the i2c-mux-gpio is
instantiated.

Signed-off-by: Evan Green <evgreen@chromium.org>
---

Changes in v3:
 - Update commit message again (Peter)
 - Added missing \n (Peter)
 - adr64 overflow check (Peter)
 - Don't initialize child (Peter)
 - Limit scope of dev_handle (Peter)

Changes in v2:
 - Make it compile properly when !CONFIG_ACPI (Randy)
 - Update commit message regarding i2c-parent (Peter)

 drivers/i2c/muxes/i2c-mux-gpio.c | 107 +++++++++++++++++++++++--------
 1 file changed, 79 insertions(+), 28 deletions(-)

Comments

Andy Shevchenko Nov. 19, 2020, 3:25 p.m. UTC | #1
On Thu, Nov 19, 2020 at 1:40 AM Evan Green <evgreen@chromium.org> wrote:
>

> Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state

> property translates directly to a fwnode_property_*() call. The child

> reg property translates naturally into _ADR in ACPI.

>

> The i2c-parent binding is a relic from the days when the bindings

> dictated that all direct children of an I2C controller had to be I2C

> devices. These days that's no longer required. The i2c-mux can sit as a

> direct child of its parent controller, which is where it makes the most

> sense from a hardware description perspective. For the ACPI

> implementation we'll assume that's always how the i2c-mux-gpio is

> instantiated.


...

> +#ifdef CONFIG_ACPI

> +

> +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> +                                    struct fwnode_handle *fwdev,

> +                                    unsigned int *adr)

> +

> +{

> +       unsigned long long adr64;

> +       acpi_status status;

> +

> +       status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev),

> +                                      METHOD_NAME__ADR,

> +                                      NULL, &adr64);

> +

> +       if (!ACPI_SUCCESS(status)) {

> +               dev_err(dev, "Cannot get address\n");

> +               return -EINVAL;

> +       }

> +

> +       *adr = adr64;

> +       if (*adr != adr64) {

> +               dev_err(dev, "Address out of range\n");

> +               return -ERANGE;

> +       }

> +

> +       return 0;

> +}

> +

> +#else

> +

> +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> +                                    struct fwnode_handle *fwdev,

> +                                    unsigned int *adr)

> +{

> +       return -EINVAL;

> +}

> +

> +#endif


I'm wondering if you may use acpi_find_child_device() here.
Or is it a complementary function?

...

> +       device_for_each_child_node(dev, child) {

> +               if (is_of_node(child)) {

> +                       fwnode_property_read_u32(child, "reg", values + i);

> +

> +               } else if (is_acpi_node(child)) {

> +                       rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i);

> +                       if (rc)

> +                               return rc;

> +               }

> +

>                 i++;

>         }


And for this I already told in two different threads with similar code
that perhaps we need common helper that will check reg followed by
_ADR.

-- 
With Best Regards,
Andy Shevchenko
Evan Green Nov. 20, 2020, 6:59 p.m. UTC | #2
On Thu, Nov 19, 2020 at 7:24 AM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>

> On Thu, Nov 19, 2020 at 1:40 AM Evan Green <evgreen@chromium.org> wrote:

> >

> > Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state

> > property translates directly to a fwnode_property_*() call. The child

> > reg property translates naturally into _ADR in ACPI.

> >

> > The i2c-parent binding is a relic from the days when the bindings

> > dictated that all direct children of an I2C controller had to be I2C

> > devices. These days that's no longer required. The i2c-mux can sit as a

> > direct child of its parent controller, which is where it makes the most

> > sense from a hardware description perspective. For the ACPI

> > implementation we'll assume that's always how the i2c-mux-gpio is

> > instantiated.

>

> ...

>

> > +#ifdef CONFIG_ACPI

> > +

> > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > +                                    struct fwnode_handle *fwdev,

> > +                                    unsigned int *adr)

> > +

> > +{

> > +       unsigned long long adr64;

> > +       acpi_status status;

> > +

> > +       status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev),

> > +                                      METHOD_NAME__ADR,

> > +                                      NULL, &adr64);

> > +

> > +       if (!ACPI_SUCCESS(status)) {

> > +               dev_err(dev, "Cannot get address\n");

> > +               return -EINVAL;

> > +       }

> > +

> > +       *adr = adr64;

> > +       if (*adr != adr64) {

> > +               dev_err(dev, "Address out of range\n");

> > +               return -ERANGE;

> > +       }

> > +

> > +       return 0;

> > +}

> > +

> > +#else

> > +

> > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > +                                    struct fwnode_handle *fwdev,

> > +                                    unsigned int *adr)

> > +{

> > +       return -EINVAL;

> > +}

> > +

> > +#endif

>

> I'm wondering if you may use acpi_find_child_device() here.

> Or is it a complementary function?


I think it's complementary. The code above is "I have a device, I want
its _ADR". whereas acpi_find_child_device() is "I have an _ADR, I want
its device". I could flip things around to use this, but it would turn
the code from linear into quadratic. I'd have to scan each possible
address and call acpi_find_child_device() with that _ADR to see if
there's a child device there.

>

> ...

>

> > +       device_for_each_child_node(dev, child) {

> > +               if (is_of_node(child)) {

> > +                       fwnode_property_read_u32(child, "reg", values + i);

> > +

> > +               } else if (is_acpi_node(child)) {

> > +                       rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i);

> > +                       if (rc)

> > +                               return rc;

> > +               }

> > +

> >                 i++;

> >         }

>

> And for this I already told in two different threads with similar code

> that perhaps we need common helper that will check reg followed by

> _ADR.


Oh, I'm not aware of those threads. I'd need some advice: I guess a
new fwnode_* API would make sense for this, but I had trouble coming
up with a generic interface. _ADR is just a blobbo 64 bit int, but
DT's "reg" is a little more flexible, having a length, and potentially
being an array. I suppose it would have to be something like:

int fwnode_property_read_reg(const struct fwnode_handle *fwnode,
                                 size_t index, uint64_t *addr, uint64_t *len);

But then ACPI would always return 0 for length, and only index 0 would
ever work? I'm worried I'm designing an API that's only useful to me.

I tried to look around for other examples of this specific pattern of
_ADR then "reg", but struggled to turn up much.
-Evan

>

> --

> With Best Regards,

> Andy Shevchenko
Evan Green Nov. 30, 2020, 7:11 p.m. UTC | #3
Hi Andy, Peter,

On Fri, Nov 20, 2020 at 10:59 AM Evan Green <evgreen@chromium.org> wrote:
>

> On Thu, Nov 19, 2020 at 7:24 AM Andy Shevchenko

> <andy.shevchenko@gmail.com> wrote:

> >

> > On Thu, Nov 19, 2020 at 1:40 AM Evan Green <evgreen@chromium.org> wrote:

> > >

> > > Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state

> > > property translates directly to a fwnode_property_*() call. The child

> > > reg property translates naturally into _ADR in ACPI.

> > >

> > > The i2c-parent binding is a relic from the days when the bindings

> > > dictated that all direct children of an I2C controller had to be I2C

> > > devices. These days that's no longer required. The i2c-mux can sit as a

> > > direct child of its parent controller, which is where it makes the most

> > > sense from a hardware description perspective. For the ACPI

> > > implementation we'll assume that's always how the i2c-mux-gpio is

> > > instantiated.

> >

> > ...

> >

> > > +#ifdef CONFIG_ACPI

> > > +

> > > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > > +                                    struct fwnode_handle *fwdev,

> > > +                                    unsigned int *adr)

> > > +

> > > +{

> > > +       unsigned long long adr64;

> > > +       acpi_status status;

> > > +

> > > +       status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev),

> > > +                                      METHOD_NAME__ADR,

> > > +                                      NULL, &adr64);

> > > +

> > > +       if (!ACPI_SUCCESS(status)) {

> > > +               dev_err(dev, "Cannot get address\n");

> > > +               return -EINVAL;

> > > +       }

> > > +

> > > +       *adr = adr64;

> > > +       if (*adr != adr64) {

> > > +               dev_err(dev, "Address out of range\n");

> > > +               return -ERANGE;

> > > +       }

> > > +

> > > +       return 0;

> > > +}

> > > +

> > > +#else

> > > +

> > > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > > +                                    struct fwnode_handle *fwdev,

> > > +                                    unsigned int *adr)

> > > +{

> > > +       return -EINVAL;

> > > +}

> > > +

> > > +#endif

> >

> > I'm wondering if you may use acpi_find_child_device() here.

> > Or is it a complementary function?

>

> I think it's complementary. The code above is "I have a device, I want

> its _ADR". whereas acpi_find_child_device() is "I have an _ADR, I want

> its device". I could flip things around to use this, but it would turn

> the code from linear into quadratic. I'd have to scan each possible

> address and call acpi_find_child_device() with that _ADR to see if

> there's a child device there.

>

> >

> > ...

> >

> > > +       device_for_each_child_node(dev, child) {

> > > +               if (is_of_node(child)) {

> > > +                       fwnode_property_read_u32(child, "reg", values + i);

> > > +

> > > +               } else if (is_acpi_node(child)) {

> > > +                       rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i);

> > > +                       if (rc)

> > > +                               return rc;

> > > +               }

> > > +

> > >                 i++;

> > >         }

> >

> > And for this I already told in two different threads with similar code

> > that perhaps we need common helper that will check reg followed by

> > _ADR.

>

> Oh, I'm not aware of those threads. I'd need some advice: I guess a

> new fwnode_* API would make sense for this, but I had trouble coming

> up with a generic interface. _ADR is just a blobbo 64 bit int, but

> DT's "reg" is a little more flexible, having a length, and potentially

> being an array. I suppose it would have to be something like:

>

> int fwnode_property_read_reg(const struct fwnode_handle *fwnode,

>                                  size_t index, uint64_t *addr, uint64_t *len);

>

> But then ACPI would always return 0 for length, and only index 0 would

> ever work? I'm worried I'm designing an API that's only useful to me.

>

> I tried to look around for other examples of this specific pattern of

> _ADR then "reg", but struggled to turn up much.


Any thoughts on this?

> -Evan

>

> >

> > --

> > With Best Regards,

> > Andy Shevchenko
Evan Green Dec. 9, 2020, 11:03 p.m. UTC | #4
Very sorry to ping. Is there anything I can do to help get this reviewed?
-Evan

On Mon, Nov 30, 2020 at 11:11 AM Evan Green <evgreen@chromium.org> wrote:
>

> Hi Andy, Peter,

>

> On Fri, Nov 20, 2020 at 10:59 AM Evan Green <evgreen@chromium.org> wrote:

> >

> > On Thu, Nov 19, 2020 at 7:24 AM Andy Shevchenko

> > <andy.shevchenko@gmail.com> wrote:

> > >

> > > On Thu, Nov 19, 2020 at 1:40 AM Evan Green <evgreen@chromium.org> wrote:

> > > >

> > > > Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state

> > > > property translates directly to a fwnode_property_*() call. The child

> > > > reg property translates naturally into _ADR in ACPI.

> > > >

> > > > The i2c-parent binding is a relic from the days when the bindings

> > > > dictated that all direct children of an I2C controller had to be I2C

> > > > devices. These days that's no longer required. The i2c-mux can sit as a

> > > > direct child of its parent controller, which is where it makes the most

> > > > sense from a hardware description perspective. For the ACPI

> > > > implementation we'll assume that's always how the i2c-mux-gpio is

> > > > instantiated.

> > >

> > > ...

> > >

> > > > +#ifdef CONFIG_ACPI

> > > > +

> > > > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > > > +                                    struct fwnode_handle *fwdev,

> > > > +                                    unsigned int *adr)

> > > > +

> > > > +{

> > > > +       unsigned long long adr64;

> > > > +       acpi_status status;

> > > > +

> > > > +       status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev),

> > > > +                                      METHOD_NAME__ADR,

> > > > +                                      NULL, &adr64);

> > > > +

> > > > +       if (!ACPI_SUCCESS(status)) {

> > > > +               dev_err(dev, "Cannot get address\n");

> > > > +               return -EINVAL;

> > > > +       }

> > > > +

> > > > +       *adr = adr64;

> > > > +       if (*adr != adr64) {

> > > > +               dev_err(dev, "Address out of range\n");

> > > > +               return -ERANGE;

> > > > +       }

> > > > +

> > > > +       return 0;

> > > > +}

> > > > +

> > > > +#else

> > > > +

> > > > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > > > +                                    struct fwnode_handle *fwdev,

> > > > +                                    unsigned int *adr)

> > > > +{

> > > > +       return -EINVAL;

> > > > +}

> > > > +

> > > > +#endif

> > >

> > > I'm wondering if you may use acpi_find_child_device() here.

> > > Or is it a complementary function?

> >

> > I think it's complementary. The code above is "I have a device, I want

> > its _ADR". whereas acpi_find_child_device() is "I have an _ADR, I want

> > its device". I could flip things around to use this, but it would turn

> > the code from linear into quadratic. I'd have to scan each possible

> > address and call acpi_find_child_device() with that _ADR to see if

> > there's a child device there.

> >

> > >

> > > ...

> > >

> > > > +       device_for_each_child_node(dev, child) {

> > > > +               if (is_of_node(child)) {

> > > > +                       fwnode_property_read_u32(child, "reg", values + i);

> > > > +

> > > > +               } else if (is_acpi_node(child)) {

> > > > +                       rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i);

> > > > +                       if (rc)

> > > > +                               return rc;

> > > > +               }

> > > > +

> > > >                 i++;

> > > >         }

> > >

> > > And for this I already told in two different threads with similar code

> > > that perhaps we need common helper that will check reg followed by

> > > _ADR.

> >

> > Oh, I'm not aware of those threads. I'd need some advice: I guess a

> > new fwnode_* API would make sense for this, but I had trouble coming

> > up with a generic interface. _ADR is just a blobbo 64 bit int, but

> > DT's "reg" is a little more flexible, having a length, and potentially

> > being an array. I suppose it would have to be something like:

> >

> > int fwnode_property_read_reg(const struct fwnode_handle *fwnode,

> >                                  size_t index, uint64_t *addr, uint64_t *len);

> >

> > But then ACPI would always return 0 for length, and only index 0 would

> > ever work? I'm worried I'm designing an API that's only useful to me.

> >

> > I tried to look around for other examples of this specific pattern of

> > _ADR then "reg", but struggled to turn up much.

>

> Any thoughts on this?

>

> > -Evan

> >

> > >

> > > --

> > > With Best Regards,

> > > Andy Shevchenko
Wolfram Sang Jan. 5, 2021, 10:25 a.m. UTC | #5
On Fri, Nov 20, 2020 at 10:59:12AM -0800, Evan Green wrote:
> On Thu, Nov 19, 2020 at 7:24 AM Andy Shevchenko

> <andy.shevchenko@gmail.com> wrote:

> >

> > On Thu, Nov 19, 2020 at 1:40 AM Evan Green <evgreen@chromium.org> wrote:

> > >

> > > Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state

> > > property translates directly to a fwnode_property_*() call. The child

> > > reg property translates naturally into _ADR in ACPI.

> > >

> > > The i2c-parent binding is a relic from the days when the bindings

> > > dictated that all direct children of an I2C controller had to be I2C

> > > devices. These days that's no longer required. The i2c-mux can sit as a

> > > direct child of its parent controller, which is where it makes the most

> > > sense from a hardware description perspective. For the ACPI

> > > implementation we'll assume that's always how the i2c-mux-gpio is

> > > instantiated.

> >

> > ...

> >

> > > +#ifdef CONFIG_ACPI

> > > +

> > > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > > +                                    struct fwnode_handle *fwdev,

> > > +                                    unsigned int *adr)

> > > +

> > > +{

> > > +       unsigned long long adr64;

> > > +       acpi_status status;

> > > +

> > > +       status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev),

> > > +                                      METHOD_NAME__ADR,

> > > +                                      NULL, &adr64);

> > > +

> > > +       if (!ACPI_SUCCESS(status)) {

> > > +               dev_err(dev, "Cannot get address\n");

> > > +               return -EINVAL;

> > > +       }

> > > +

> > > +       *adr = adr64;

> > > +       if (*adr != adr64) {

> > > +               dev_err(dev, "Address out of range\n");

> > > +               return -ERANGE;

> > > +       }

> > > +

> > > +       return 0;

> > > +}

> > > +

> > > +#else

> > > +

> > > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > > +                                    struct fwnode_handle *fwdev,

> > > +                                    unsigned int *adr)

> > > +{

> > > +       return -EINVAL;

> > > +}

> > > +

> > > +#endif

> >

> > I'm wondering if you may use acpi_find_child_device() here.

> > Or is it a complementary function?

> 

> I think it's complementary. The code above is "I have a device, I want

> its _ADR". whereas acpi_find_child_device() is "I have an _ADR, I want

> its device". I could flip things around to use this, but it would turn

> the code from linear into quadratic. I'd have to scan each possible

> address and call acpi_find_child_device() with that _ADR to see if

> there's a child device there.

> 

> >

> > ...

> >

> > > +       device_for_each_child_node(dev, child) {

> > > +               if (is_of_node(child)) {

> > > +                       fwnode_property_read_u32(child, "reg", values + i);

> > > +

> > > +               } else if (is_acpi_node(child)) {

> > > +                       rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i);

> > > +                       if (rc)

> > > +                               return rc;

> > > +               }

> > > +

> > >                 i++;

> > >         }

> >

> > And for this I already told in two different threads with similar code

> > that perhaps we need common helper that will check reg followed by

> > _ADR.

> 

> Oh, I'm not aware of those threads. I'd need some advice: I guess a

> new fwnode_* API would make sense for this, but I had trouble coming

> up with a generic interface. _ADR is just a blobbo 64 bit int, but

> DT's "reg" is a little more flexible, having a length, and potentially

> being an array. I suppose it would have to be something like:

> 

> int fwnode_property_read_reg(const struct fwnode_handle *fwnode,

>                                  size_t index, uint64_t *addr, uint64_t *len);

> 

> But then ACPI would always return 0 for length, and only index 0 would

> ever work? I'm worried I'm designing an API that's only useful to me.

> 

> I tried to look around for other examples of this specific pattern of

> _ADR then "reg", but struggled to turn up much.

> -Evan


Andy, is Evan's answer satisfying for you?
Evan Green Jan. 14, 2021, 6:17 p.m. UTC | #6
On Tue, Jan 5, 2021 at 2:25 AM Wolfram Sang <wsa@kernel.org> wrote:
>

> On Fri, Nov 20, 2020 at 10:59:12AM -0800, Evan Green wrote:

> > On Thu, Nov 19, 2020 at 7:24 AM Andy Shevchenko

> > <andy.shevchenko@gmail.com> wrote:

> > >

> > > On Thu, Nov 19, 2020 at 1:40 AM Evan Green <evgreen@chromium.org> wrote:

> > > >

> > > > Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state

> > > > property translates directly to a fwnode_property_*() call. The child

> > > > reg property translates naturally into _ADR in ACPI.

> > > >

> > > > The i2c-parent binding is a relic from the days when the bindings

> > > > dictated that all direct children of an I2C controller had to be I2C

> > > > devices. These days that's no longer required. The i2c-mux can sit as a

> > > > direct child of its parent controller, which is where it makes the most

> > > > sense from a hardware description perspective. For the ACPI

> > > > implementation we'll assume that's always how the i2c-mux-gpio is

> > > > instantiated.

> > >

> > > ...

> > >

> > > > +#ifdef CONFIG_ACPI

> > > > +

> > > > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > > > +                                    struct fwnode_handle *fwdev,

> > > > +                                    unsigned int *adr)

> > > > +

> > > > +{

> > > > +       unsigned long long adr64;

> > > > +       acpi_status status;

> > > > +

> > > > +       status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev),

> > > > +                                      METHOD_NAME__ADR,

> > > > +                                      NULL, &adr64);

> > > > +

> > > > +       if (!ACPI_SUCCESS(status)) {

> > > > +               dev_err(dev, "Cannot get address\n");

> > > > +               return -EINVAL;

> > > > +       }

> > > > +

> > > > +       *adr = adr64;

> > > > +       if (*adr != adr64) {

> > > > +               dev_err(dev, "Address out of range\n");

> > > > +               return -ERANGE;

> > > > +       }

> > > > +

> > > > +       return 0;

> > > > +}

> > > > +

> > > > +#else

> > > > +

> > > > +static int i2c_mux_gpio_get_acpi_adr(struct device *dev,

> > > > +                                    struct fwnode_handle *fwdev,

> > > > +                                    unsigned int *adr)

> > > > +{

> > > > +       return -EINVAL;

> > > > +}

> > > > +

> > > > +#endif

> > >

> > > I'm wondering if you may use acpi_find_child_device() here.

> > > Or is it a complementary function?

> >

> > I think it's complementary. The code above is "I have a device, I want

> > its _ADR". whereas acpi_find_child_device() is "I have an _ADR, I want

> > its device". I could flip things around to use this, but it would turn

> > the code from linear into quadratic. I'd have to scan each possible

> > address and call acpi_find_child_device() with that _ADR to see if

> > there's a child device there.

> >

> > >

> > > ...

> > >

> > > > +       device_for_each_child_node(dev, child) {

> > > > +               if (is_of_node(child)) {

> > > > +                       fwnode_property_read_u32(child, "reg", values + i);

> > > > +

> > > > +               } else if (is_acpi_node(child)) {

> > > > +                       rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i);

> > > > +                       if (rc)

> > > > +                               return rc;

> > > > +               }

> > > > +

> > > >                 i++;

> > > >         }

> > >

> > > And for this I already told in two different threads with similar code

> > > that perhaps we need common helper that will check reg followed by

> > > _ADR.

> >

> > Oh, I'm not aware of those threads. I'd need some advice: I guess a

> > new fwnode_* API would make sense for this, but I had trouble coming

> > up with a generic interface. _ADR is just a blobbo 64 bit int, but

> > DT's "reg" is a little more flexible, having a length, and potentially

> > being an array. I suppose it would have to be something like:

> >

> > int fwnode_property_read_reg(const struct fwnode_handle *fwnode,

> >                                  size_t index, uint64_t *addr, uint64_t *len);

> >

> > But then ACPI would always return 0 for length, and only index 0 would

> > ever work? I'm worried I'm designing an API that's only useful to me.

> >

> > I tried to look around for other examples of this specific pattern of

> > _ADR then "reg", but struggled to turn up much.

> > -Evan

>

> Andy, is Evan's answer satisfying for you?


Can this be accepted as-is, or should I resend?
-Evan
Wolfram Sang Jan. 14, 2021, 7:53 p.m. UTC | #7
> Can this be accepted as-is, or should I resend?


Peter, can you have a look here as well?
Peter Rosin Jan. 15, 2021, 9:29 a.m. UTC | #8
On 2021-01-14 20:53, Wolfram Sang wrote:
>> Can this be accepted as-is, or should I resend?

> 

> Peter, can you have a look here as well?


I have no issues, but I was waiting for a response from Andy here. I have
little knowledge of ACPI, and have previously made ignorant mistakes in
that area. I would greatly appreciate Andy following through with his
line of thinking...

So, if we ignore Andys review comments, then:

Acked-by: Peter Rosin <peda@axentia.se>


Cheers,
Peter
Wolfram Sang Jan. 17, 2021, 11:54 a.m. UTC | #9
On Wed, Nov 18, 2020 at 03:40:25PM -0800, Evan Green wrote:
> Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state

> property translates directly to a fwnode_property_*() call. The child

> reg property translates naturally into _ADR in ACPI.

> 

> The i2c-parent binding is a relic from the days when the bindings

> dictated that all direct children of an I2C controller had to be I2C

> devices. These days that's no longer required. The i2c-mux can sit as a

> direct child of its parent controller, which is where it makes the most

> sense from a hardware description perspective. For the ACPI

> implementation we'll assume that's always how the i2c-mux-gpio is

> instantiated.

> 

> Signed-off-by: Evan Green <evgreen@chromium.org>


Applied to for-next, thanks! The code Andy mentioned can still be
refactored later if new ACPI helpers appear in the future.
Evan Green Jan. 17, 2021, 5:15 p.m. UTC | #10
On Sun, Jan 17, 2021 at 3:54 AM Wolfram Sang <wsa@kernel.org> wrote:
>

> On Wed, Nov 18, 2020 at 03:40:25PM -0800, Evan Green wrote:

> > Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state

> > property translates directly to a fwnode_property_*() call. The child

> > reg property translates naturally into _ADR in ACPI.

> >

> > The i2c-parent binding is a relic from the days when the bindings

> > dictated that all direct children of an I2C controller had to be I2C

> > devices. These days that's no longer required. The i2c-mux can sit as a

> > direct child of its parent controller, which is where it makes the most

> > sense from a hardware description perspective. For the ACPI

> > implementation we'll assume that's always how the i2c-mux-gpio is

> > instantiated.

> >

> > Signed-off-by: Evan Green <evgreen@chromium.org>

>

> Applied to for-next, thanks! The code Andy mentioned can still be

> refactored later if new ACPI helpers appear in the future.


Thanks Wolfram and Peter!
Andy Shevchenko Jan. 19, 2021, 12:10 p.m. UTC | #11
On Fri, Jan 15, 2021 at 10:29:46AM +0100, Peter Rosin wrote:
> On 2021-01-14 20:53, Wolfram Sang wrote:

> >> Can this be accepted as-is, or should I resend?

> > 

> > Peter, can you have a look here as well?

> 

> I have no issues, but I was waiting for a response from Andy here. I have

> little knowledge of ACPI, and have previously made ignorant mistakes in

> that area. I would greatly appreciate Andy following through with his

> line of thinking...

> 

> So, if we ignore Andys review comments, then:

> 

> Acked-by: Peter Rosin <peda@axentia.se>


Sorry guys for me being silent, I have a lot of stuff which makes me under
DDoS-like attack (metaphorically speaking). I'm going to look at this just now.

-- 
With Best Regards,
Andy Shevchenko
diff mbox series

Patch

diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index caaa782b50d83..bac415a52b780 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -49,35 +49,85 @@  static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
 	return 0;
 }
 
-#ifdef CONFIG_OF
-static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
-					struct platform_device *pdev)
+#ifdef CONFIG_ACPI
+
+static int i2c_mux_gpio_get_acpi_adr(struct device *dev,
+				     struct fwnode_handle *fwdev,
+				     unsigned int *adr)
+
+{
+	unsigned long long adr64;
+	acpi_status status;
+
+	status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev),
+				       METHOD_NAME__ADR,
+				       NULL, &adr64);
+
+	if (!ACPI_SUCCESS(status)) {
+		dev_err(dev, "Cannot get address\n");
+		return -EINVAL;
+	}
+
+	*adr = adr64;
+	if (*adr != adr64) {
+		dev_err(dev, "Address out of range\n");
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
+#else
+
+static int i2c_mux_gpio_get_acpi_adr(struct device *dev,
+				     struct fwnode_handle *fwdev,
+				     unsigned int *adr)
+{
+	return -EINVAL;
+}
+
+#endif
+
+static int i2c_mux_gpio_probe_fw(struct gpiomux *mux,
+				 struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *np = pdev->dev.of_node;
-	struct device_node *adapter_np, *child;
-	struct i2c_adapter *adapter;
+	struct device_node *np = dev->of_node;
+	struct device_node *adapter_np;
+	struct i2c_adapter *adapter = NULL;
+	struct fwnode_handle *child;
 	unsigned *values;
-	int i = 0;
+	int rc, i = 0;
+
+	if (is_of_node(dev->fwnode)) {
+		if (!np)
+			return -ENODEV;
 
-	if (!np)
-		return -ENODEV;
+		adapter_np = of_parse_phandle(np, "i2c-parent", 0);
+		if (!adapter_np) {
+			dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
+			return -ENODEV;
+		}
+		adapter = of_find_i2c_adapter_by_node(adapter_np);
+		of_node_put(adapter_np);
+
+	} else if (is_acpi_node(dev->fwnode)) {
+		/*
+		 * In ACPI land the mux should be a direct child of the i2c
+		 * bus it muxes.
+		 */
+		acpi_handle dev_handle = ACPI_HANDLE(dev->parent);
 
-	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
-	if (!adapter_np) {
-		dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
-		return -ENODEV;
+		adapter = i2c_acpi_find_adapter_by_handle(dev_handle);
 	}
-	adapter = of_find_i2c_adapter_by_node(adapter_np);
-	of_node_put(adapter_np);
+
 	if (!adapter)
 		return -EPROBE_DEFER;
 
 	mux->data.parent = i2c_adapter_id(adapter);
 	put_device(&adapter->dev);
 
-	mux->data.n_values = of_get_child_count(np);
-
+	mux->data.n_values = device_get_child_node_count(dev);
 	values = devm_kcalloc(dev,
 			      mux->data.n_values, sizeof(*mux->data.values),
 			      GFP_KERNEL);
@@ -86,24 +136,25 @@  static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
 		return -ENOMEM;
 	}
 
-	for_each_child_of_node(np, child) {
-		of_property_read_u32(child, "reg", values + i);
+	device_for_each_child_node(dev, child) {
+		if (is_of_node(child)) {
+			fwnode_property_read_u32(child, "reg", values + i);
+
+		} else if (is_acpi_node(child)) {
+			rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i);
+			if (rc)
+				return rc;
+		}
+
 		i++;
 	}
 	mux->data.values = values;
 
-	if (of_property_read_u32(np, "idle-state", &mux->data.idle))
+	if (fwnode_property_read_u32(dev->fwnode, "idle-state", &mux->data.idle))
 		mux->data.idle = I2C_MUX_GPIO_NO_IDLE;
 
 	return 0;
 }
-#else
-static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
-					struct platform_device *pdev)
-{
-	return 0;
-}
-#endif
 
 static int i2c_mux_gpio_probe(struct platform_device *pdev)
 {
@@ -119,7 +170,7 @@  static int i2c_mux_gpio_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	if (!dev_get_platdata(&pdev->dev)) {
-		ret = i2c_mux_gpio_probe_dt(mux, pdev);
+		ret = i2c_mux_gpio_probe_fw(mux, pdev);
 		if (ret < 0)
 			return ret;
 	} else {