From fb79e09a74faf39fbeee975e0ead442b7b7f6aac Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 29 Jun 2016 15:04:03 +0200 Subject: i2c: add i2c_trylock_bus wrapper, use it This unifies usage with i2c_lock_bus and i2c_unlock_bus, and paves the way for the next patch which looks a bit saner with this preparatory work taken care of beforehand. Signed-off-by: Peter Rosin Signed-off-by: Wolfram Sang --- include/linux/i2c.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'include/linux/i2c.h') diff --git a/include/linux/i2c.h b/include/linux/i2c.h index fffdc270ca18..c1f60a345db7 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -600,6 +600,20 @@ i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags) adapter->lock_bus(adapter, flags); } +/** + * i2c_trylock_bus - Try to get exclusive access to an I2C bus segment + * @adapter: Target I2C bus segment + * @flags: I2C_LOCK_ROOT_ADAPTER tries to locks the root i2c adapter, + * I2C_LOCK_SEGMENT tries to lock only this branch in the adapter tree + * + * Return: true if the I2C bus segment is locked, false otherwise + */ +static inline int +i2c_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) +{ + return adapter->trylock_bus(adapter, flags); +} + /** * i2c_unlock_bus - Release exclusive access to an I2C bus segment * @adapter: Target I2C bus segment -- cgit v1.2.3 From 5853b22d96fa786365ff11fe9f008a68a533f043 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 12 Aug 2016 17:02:53 +0300 Subject: i2c: core: Add function for finding the bus speed from ACPI, take 2 ACPI 5 specification doesn't have property for the I2C bus speed but I2cSerialBus resource descriptor which define each controller-slave connection define the maximum speed supported by that connection. Thus finding the maximum safe speed for the bus is to walk through all I2cSerialBus resources that are associated to I2C controller and use the speed of slowest connection. Add function i2c_acpi_find_bus_speed() to the i2c-core that adapter drivers can call prior registering itself to core. This implies two-step walk through the I2cSerialBus resources: call to i2c_acpi_find_bus_speed() does the first scan and finds the safe bus speed that adapter drivers can set up. Adapter driver registration does the second scan when i2c-core creates the I2C slaves by calling the i2c_acpi_register_devices(). In that way the bus speed is set in case slave device probe gets called during registration and does communication. Previous version commit 55d38d060e99 ("i2c: core: Add function for finding the bus speed from ACPI") got reverted due merge conflicts from commit 525e6fabeae2 ("i2c / ACPI: add support for ACPI reconfigure notifications"). This version is a bit bigger than previous version but is still sharing the lowest and complicated part of I2cSerialBus lookup routines with the existing code. Signed-off-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 99 ++++++++++++++++++++++++++++++++++++++++++++------ include/linux/i2c.h | 9 +++++ 2 files changed, 97 insertions(+), 11 deletions(-) (limited to 'include/linux/i2c.h') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d4b2f66d8994..05794423e01f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -107,6 +107,9 @@ struct i2c_acpi_lookup { struct i2c_board_info *info; acpi_handle adapter_handle; acpi_handle device_handle; + acpi_handle search_handle; + u32 speed; + u32 min_speed; }; static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) @@ -130,19 +133,18 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) return 1; info->addr = sb->slave_address; + lookup->speed = sb->connection_speed; if (sb->access_mode == ACPI_I2C_10BIT_MODE) info->flags |= I2C_CLIENT_TEN; return 1; } -static int i2c_acpi_get_info(struct acpi_device *adev, - struct i2c_board_info *info, - acpi_handle *adapter_handle) +static int i2c_acpi_do_lookup(struct acpi_device *adev, + struct i2c_acpi_lookup *lookup) { + struct i2c_board_info *info = lookup->info; struct list_head resource_list; - struct resource_entry *entry; - struct i2c_acpi_lookup lookup; int ret; if (acpi_bus_get_status(adev) || !adev->status.present || @@ -150,24 +152,41 @@ static int i2c_acpi_get_info(struct acpi_device *adev, return -EINVAL; memset(info, 0, sizeof(*info)); - info->fwnode = acpi_fwnode_handle(adev); - - memset(&lookup, 0, sizeof(lookup)); - lookup.device_handle = acpi_device_handle(adev); - lookup.info = info; + lookup->device_handle = acpi_device_handle(adev); /* Look up for I2cSerialBus resource */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - i2c_acpi_fill_info, &lookup); + i2c_acpi_fill_info, lookup); acpi_dev_free_resource_list(&resource_list); if (ret < 0 || !info->addr) return -EINVAL; + return 0; +} + +static int i2c_acpi_get_info(struct acpi_device *adev, + struct i2c_board_info *info, + acpi_handle *adapter_handle) +{ + struct list_head resource_list; + struct resource_entry *entry; + struct i2c_acpi_lookup lookup; + int ret; + + memset(&lookup, 0, sizeof(lookup)); + lookup.info = info; + + ret = i2c_acpi_do_lookup(adev, &lookup); + if (ret) + return ret; + + info->fwnode = acpi_fwnode_handle(adev); *adapter_handle = lookup.adapter_handle; /* Then fill IRQ number if any */ + INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); if (ret < 0) return -EINVAL; @@ -248,6 +267,64 @@ static void i2c_acpi_register_devices(struct i2c_adapter *adap) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } +static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct i2c_acpi_lookup *lookup = data; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (i2c_acpi_do_lookup(adev, lookup)) + return AE_OK; + + if (lookup->search_handle != lookup->adapter_handle) + return AE_OK; + + if (lookup->speed <= lookup->min_speed) + lookup->min_speed = lookup->speed; + + return AE_OK; +} + +/** + * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI + * @dev: The device owning the bus + * + * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves + * devices connected to this bus and use the speed of slowest device. + * + * Returns the speed in Hz or zero + */ +u32 i2c_acpi_find_bus_speed(struct device *dev) +{ + struct i2c_acpi_lookup lookup; + struct i2c_board_info dummy; + acpi_status status; + + if (!has_acpi_companion(dev)) + return 0; + + memset(&lookup, 0, sizeof(lookup)); + lookup.search_handle = ACPI_HANDLE(dev); + lookup.min_speed = UINT_MAX; + lookup.info = &dummy; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + I2C_ACPI_MAX_SCAN_DEPTH, + i2c_acpi_lookup_speed, NULL, + &lookup, NULL); + + if (ACPI_FAILURE(status)) { + dev_warn(dev, "unable to find I2C bus speed from ACPI\n"); + return 0; + } + + return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0; +} +EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); + static int i2c_acpi_match_adapter(struct device *dev, void *data) { struct i2c_adapter *adapter = i2c_verify_adapter(dev); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index c1f60a345db7..5b4a3cbe5d7d 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -780,4 +780,13 @@ static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node } #endif /* CONFIG_OF */ +#if IS_ENABLED(CONFIG_ACPI) +u32 i2c_acpi_find_bus_speed(struct device *dev); +#else +static inline u32 i2c_acpi_find_bus_speed(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_ACPI */ + #endif /* _LINUX_I2C_H */ -- cgit v1.2.3 From d1ed7985b9a6b85ea38a330108c51ec83381c01b Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Thu, 25 Aug 2016 23:07:01 +0200 Subject: i2c: move locking operations to their own struct This makes it trivial to constify them, so do that. Signed-off-by: Peter Rosin Acked-by: Daniel Vetter Signed-off-by: Wolfram Sang --- drivers/gpu/drm/drm_dp_helper.c | 10 +++++++--- drivers/i2c/i2c-core.c | 13 ++++++++----- drivers/i2c/i2c-mux.c | 25 ++++++++++++++++--------- include/linux/i2c.h | 25 ++++++++++++++++++------- 4 files changed, 49 insertions(+), 24 deletions(-) (limited to 'include/linux/i2c.h') diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index eae5ef963cb7..2bd064493ae7 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -790,6 +790,12 @@ static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags) mutex_unlock(&i2c_to_aux(i2c)->hw_mutex); } +static const struct i2c_lock_operations drm_dp_i2c_lock_ops = { + .lock_bus = lock_bus, + .trylock_bus = trylock_bus, + .unlock_bus = unlock_bus, +}; + /** * drm_dp_aux_init() - minimally initialise an aux channel * @aux: DisplayPort AUX channel @@ -807,9 +813,7 @@ void drm_dp_aux_init(struct drm_dp_aux *aux) aux->ddc.algo_data = aux; aux->ddc.retries = 3; - aux->ddc.lock_bus = lock_bus; - aux->ddc.trylock_bus = trylock_bus; - aux->ddc.unlock_bus = unlock_bus; + aux->ddc.lock_ops = &drm_dp_i2c_lock_ops; } EXPORT_SYMBOL(drm_dp_aux_init); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 05794423e01f..0722713e5910 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1768,6 +1768,12 @@ static int __process_new_adapter(struct device_driver *d, void *data) return i2c_do_add_adapter(to_i2c_driver(d), data); } +static const struct i2c_lock_operations i2c_adapter_lock_ops = { + .lock_bus = i2c_adapter_lock_bus, + .trylock_bus = i2c_adapter_trylock_bus, + .unlock_bus = i2c_adapter_unlock_bus, +}; + static int i2c_register_adapter(struct i2c_adapter *adap) { int res = -EINVAL; @@ -1787,11 +1793,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) goto out_list; } - if (!adap->lock_bus) { - adap->lock_bus = i2c_adapter_lock_bus; - adap->trylock_bus = i2c_adapter_trylock_bus; - adap->unlock_bus = i2c_adapter_unlock_bus; - } + if (!adap->lock_ops) + adap->lock_ops = &i2c_adapter_lock_ops; rt_mutex_init(&adap->bus_lock); rt_mutex_init(&adap->mux_lock); diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 90f59c088750..83768e85a919 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -267,6 +267,18 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, } EXPORT_SYMBOL_GPL(i2c_mux_alloc); +static const struct i2c_lock_operations i2c_mux_lock_ops = { + .lock_bus = i2c_mux_lock_bus, + .trylock_bus = i2c_mux_trylock_bus, + .unlock_bus = i2c_mux_unlock_bus, +}; + +static const struct i2c_lock_operations i2c_parent_lock_ops = { + .lock_bus = i2c_parent_lock_bus, + .trylock_bus = i2c_parent_trylock_bus, + .unlock_bus = i2c_parent_unlock_bus, +}; + int i2c_mux_add_adapter(struct i2c_mux_core *muxc, u32 force_nr, u32 chan_id, unsigned int class) @@ -316,15 +328,10 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, priv->adap.retries = parent->retries; priv->adap.timeout = parent->timeout; priv->adap.quirks = parent->quirks; - if (muxc->mux_locked) { - priv->adap.lock_bus = i2c_mux_lock_bus; - priv->adap.trylock_bus = i2c_mux_trylock_bus; - priv->adap.unlock_bus = i2c_mux_unlock_bus; - } else { - priv->adap.lock_bus = i2c_parent_lock_bus; - priv->adap.trylock_bus = i2c_parent_trylock_bus; - priv->adap.unlock_bus = i2c_parent_unlock_bus; - } + if (muxc->mux_locked) + priv->adap.lock_ops = &i2c_mux_lock_ops; + else + priv->adap.lock_ops = &i2c_parent_lock_ops; /* Sanity check on class */ if (i2c_mux_parent_classes(parent) & class) diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 5b4a3cbe5d7d..4a4099d3a4b9 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -426,6 +426,20 @@ struct i2c_algorithm { #endif }; +/** + * struct i2c_lock_operations - represent I2C locking operations + * @lock_bus: Get exclusive access to an I2C bus segment + * @trylock_bus: Try to get exclusive access to an I2C bus segment + * @unlock_bus: Release exclusive access to an I2C bus segment + * + * The main operations are wrapped by i2c_lock_bus and i2c_unlock_bus. + */ +struct i2c_lock_operations { + void (*lock_bus)(struct i2c_adapter *, unsigned int flags); + int (*trylock_bus)(struct i2c_adapter *, unsigned int flags); + void (*unlock_bus)(struct i2c_adapter *, unsigned int flags); +}; + /** * struct i2c_timings - I2C timing information * @bus_freq_hz: the bus frequency in Hz @@ -536,6 +550,7 @@ struct i2c_adapter { void *algo_data; /* data fields that are valid for all devices */ + const struct i2c_lock_operations *lock_ops; struct rt_mutex bus_lock; struct rt_mutex mux_lock; @@ -552,10 +567,6 @@ struct i2c_adapter { struct i2c_bus_recovery_info *bus_recovery_info; const struct i2c_adapter_quirks *quirks; - - void (*lock_bus)(struct i2c_adapter *, unsigned int flags); - int (*trylock_bus)(struct i2c_adapter *, unsigned int flags); - void (*unlock_bus)(struct i2c_adapter *, unsigned int flags); }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) @@ -597,7 +608,7 @@ int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *)); static inline void i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { - adapter->lock_bus(adapter, flags); + adapter->lock_ops->lock_bus(adapter, flags); } /** @@ -611,7 +622,7 @@ i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags) static inline int i2c_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) { - return adapter->trylock_bus(adapter, flags); + return adapter->lock_ops->trylock_bus(adapter, flags); } /** @@ -623,7 +634,7 @@ i2c_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) static inline void i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) { - adapter->unlock_bus(adapter, flags); + adapter->lock_ops->unlock_bus(adapter, flags); } static inline void -- cgit v1.2.3 From 8dd1fe1594a712eb326e1607c694fbd1baf85f4b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 16 Sep 2016 18:02:42 +0200 Subject: i2c: export i2c_adapter_depth() For crazy setups in which an i2c gpio expander is behind an i2c gpio multiplexer controlled by a gpio provided a second expander using the same device driver we need to explicitly tell lockdep how to handle nested locking. Export i2c_adapter_depth() as public API to be reused outside of i2c core code. Signed-off-by: Bartosz Golaszewski Acked-by: Peter Rosin Acked-by: Peter Zijlstra (Intel) Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 9 ++------- include/linux/i2c.h | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'include/linux/i2c.h') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index cdbbd9bdb7b4..981de21ab814 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1426,13 +1426,7 @@ static void i2c_adapter_dev_release(struct device *dev) complete(&adap->dev_released); } -/* - * This function is only needed for mutex_lock_nested, so it is never - * called unless locking correctness checking is enabled. Thus we - * make it inline to avoid a compiler warning. That's what gcc ends up - * doing anyway. - */ -static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) +unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) { unsigned int depth = 0; @@ -1441,6 +1435,7 @@ static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) return depth; } +EXPORT_SYMBOL_GPL(i2c_adapter_depth); /* * Let users instantiate I2C devices through sysfs. This can be used when diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 4a4099d3a4b9..6422eef428c4 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -698,6 +698,7 @@ extern void i2c_clients_command(struct i2c_adapter *adap, extern struct i2c_adapter *i2c_get_adapter(int nr); extern void i2c_put_adapter(struct i2c_adapter *adap); +extern unsigned int i2c_adapter_depth(struct i2c_adapter *adapter); void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults); -- cgit v1.2.3