diff mbox

i2c: Add generic support passing secondary devices addresses

Message ID 1409925739-28188-1-git-send-email-jean-michel.hautbois@vodalys.com
State Deferred
Headers show

Commit Message

Jean-Michel Hautbois Sept. 5, 2014, 2:02 p.m. UTC
Some I2C devices have multiple addresses assigned, for example each address
corresponding to a different internal register map page of the device.
So far drivers which need support for this have handled this with a driver
specific and non-generic implementation, e.g. passing the additional address
via platform data.

This patch provides a new helper function called i2c_new_secondary_device()
which is intended to provide a generic way to get the secondary address
as well as instantiate a struct i2c_client for the secondary address.

The function expects a pointer to the primary i2c_client, a name
for the secondary address and an optional default address. The name is used
as a handle to specify which secondary address to get.

The default address is used as a fallback in case no secondary address
was explicitly specified. In case no secondary address and no default
address were specified the function returns NULL.

For now the function only supports look-up of the secondary address
from devicetree, but it can be extended in the future
to for example support board files and/or ACPI.

Signed-off-by: Jean-Michel Hautbois <jean-michel.hautbois@vodalys.com>
---
 drivers/i2c/i2c-core.c | 40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/i2c.h    |  8 ++++++++
 2 files changed, 48 insertions(+)

Comments

Wolfram Sang Sept. 20, 2014, 4:49 p.m. UTC | #1
On Fri, Sep 05, 2014 at 04:02:19PM +0200, Jean-Michel Hautbois wrote:
> Some I2C devices have multiple addresses assigned, for example each address
> corresponding to a different internal register map page of the device.
> So far drivers which need support for this have handled this with a driver
> specific and non-generic implementation, e.g. passing the additional address
> via platform data.

This raises the first question for me: Are the additional addresses
configurable? Sadly, I can't find good documentation for the adv7604.
Otherwise, if I know I have a adv7604 and know its addresses, this
information should go into the driver and not the DT.
Lars-Peter Clausen Sept. 20, 2014, 7:50 p.m. UTC | #2
On 09/20/2014 06:49 PM, Wolfram Sang wrote:
> On Fri, Sep 05, 2014 at 04:02:19PM +0200, Jean-Michel Hautbois wrote:
>> Some I2C devices have multiple addresses assigned, for example each address
>> corresponding to a different internal register map page of the device.
>> So far drivers which need support for this have handled this with a driver
>> specific and non-generic implementation, e.g. passing the additional address
>> via platform data.
>
> This raises the first question for me: Are the additional addresses
> configurable? Sadly, I can't find good documentation for the adv7604.
> Otherwise, if I know I have a adv7604 and know its addresses, this
> information should go into the driver and not the DT.
>

They are. The current driver hard codes the other addresses, but that's not 
working when you have multiple adv7604s on the same I2C bus.

- Lars
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wolfram Sang Sept. 21, 2014, 5:49 p.m. UTC | #3
> >This raises the first question for me: Are the additional addresses
> >configurable? Sadly, I can't find good documentation for the adv7604.
> >Otherwise, if I know I have a adv7604 and know its addresses, this
> >information should go into the driver and not the DT.
> >
> 
> They are. The current driver hard codes the other addresses, but that's not
> working when you have multiple adv7604s on the same I2C bus.

How is this configured? I can't imagine every address has its own
setting, but rather some 1-3 pins which select a certain block of
addresses?
Lars-Peter Clausen Sept. 21, 2014, 7:23 p.m. UTC | #4
On 09/21/2014 07:49 PM, Wolfram Sang wrote:
>
>>> This raises the first question for me: Are the additional addresses
>>> configurable? Sadly, I can't find good documentation for the adv7604.
>>> Otherwise, if I know I have a adv7604 and know its addresses, this
>>> information should go into the driver and not the DT.
>>>
>>
>> They are. The current driver hard codes the other addresses, but that's not
>> working when you have multiple adv7604s on the same I2C bus.
>
> How is this configured? I can't imagine every address has its own
> setting, but rather some 1-3 pins which select a certain block of
> addresses?
>

Every secondary address has its own register and can be set to any valid I2C 
address.

- Lars
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg Sept. 22, 2014, 10:45 a.m. UTC | #5
On Fri, Sep 05, 2014 at 04:02:19PM +0200, Jean-Michel Hautbois wrote:
> Some I2C devices have multiple addresses assigned, for example each address
> corresponding to a different internal register map page of the device.
> So far drivers which need support for this have handled this with a driver
> specific and non-generic implementation, e.g. passing the additional address
> via platform data.
> 
> This patch provides a new helper function called i2c_new_secondary_device()
> which is intended to provide a generic way to get the secondary address
> as well as instantiate a struct i2c_client for the secondary address.
> 
> The function expects a pointer to the primary i2c_client, a name
> for the secondary address and an optional default address. The name is used
> as a handle to specify which secondary address to get.
> 
> The default address is used as a fallback in case no secondary address
> was explicitly specified. In case no secondary address and no default
> address were specified the function returns NULL.
> 
> For now the function only supports look-up of the secondary address
> from devicetree, but it can be extended in the future
> to for example support board files and/or ACPI.
> 
> Signed-off-by: Jean-Michel Hautbois <jean-michel.hautbois@vodalys.com>

Sorry, just noticed this one.

Srinivas (CC'd) and I did similar patch series here:

http://patchwork.ozlabs.org/patch/338342/

We should probably collaborate on this one to get both DT and ACPI
supported.

> ---
>  drivers/i2c/i2c-core.c | 40 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/i2c.h    |  8 ++++++++
>  2 files changed, 48 insertions(+)
> 
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index 632057a..ef31d6f 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -798,6 +798,46 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
>  }
>  EXPORT_SYMBOL_GPL(i2c_new_dummy);
>  
> +/**
> + * i2c_new_secondary_device - Helper to get the instantiated secondary address
> + * @client: Handle to the primary client
> + * @name: Handle to specify which secondary address to get
> + * @default_addr: Used as a fallback if no secondary address was specified
> + * Context: can sleep
> + *
> + * This returns an I2C client bound to the "dummy" driver based on DT parsing.
> + *
> + * This returns the new i2c client, which should be saved for later use with
> + * i2c_unregister_device(); or NULL to indicate an error.
> + */
> +struct i2c_client *i2c_new_secondary_device(struct i2c_client *client,
> +						const char *name,
> +						u16 default_addr)
> +{
> +	int i;
> +	u32 addr;
> +	struct device_node *np;
> +
> +	np = client->dev.of_node;
> +
> +	if (np) {
> +		i = of_property_match_string(np, "reg-names", name);
> +		if (i >= 0)
> +			of_property_read_u32_index(np, "reg", i, &addr);
> +		else if (default_addr != 0)
> +			addr = default_addr;
> +		else
> +			addr = NULL;
> +	} else {
> +		addr = default_addr;
> +	}
> +
> +	dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr);
> +	return i2c_new_dummy(client->adapter, addr);
> +}
> +EXPORT_SYMBOL_GPL(i2c_new_secondary_device);
> +
> +
>  /* ------------------------------------------------------------------------- */
>  
>  /* I2C bus adapters -- one roots each I2C or SMBUS segment */
> diff --git a/include/linux/i2c.h b/include/linux/i2c.h
> index a95efeb..0f190e6 100644
> --- a/include/linux/i2c.h
> +++ b/include/linux/i2c.h
> @@ -322,6 +322,14 @@ extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr);
>  extern struct i2c_client *
>  i2c_new_dummy(struct i2c_adapter *adap, u16 address);
>  
> +/* Helper function providing a generic way to get the secondary address
> + * as well as a client handle to this extra address.
> + */
> +extern struct i2c_client *
> +i2c_new_secondary_device(struct i2c_client *client,
> +				const char *name,
> +				u32 default_addr);
> +
>  extern void i2c_unregister_device(struct i2c_client *);
>  #endif /* I2C */
>  
> -- 
> 2.0.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lars-Peter Clausen Sept. 22, 2014, 1:27 p.m. UTC | #6
On 09/22/2014 12:45 PM, Mika Westerberg wrote:
> On Fri, Sep 05, 2014 at 04:02:19PM +0200, Jean-Michel Hautbois wrote:
>> Some I2C devices have multiple addresses assigned, for example each address
>> corresponding to a different internal register map page of the device.
>> So far drivers which need support for this have handled this with a driver
>> specific and non-generic implementation, e.g. passing the additional address
>> via platform data.
>>
>> This patch provides a new helper function called i2c_new_secondary_device()
>> which is intended to provide a generic way to get the secondary address
>> as well as instantiate a struct i2c_client for the secondary address.
>>
>> The function expects a pointer to the primary i2c_client, a name
>> for the secondary address and an optional default address. The name is used
>> as a handle to specify which secondary address to get.
>>
>> The default address is used as a fallback in case no secondary address
>> was explicitly specified. In case no secondary address and no default
>> address were specified the function returns NULL.
>>
>> For now the function only supports look-up of the secondary address
>> from devicetree, but it can be extended in the future
>> to for example support board files and/or ACPI.
>>
>> Signed-off-by: Jean-Michel Hautbois <jean-michel.hautbois@vodalys.com>
>
> Sorry, just noticed this one.
>
> Srinivas (CC'd) and I did similar patch series here:
>
> http://patchwork.ozlabs.org/patch/338342/
>
> We should probably collaborate on this one to get both DT and ACPI
> supported.

Yes. The idea was to keep the interface of the API generic so it can be used 
by ACPI or other device topology description mechanisms as well.

But it looks as if the ACPI case is a bit more complex and we may need a 
revision of the API. How for example in the ACPI case do you know which 
address is which, when different parts of a chip are addressed using 
different addresses?

- Lars

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg Sept. 22, 2014, 1:45 p.m. UTC | #7
On Mon, Sep 22, 2014 at 03:27:36PM +0200, Lars-Peter Clausen wrote:
> On 09/22/2014 12:45 PM, Mika Westerberg wrote:
> >On Fri, Sep 05, 2014 at 04:02:19PM +0200, Jean-Michel Hautbois wrote:
> >>Some I2C devices have multiple addresses assigned, for example each address
> >>corresponding to a different internal register map page of the device.
> >>So far drivers which need support for this have handled this with a driver
> >>specific and non-generic implementation, e.g. passing the additional address
> >>via platform data.
> >>
> >>This patch provides a new helper function called i2c_new_secondary_device()
> >>which is intended to provide a generic way to get the secondary address
> >>as well as instantiate a struct i2c_client for the secondary address.
> >>
> >>The function expects a pointer to the primary i2c_client, a name
> >>for the secondary address and an optional default address. The name is used
> >>as a handle to specify which secondary address to get.
> >>
> >>The default address is used as a fallback in case no secondary address
> >>was explicitly specified. In case no secondary address and no default
> >>address were specified the function returns NULL.
> >>
> >>For now the function only supports look-up of the secondary address
> >>from devicetree, but it can be extended in the future
> >>to for example support board files and/or ACPI.
> >>
> >>Signed-off-by: Jean-Michel Hautbois <jean-michel.hautbois@vodalys.com>
> >
> >Sorry, just noticed this one.
> >
> >Srinivas (CC'd) and I did similar patch series here:
> >
> >http://patchwork.ozlabs.org/patch/338342/

Sorry I gave wrong link. That one is older version.

Here is the current:

http://patchwork.ozlabs.org/patch/386409/
http://patchwork.ozlabs.org/patch/386410/

> >
> >We should probably collaborate on this one to get both DT and ACPI
> >supported.
> 
> Yes. The idea was to keep the interface of the API generic so it can be used
> by ACPI or other device topology description mechanisms as well.
> 
> But it looks as if the ACPI case is a bit more complex and we may need a
> revision of the API. How for example in the ACPI case do you know which
> address is which, when different parts of a chip are addressed using
> different addresses?

Unfortunately there is no way in ACPI 5.0 to find out which is which. So
we trust the ordering of I2cSerialBus() resources. Even that has been
problematic because some vendors then list things like SMBus ARA
addresses there in random order :-(

Our API has following signature:

int i2c_address_by_index(struct i2c_client *client, int index,
			 struct i2c_board_info *info,
			 struct i2c_adapter **adapter)

and we use index to find out which address to use.

Note also that in ACPI it is possible that the I2cSerialBus() resource
points to another I2C host controller, so we need to have 'adapter'
parameter as well.
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lars-Peter Clausen Sept. 22, 2014, 2:11 p.m. UTC | #8
On 09/22/2014 03:45 PM, Mika Westerberg wrote:
> On Mon, Sep 22, 2014 at 03:27:36PM +0200, Lars-Peter Clausen wrote:
>> On 09/22/2014 12:45 PM, Mika Westerberg wrote:
>>> On Fri, Sep 05, 2014 at 04:02:19PM +0200, Jean-Michel Hautbois wrote:
>>>> Some I2C devices have multiple addresses assigned, for example each address
>>>> corresponding to a different internal register map page of the device.
>>>> So far drivers which need support for this have handled this with a driver
>>>> specific and non-generic implementation, e.g. passing the additional address
>>>> via platform data.
>>>>
>>>> This patch provides a new helper function called i2c_new_secondary_device()
>>>> which is intended to provide a generic way to get the secondary address
>>>> as well as instantiate a struct i2c_client for the secondary address.
>>>>
>>>> The function expects a pointer to the primary i2c_client, a name
>>>> for the secondary address and an optional default address. The name is used
>>>> as a handle to specify which secondary address to get.
>>>>
>>>> The default address is used as a fallback in case no secondary address
>>>> was explicitly specified. In case no secondary address and no default
>>>> address were specified the function returns NULL.
>>>>
>>>> For now the function only supports look-up of the secondary address
>>> >from devicetree, but it can be extended in the future
>>>> to for example support board files and/or ACPI.
>>>>
>>>> Signed-off-by: Jean-Michel Hautbois <jean-michel.hautbois@vodalys.com>
>>>
>>> Sorry, just noticed this one.
>>>
>>> Srinivas (CC'd) and I did similar patch series here:
>>>
>>> http://patchwork.ozlabs.org/patch/338342/
>
> Sorry I gave wrong link. That one is older version.
>
> Here is the current:
>
> http://patchwork.ozlabs.org/patch/386409/
> http://patchwork.ozlabs.org/patch/386410/
>
>>>
>>> We should probably collaborate on this one to get both DT and ACPI
>>> supported.
>>
>> Yes. The idea was to keep the interface of the API generic so it can be used
>> by ACPI or other device topology description mechanisms as well.
>>
>> But it looks as if the ACPI case is a bit more complex and we may need a
>> revision of the API. How for example in the ACPI case do you know which
>> address is which, when different parts of a chip are addressed using
>> different addresses?
>
> Unfortunately there is no way in ACPI 5.0 to find out which is which. So
> we trust the ordering of I2cSerialBus() resources. Even that has been
> problematic because some vendors then list things like SMBus ARA
> addresses there in random order :-(
>
> Our API has following signature:
>
> int i2c_address_by_index(struct i2c_client *client, int index,
> 			 struct i2c_board_info *info,
> 			 struct i2c_adapter **adapter)
>
> and we use index to find out which address to use.
>
> Note also that in ACPI it is possible that the I2cSerialBus() resource
> points to another I2C host controller, so we need to have 'adapter'
> parameter as well.
>

Ok, looks like there are two main differences in the two implementations.

1) The ACPI one uses a integer index and the DT one uses a string index to 
lookup the device.

The problem with the index lookup is that the order is binding specific. So 
it might be different between e.g. the devicetree binding and the ACPI 
binding. This makes it quite hard to use the API in a generic way and you'd 
end up with hacks like:

if (client->dev.of_node)
	index = 3;
else if (ACPI_COMPANION(client->dev))
	index = 1;
else
	index = 5;


So we might need a extra translation table which maps a name to a ACPI index 
and then we could use the name as the generic index in the driver.

2) The ACPI implementation returns the i2c_board_info and the adapter, while 
the DT implementation returns the instantiated I2C client device.

It might make sense to have both. I image that most drivers are just 
interested in creating a new client device and will simply pass the board 
info and adapter they got to i2c_new_device(). In this case it makes sense 
to have a helper function which already does this internally to avoid 
boilerplate code duplication.

There will probably some special cases though in which case the driver wants 
to get the adapter and the board info and then manually call 
i2c_new_device() after having done some additional steps.

- Lars
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg Sept. 22, 2014, 2:41 p.m. UTC | #9
On Mon, Sep 22, 2014 at 04:11:52PM +0200, Lars-Peter Clausen wrote:
> On 09/22/2014 03:45 PM, Mika Westerberg wrote:
> >On Mon, Sep 22, 2014 at 03:27:36PM +0200, Lars-Peter Clausen wrote:
> >>On 09/22/2014 12:45 PM, Mika Westerberg wrote:
> >>>On Fri, Sep 05, 2014 at 04:02:19PM +0200, Jean-Michel Hautbois wrote:
> >>>>Some I2C devices have multiple addresses assigned, for example each address
> >>>>corresponding to a different internal register map page of the device.
> >>>>So far drivers which need support for this have handled this with a driver
> >>>>specific and non-generic implementation, e.g. passing the additional address
> >>>>via platform data.
> >>>>
> >>>>This patch provides a new helper function called i2c_new_secondary_device()
> >>>>which is intended to provide a generic way to get the secondary address
> >>>>as well as instantiate a struct i2c_client for the secondary address.
> >>>>
> >>>>The function expects a pointer to the primary i2c_client, a name
> >>>>for the secondary address and an optional default address. The name is used
> >>>>as a handle to specify which secondary address to get.
> >>>>
> >>>>The default address is used as a fallback in case no secondary address
> >>>>was explicitly specified. In case no secondary address and no default
> >>>>address were specified the function returns NULL.
> >>>>
> >>>>For now the function only supports look-up of the secondary address
> >>>>from devicetree, but it can be extended in the future
> >>>>to for example support board files and/or ACPI.
> >>>>
> >>>>Signed-off-by: Jean-Michel Hautbois <jean-michel.hautbois@vodalys.com>
> >>>
> >>>Sorry, just noticed this one.
> >>>
> >>>Srinivas (CC'd) and I did similar patch series here:
> >>>
> >>>http://patchwork.ozlabs.org/patch/338342/
> >
> >Sorry I gave wrong link. That one is older version.
> >
> >Here is the current:
> >
> >http://patchwork.ozlabs.org/patch/386409/
> >http://patchwork.ozlabs.org/patch/386410/
> >
> >>>
> >>>We should probably collaborate on this one to get both DT and ACPI
> >>>supported.
> >>
> >>Yes. The idea was to keep the interface of the API generic so it can be used
> >>by ACPI or other device topology description mechanisms as well.
> >>
> >>But it looks as if the ACPI case is a bit more complex and we may need a
> >>revision of the API. How for example in the ACPI case do you know which
> >>address is which, when different parts of a chip are addressed using
> >>different addresses?
> >
> >Unfortunately there is no way in ACPI 5.0 to find out which is which. So
> >we trust the ordering of I2cSerialBus() resources. Even that has been
> >problematic because some vendors then list things like SMBus ARA
> >addresses there in random order :-(
> >
> >Our API has following signature:
> >
> >int i2c_address_by_index(struct i2c_client *client, int index,
> >			 struct i2c_board_info *info,
> >			 struct i2c_adapter **adapter)
> >
> >and we use index to find out which address to use.
> >
> >Note also that in ACPI it is possible that the I2cSerialBus() resource
> >points to another I2C host controller, so we need to have 'adapter'
> >parameter as well.
> >
> 
> Ok, looks like there are two main differences in the two implementations.
> 
> 1) The ACPI one uses a integer index and the DT one uses a string index to
> lookup the device.
> 
> The problem with the index lookup is that the order is binding specific. So
> it might be different between e.g. the devicetree binding and the ACPI
> binding. This makes it quite hard to use the API in a generic way and you'd
> end up with hacks like:
> 
> if (client->dev.of_node)
> 	index = 3;
> else if (ACPI_COMPANION(client->dev))
> 	index = 1;
> else
> 	index = 5;
> 

Indeed.

> So we might need a extra translation table which maps a name to a ACPI index
> and then we could use the name as the generic index in the driver.

Good thing is that ACPI 5.1 _DSD finally allows us to use similar naming
as the DT has been doing. Problem is that we need to support both the
new way *and* the older index lookup somehow :-/

> 2) The ACPI implementation returns the i2c_board_info and the adapter, while
> the DT implementation returns the instantiated I2C client device.
> 
> It might make sense to have both. I image that most drivers are just
> interested in creating a new client device and will simply pass the board
> info and adapter they got to i2c_new_device(). In this case it makes sense
> to have a helper function which already does this internally to avoid
> boilerplate code duplication.

I agree. How about making that helper a wrapper around the function that
returns both i2c_board_info and an adapter?

> There will probably some special cases though in which case the driver wants
> to get the adapter and the board info and then manually call
> i2c_new_device() after having done some additional steps.

Yes, if the alternative address happens to be on another bus. That
should at least be possible with this API.
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wolfram Sang Oct. 3, 2014, 10:46 a.m. UTC | #10
> > Ok, looks like there are two main differences in the two implementations.
> > 
> > 1) The ACPI one uses a integer index and the DT one uses a string index to
> > lookup the device.
> > 
> > The problem with the index lookup is that the order is binding specific. So
> > it might be different between e.g. the devicetree binding and the ACPI
> > binding. This makes it quite hard to use the API in a generic way and you'd
> > end up with hacks like:
> > 
> > if (client->dev.of_node)
> > 	index = 3;
> > else if (ACPI_COMPANION(client->dev))
> > 	index = 1;
> > else
> > 	index = 5;
> > 
> 
> Indeed.
> 
> > So we might need a extra translation table which maps a name to a ACPI index
> > and then we could use the name as the generic index in the driver.
> 
> Good thing is that ACPI 5.1 _DSD finally allows us to use similar naming
> as the DT has been doing. Problem is that we need to support both the
> new way *and* the older index lookup somehow :-/
> 
> > 2) The ACPI implementation returns the i2c_board_info and the adapter, while
> > the DT implementation returns the instantiated I2C client device.
> > 
> > It might make sense to have both. I image that most drivers are just
> > interested in creating a new client device and will simply pass the board
> > info and adapter they got to i2c_new_device(). In this case it makes sense
> > to have a helper function which already does this internally to avoid
> > boilerplate code duplication.
> 
> I agree. How about making that helper a wrapper around the function that
> returns both i2c_board_info and an adapter?
> 
> > There will probably some special cases though in which case the driver wants
> > to get the adapter and the board info and then manually call
> > i2c_new_device() after having done some additional steps.
> 
> Yes, if the alternative address happens to be on another bus. That
> should at least be possible with this API.

Thanks for the discussion so far! I'll wait and see if some patches come
out of it and mark this one as deferred for now.
Srinivas Pandruvada Oct. 15, 2014, 6:54 p.m. UTC | #11
Hi Lars and Jean,

Are you taking this patch further to take care about ACPI related stuff
submitted by Mika?

Thanks,
Srinivas
On Fri, 2014-10-03 at 12:46 +0200, Wolfram Sang wrote: 
> > > Ok, looks like there are two main differences in the two implementations.
> > > 
> > > 1) The ACPI one uses a integer index and the DT one uses a string index to
> > > lookup the device.
> > > 
> > > The problem with the index lookup is that the order is binding specific. So
> > > it might be different between e.g. the devicetree binding and the ACPI
> > > binding. This makes it quite hard to use the API in a generic way and you'd
> > > end up with hacks like:
> > > 
> > > if (client->dev.of_node)
> > > 	index = 3;
> > > else if (ACPI_COMPANION(client->dev))
> > > 	index = 1;
> > > else
> > > 	index = 5;
> > > 
> > 
> > Indeed.
> > 
> > > So we might need a extra translation table which maps a name to a ACPI index
> > > and then we could use the name as the generic index in the driver.
> > 
> > Good thing is that ACPI 5.1 _DSD finally allows us to use similar naming
> > as the DT has been doing. Problem is that we need to support both the
> > new way *and* the older index lookup somehow :-/
> > 
> > > 2) The ACPI implementation returns the i2c_board_info and the adapter, while
> > > the DT implementation returns the instantiated I2C client device.
> > > 
> > > It might make sense to have both. I image that most drivers are just
> > > interested in creating a new client device and will simply pass the board
> > > info and adapter they got to i2c_new_device(). In this case it makes sense
> > > to have a helper function which already does this internally to avoid
> > > boilerplate code duplication.
> > 
> > I agree. How about making that helper a wrapper around the function that
> > returns both i2c_board_info and an adapter?
> > 
> > > There will probably some special cases though in which case the driver wants
> > > to get the adapter and the board info and then manually call
> > > i2c_new_device() after having done some additional steps.
> > 
> > Yes, if the alternative address happens to be on another bus. That
> > should at least be possible with this API.
> 
> Thanks for the discussion so far! I'll wait and see if some patches come
> out of it and mark this one as deferred for now.
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 632057a..ef31d6f 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -798,6 +798,46 @@  struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
 }
 EXPORT_SYMBOL_GPL(i2c_new_dummy);
 
+/**
+ * i2c_new_secondary_device - Helper to get the instantiated secondary address
+ * @client: Handle to the primary client
+ * @name: Handle to specify which secondary address to get
+ * @default_addr: Used as a fallback if no secondary address was specified
+ * Context: can sleep
+ *
+ * This returns an I2C client bound to the "dummy" driver based on DT parsing.
+ *
+ * This returns the new i2c client, which should be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *i2c_new_secondary_device(struct i2c_client *client,
+						const char *name,
+						u16 default_addr)
+{
+	int i;
+	u32 addr;
+	struct device_node *np;
+
+	np = client->dev.of_node;
+
+	if (np) {
+		i = of_property_match_string(np, "reg-names", name);
+		if (i >= 0)
+			of_property_read_u32_index(np, "reg", i, &addr);
+		else if (default_addr != 0)
+			addr = default_addr;
+		else
+			addr = NULL;
+	} else {
+		addr = default_addr;
+	}
+
+	dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr);
+	return i2c_new_dummy(client->adapter, addr);
+}
+EXPORT_SYMBOL_GPL(i2c_new_secondary_device);
+
+
 /* ------------------------------------------------------------------------- */
 
 /* I2C bus adapters -- one roots each I2C or SMBUS segment */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index a95efeb..0f190e6 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -322,6 +322,14 @@  extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr);
 extern struct i2c_client *
 i2c_new_dummy(struct i2c_adapter *adap, u16 address);
 
+/* Helper function providing a generic way to get the secondary address
+ * as well as a client handle to this extra address.
+ */
+extern struct i2c_client *
+i2c_new_secondary_device(struct i2c_client *client,
+				const char *name,
+				u32 default_addr);
+
 extern void i2c_unregister_device(struct i2c_client *);
 #endif /* I2C */