From cefae80249f6bf3fdbc7c3a00bc43deb4c1bccf0 Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Thu, 26 Jan 2017 17:45:32 +0000 Subject: i2c: core: helper function to detect slave mode This function has the purpose of mode detection by checking the device nodes for a reg matching with the I2C_OWN_SLAVE_ADDREESS flag. Currently only checks using OF functions (ACPI slave not supported yet). Signed-off-by: Luis Oliveira Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/i2c/i2c-core.c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 583e95042a21..408de741fec5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -3690,6 +3690,39 @@ int i2c_slave_unregister(struct i2c_client *client) return ret; } EXPORT_SYMBOL_GPL(i2c_slave_unregister); + +/** + * i2c_detect_slave_mode - detect operation mode + * @dev: The device owning the bus + * + * This checks the device nodes for an I2C slave by checking the address + * used in the reg property. If the address match the I2C_OWN_SLAVE_ADDRESS + * flag this means the device is configured to act as a I2C slave and it will + * be listening at that address. + * + * Returns true if an I2C own slave address is detected, otherwise returns + * false. + */ +bool i2c_detect_slave_mode(struct device *dev) +{ + if (IS_BUILTIN(CONFIG_OF) && dev->of_node) { + struct device_node *child; + u32 reg; + + for_each_child_of_node(dev->of_node, child) { + of_property_read_u32(child, "reg", ®); + if (reg & I2C_OWN_SLAVE_ADDRESS) { + of_node_put(child); + return true; + } + } + } else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) { + dev_dbg(dev, "ACPI slave is not supported yet\n"); + } + return false; +} +EXPORT_SYMBOL_GPL(i2c_detect_slave_mode); + #endif MODULE_AUTHOR("Simon G. Vogl "); -- cgit v1.2.3 From 622b307712f1d02048a7abbe376cf30f04c5b310 Mon Sep 17 00:00:00 2001 From: Dan O'Donovan Date: Sun, 5 Feb 2017 16:30:13 +0000 Subject: i2c: acpi: Initialize info.type from of_compatible When using devicetree i2c_board_info.type is set to the compatible string with the vendor prefix removed. For I2C devices described via ACPI the i2c_board_info.type string is set to the ACPI device name. When using ACPI and DT ids this string ends up something like "PRP0001:00". If the of_compatible property is present try to use that instead. This makes it easier to instantiate i2c drivers through ACPI with DT ids. Signed-off-by: Dan O'Donovan Reviewed-by: Andy Shevchenko Reviewed-by: Jarkko Nikula Tested-by: Jarkko Nikula Acked-by: Wolfram Sang Signed-off-by: Rafael J. Wysocki --- drivers/i2c/i2c-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/i2c-core.c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 583e95042a21..1e52395e90a7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -221,7 +221,8 @@ static int i2c_acpi_get_info(struct acpi_device *adev, acpi_dev_free_resource_list(&resource_list); - strlcpy(info->type, dev_name(&adev->dev), sizeof(info->type)); + acpi_set_modalias(adev, dev_name(&adev->dev), info->type, + sizeof(info->type)); return 0; } -- cgit v1.2.3 From d3e1b617ae20c459627f501b4bc55b1ea91f662b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 2 Feb 2017 17:41:28 -0800 Subject: i2c: allow specify device properties in i2c_board_info With many drivers converting to using generic device properties, it is useful to provide array of device properties when instantiating new i2c client via i2c_board_info and have them automatically added to the device in question. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Acked-by: Wolfram Sang Signed-off-by: Rafael J. Wysocki --- drivers/i2c/i2c-core.c | 16 +++++++++++++++- include/linux/i2c.h | 3 +++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/i2c-core.c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 583e95042a21..f72292156faf 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1335,15 +1335,29 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.fwnode = info->fwnode; i2c_dev_set_name(adap, client); + + if (info->properties) { + status = device_add_properties(&client->dev, info->properties); + if (status) { + dev_err(&adap->dev, + "Failed to add properties to client %s: %d\n", + client->name, status); + goto out_err; + } + } + status = device_register(&client->dev); if (status) - goto out_err; + goto out_free_props; dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); return client; +out_free_props: + if (info->properties) + device_remove_properties(&client->dev); out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x (%d)\n", diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 4b45ec46161f..7b23a3316dcb 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -51,6 +51,7 @@ enum i2c_slave_event; typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *); struct module; +struct property_entry; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /* @@ -299,6 +300,7 @@ static inline int i2c_slave_event(struct i2c_client *client, * @archdata: copied into i2c_client.dev.archdata * @of_node: pointer to OpenFirmware device node * @fwnode: device node supplied by the platform firmware + * @properties: additional device properties for the device * @irq: stored in i2c_client.irq * * I2C doesn't actually support hardware probing, although controllers and @@ -320,6 +322,7 @@ struct i2c_board_info { struct dev_archdata *archdata; struct device_node *of_node; struct fwnode_handle *fwnode; + const struct property_entry *properties; int irq; }; -- cgit v1.2.3 From 00a06c22e9fc0a33ae0b6ca2d47938340dbcd539 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 4 Mar 2017 11:29:34 -0800 Subject: i2c: export i2c_client_type structure i2c bus has 2 different types of device belonging to the same bus and bus notifiers use device type to distinguish between adapters and clients. Previously we only had i2c_adapter_type exported, which made code wanting to work with i2c_client devices test for type not equal to adapter type. This unfortunately is not safe if we ever add another type to the bus, so let's export i2c_client_type as well. Reviewed-by: Jean Delvare Acked-by: Benjamin Tissoires Reviewed-by: Wolfram Sang Signed-off-by: Dmitry Torokhov --- drivers/i2c/i2c-core.c | 4 ++-- include/linux/i2c.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/i2c/i2c-core.c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d2402bbf6729..bf7892e3b0c8 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); /** diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 6b183521c616..6366989d1001 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 ------------------------------------------------ */ -- cgit v1.2.3 From 4124c4eba40256b65acb5016a1edfdd59a1960b6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 1 Mar 2017 11:45:51 -0800 Subject: i2c: allow attaching IRQ resources to i2c_board_info Simple integer for interrupt number is not expressive enough, as it does not convey interrupt trigger type that should be used. Let's allow attaching array of resources to the board info and have i2c core parse first IRQ resource and set up interrupt trigger as needed. Reviewed-by: Wolfram Sang Signed-off-by: Dmitry Torokhov --- drivers/i2c/i2c-boardinfo.c | 12 ++++++++++++ drivers/i2c/i2c-core.c | 30 ++++++++++++++++++++++++++++++ include/linux/i2c.h | 4 ++++ 3 files changed, 46 insertions(+) (limited to 'drivers/i2c/i2c-core.c') diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 0e285c68b2ff..31186ead5a40 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -90,6 +90,18 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig } } + 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 bf7892e3b0c8..679a31fcb6d6 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -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 6366989d1001..c5bd8b8daf97 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -304,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 @@ -326,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; }; -- cgit v1.2.3