Commit 0f614d83 authored by Jean-Michel Hautbois's avatar Jean-Michel Hautbois Committed by Wolfram Sang

i2c: Add generic support passing secondary devices addresses

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: default avatarJean-Michel Hautbois <jean-michel.hautbois@veo-labs.com>
Acked-by: default avatarRob Herring <robh@kernel.org>
Acked-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 5edb5649
...@@ -62,6 +62,13 @@ wants to support one of the below features, it should adapt the bindings below. ...@@ -62,6 +62,13 @@ wants to support one of the below features, it should adapt the bindings below.
- wakeup-source - wakeup-source
device can be used as a wakeup source. device can be used as a wakeup source.
- reg
I2C slave addresses
- reg-names
Names of map programmable addresses.
It can contain any map needing another address than default one.
Binding may contain optional "interrupts" property, describing interrupts Binding may contain optional "interrupts" property, describing interrupts
used by the device. I2C core will assign "irq" interrupt (or the very first used by the device. I2C core will assign "irq" interrupt (or the very first
interrupt if not using interrupt names) as primary interrupt for the slave. interrupt if not using interrupt names) as primary interrupt for the slave.
......
...@@ -1145,6 +1145,47 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address) ...@@ -1145,6 +1145,47 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
} }
EXPORT_SYMBOL_GPL(i2c_new_dummy); EXPORT_SYMBOL_GPL(i2c_new_dummy);
/**
* i2c_new_secondary_device - Helper to get the instantiated secondary address
* and create the associated device
* @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
*
* I2C clients can be composed of multiple I2C slaves bound together in a single
* component. The I2C client driver then binds to the master I2C slave and needs
* to create I2C dummy clients to communicate with all the other slaves.
*
* This function creates and returns an I2C dummy client whose I2C address is
* retrieved from the platform firmware based on the given slave name. If no
* address is specified by the firmware default_addr is used.
*
* On DT-based platforms the address is retrieved from the "reg" property entry
* cell whose "reg-names" value matches the slave name.
*
* 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)
{
struct device_node *np = client->dev.of_node;
u32 addr = default_addr;
int i;
if (np) {
i = of_property_match_string(np, "reg-names", name);
if (i >= 0)
of_property_read_u32_index(np, "reg", i, &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 */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */
......
...@@ -349,6 +349,11 @@ extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr); ...@@ -349,6 +349,11 @@ extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr);
extern struct i2c_client * extern struct i2c_client *
i2c_new_dummy(struct i2c_adapter *adap, u16 address); i2c_new_dummy(struct i2c_adapter *adap, u16 address);
extern struct i2c_client *
i2c_new_secondary_device(struct i2c_client *client,
const char *name,
u16 default_addr);
extern void i2c_unregister_device(struct i2c_client *); extern void i2c_unregister_device(struct i2c_client *);
#endif /* I2C */ #endif /* I2C */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment