Thomas Gleixner | c942fdd | 2019-05-27 08:55:06 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
David Brownell | 9c1600e | 2007-05-01 23:26:31 +0200 | [diff] [blame] | 2 | /* |
| 3 | * i2c-core.h - interfaces internal to the I2C framework |
David Brownell | 9c1600e | 2007-05-01 23:26:31 +0200 | [diff] [blame] | 4 | */ |
| 5 | |
Rodolfo Giometti | f18c41d | 2009-06-19 16:58:20 +0200 | [diff] [blame] | 6 | #include <linux/rwsem.h> |
| 7 | |
David Brownell | 9c1600e | 2007-05-01 23:26:31 +0200 | [diff] [blame] | 8 | struct i2c_devinfo { |
| 9 | struct list_head list; |
| 10 | int busnum; |
| 11 | struct i2c_board_info board_info; |
| 12 | }; |
| 13 | |
| 14 | /* board_lock protects board_list and first_dynamic_bus_num. |
| 15 | * only i2c core components are allowed to use these symbols. |
| 16 | */ |
Rodolfo Giometti | f18c41d | 2009-06-19 16:58:20 +0200 | [diff] [blame] | 17 | extern struct rw_semaphore __i2c_board_lock; |
David Brownell | 9c1600e | 2007-05-01 23:26:31 +0200 | [diff] [blame] | 18 | extern struct list_head __i2c_board_list; |
| 19 | extern int __i2c_first_dynamic_bus_num; |
| 20 | |
Wolfram Sang | e4991ec | 2017-05-23 11:14:17 +0200 | [diff] [blame] | 21 | int i2c_check_7bit_addr_validity_strict(unsigned short addr); |
Charles Keepax | 1d7534b | 2019-06-27 10:24:06 +0100 | [diff] [blame] | 22 | int i2c_dev_irq_from_resources(const struct resource *resources, |
| 23 | unsigned int num_resources); |
Wolfram Sang | 5bf4fa7 | 2017-05-23 11:50:58 +0200 | [diff] [blame] | 24 | |
Wolfram Sang | bae1d3a | 2019-04-03 14:40:08 +0200 | [diff] [blame] | 25 | /* |
| 26 | * We only allow atomic transfers for very late communication, e.g. to send |
| 27 | * the powerdown command to a PMIC. Atomic transfers are a corner case and not |
| 28 | * for generic use! |
| 29 | */ |
| 30 | static inline bool i2c_in_atomic_xfer_mode(void) |
| 31 | { |
| 32 | return system_state > SYSTEM_RUNNING && irqs_disabled(); |
| 33 | } |
| 34 | |
Wolfram Sang | 83c4221 | 2019-04-03 14:40:09 +0200 | [diff] [blame] | 35 | static inline int __i2c_lock_bus_helper(struct i2c_adapter *adap) |
| 36 | { |
| 37 | int ret = 0; |
| 38 | |
Wolfram Sang | 63b9698 | 2019-04-03 14:40:10 +0200 | [diff] [blame] | 39 | if (i2c_in_atomic_xfer_mode()) { |
| 40 | WARN(!adap->algo->master_xfer_atomic && !adap->algo->smbus_xfer_atomic, |
| 41 | "No atomic I2C transfer handler for '%s'\n", dev_name(&adap->dev)); |
Wolfram Sang | 83c4221 | 2019-04-03 14:40:09 +0200 | [diff] [blame] | 42 | ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT) ? 0 : -EAGAIN; |
Wolfram Sang | 63b9698 | 2019-04-03 14:40:10 +0200 | [diff] [blame] | 43 | } else { |
Wolfram Sang | 83c4221 | 2019-04-03 14:40:09 +0200 | [diff] [blame] | 44 | i2c_lock_bus(adap, I2C_LOCK_SEGMENT); |
Wolfram Sang | 63b9698 | 2019-04-03 14:40:10 +0200 | [diff] [blame] | 45 | } |
Wolfram Sang | 83c4221 | 2019-04-03 14:40:09 +0200 | [diff] [blame] | 46 | |
| 47 | return ret; |
| 48 | } |
| 49 | |
Wolfram Sang | 5d75611 | 2019-04-25 16:19:48 +0200 | [diff] [blame] | 50 | static inline int __i2c_check_suspended(struct i2c_adapter *adap) |
| 51 | { |
| 52 | if (test_bit(I2C_ALF_IS_SUSPENDED, &adap->locked_flags)) { |
| 53 | if (!test_and_set_bit(I2C_ALF_SUSPEND_REPORTED, &adap->locked_flags)) |
| 54 | dev_WARN(&adap->dev, "Transfer while suspended\n"); |
| 55 | return -ESHUTDOWN; |
| 56 | } |
| 57 | |
| 58 | return 0; |
| 59 | } |
| 60 | |
Wolfram Sang | 53f8f7c | 2017-05-23 16:22:23 +0200 | [diff] [blame] | 61 | #ifdef CONFIG_ACPI |
Andy Shevchenko | c64ffff | 2017-07-17 17:13:28 +0300 | [diff] [blame] | 62 | const struct acpi_device_id * |
| 63 | i2c_acpi_match_device(const struct acpi_device_id *matches, |
| 64 | struct i2c_client *client); |
Wolfram Sang | 53f8f7c | 2017-05-23 16:22:23 +0200 | [diff] [blame] | 65 | void i2c_acpi_register_devices(struct i2c_adapter *adap); |
Charles Keepax | 16c9db1 | 2019-06-27 10:24:09 +0100 | [diff] [blame] | 66 | |
| 67 | int i2c_acpi_get_irq(struct i2c_client *client); |
Wolfram Sang | 53f8f7c | 2017-05-23 16:22:23 +0200 | [diff] [blame] | 68 | #else /* CONFIG_ACPI */ |
| 69 | static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } |
Andy Shevchenko | c64ffff | 2017-07-17 17:13:28 +0300 | [diff] [blame] | 70 | static inline const struct acpi_device_id * |
| 71 | i2c_acpi_match_device(const struct acpi_device_id *matches, |
| 72 | struct i2c_client *client) |
| 73 | { |
| 74 | return NULL; |
| 75 | } |
Charles Keepax | 16c9db1 | 2019-06-27 10:24:09 +0100 | [diff] [blame] | 76 | |
| 77 | static inline int i2c_acpi_get_irq(struct i2c_client *client) |
| 78 | { |
| 79 | return 0; |
| 80 | } |
Wolfram Sang | 53f8f7c | 2017-05-23 16:22:23 +0200 | [diff] [blame] | 81 | #endif /* CONFIG_ACPI */ |
| 82 | extern struct notifier_block i2c_acpi_notifier; |
| 83 | |
| 84 | #ifdef CONFIG_ACPI_I2C_OPREGION |
| 85 | int i2c_acpi_install_space_handler(struct i2c_adapter *adapter); |
| 86 | void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter); |
| 87 | #else /* CONFIG_ACPI_I2C_OPREGION */ |
| 88 | static inline int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) { return 0; } |
| 89 | static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { } |
| 90 | #endif /* CONFIG_ACPI_I2C_OPREGION */ |
| 91 | |
Wolfram Sang | 5bf4fa7 | 2017-05-23 11:50:58 +0200 | [diff] [blame] | 92 | #ifdef CONFIG_OF |
| 93 | void of_i2c_register_devices(struct i2c_adapter *adap); |
| 94 | #else |
| 95 | static inline void of_i2c_register_devices(struct i2c_adapter *adap) { } |
| 96 | #endif |
| 97 | extern struct notifier_block i2c_of_notifier; |