summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/i2c/i2c-boardinfo.c24
-rw-r--r--drivers/i2c/i2c-core.c34
-rw-r--r--include/linux/i2c.h5
3 files changed, 61 insertions, 2 deletions
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
index 6e5fac6a5262..31186ead5a40 100644
--- a/drivers/i2c/i2c-boardinfo.c
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -15,6 +15,7 @@
#include <linux/export.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
+#include <linux/property.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
@@ -55,6 +56,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
*
* The board info passed can safely be __initdata, but be careful of embedded
* pointers (for platform_data, functions, etc) since that won't be copied.
+ * Device properties are deep-copied though.
*/
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
{
@@ -78,6 +80,28 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig
devinfo->busnum = busnum;
devinfo->board_info = *info;
+
+ if (info->properties) {
+ devinfo->board_info.properties =
+ property_entries_dup(info->properties);
+ if (IS_ERR(devinfo->board_info.properties)) {
+ status = PTR_ERR(devinfo->board_info.properties);
+ break;
+ }
+ }
+
+ if (info->resources) {
+ devinfo->board_info.resources =
+ kmemdup(info->resources,
+ info->num_resources *
+ sizeof(*info->resources),
+ GFP_KERNEL);
+ if (!devinfo->board_info.resources) {
+ status = -ENOMEM;
+ break;
+ }
+ }
+
list_add_tail(&devinfo->list, &__i2c_board_list);
}
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d2402bbf6729..679a31fcb6d6 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -74,7 +74,6 @@
static DEFINE_MUTEX(core_lock);
static DEFINE_IDR(i2c_adapter_idr);
-static struct device_type i2c_client_type;
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE;
@@ -1097,11 +1096,12 @@ struct bus_type i2c_bus_type = {
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
-static struct device_type i2c_client_type = {
+struct device_type i2c_client_type = {
.groups = i2c_dev_groups,
.uevent = i2c_device_uevent,
.release = i2c_client_dev_release,
};
+EXPORT_SYMBOL_GPL(i2c_client_type);
/**
@@ -1278,6 +1278,32 @@ static void i2c_dev_set_name(struct i2c_adapter *adap,
i2c_encode_flags_to_addr(client));
}
+static int i2c_dev_irq_from_resources(const struct resource *resources,
+ unsigned int num_resources)
+{
+ struct irq_data *irqd;
+ int i;
+
+ for (i = 0; i < num_resources; i++) {
+ const struct resource *r = &resources[i];
+
+ if (resource_type(r) != IORESOURCE_IRQ)
+ continue;
+
+ if (r->flags & IORESOURCE_BITS) {
+ irqd = irq_get_irq_data(r->start);
+ if (!irqd)
+ break;
+
+ irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS);
+ }
+
+ return r->start;
+ }
+
+ return 0;
+}
+
/**
* i2c_new_device - instantiate an i2c device
* @adap: the adapter managing the device
@@ -1313,7 +1339,11 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->flags = info->flags;
client->addr = info->addr;
+
client->irq = info->irq;
+ if (!client->irq)
+ client->irq = i2c_dev_irq_from_resources(info->resources,
+ info->num_resources);
strlcpy(client->name, info->type, sizeof(client->name));
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 6b183521c616..c5bd8b8daf97 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -38,6 +38,7 @@
extern struct bus_type i2c_bus_type;
extern struct device_type i2c_adapter_type;
+extern struct device_type i2c_client_type;
/* --- General options ------------------------------------------------ */
@@ -303,6 +304,8 @@ static inline int i2c_slave_event(struct i2c_client *client,
* @of_node: pointer to OpenFirmware device node
* @fwnode: device node supplied by the platform firmware
* @properties: additional device properties for the device
+ * @resources: resources associated with the device
+ * @num_resources: number of resources in the @resources array
* @irq: stored in i2c_client.irq
*
* I2C doesn't actually support hardware probing, although controllers and
@@ -325,6 +328,8 @@ struct i2c_board_info {
struct device_node *of_node;
struct fwnode_handle *fwnode;
const struct property_entry *properties;
+ const struct resource *resources;
+ unsigned int num_resources;
int irq;
};