diff options
-rw-r--r-- | drivers/i2c/i2c-core.c | 49 | ||||
-rw-r--r-- | include/linux/i2c.h | 29 |
2 files changed, 78 insertions, 0 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 3105bd273f70..c09d06bf4d9b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -24,6 +24,7 @@ | |||
24 | (c) 2013 Wolfram Sang <wsa@the-dreams.de> | 24 | (c) 2013 Wolfram Sang <wsa@the-dreams.de> |
25 | I2C ACPI code Copyright (C) 2014 Intel Corp | 25 | I2C ACPI code Copyright (C) 2014 Intel Corp |
26 | Author: Lan Tianyu <tianyu.lan@intel.com> | 26 | Author: Lan Tianyu <tianyu.lan@intel.com> |
27 | I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com> | ||
27 | */ | 28 | */ |
28 | 29 | ||
29 | #include <linux/module.h> | 30 | #include <linux/module.h> |
@@ -2911,6 +2912,54 @@ trace: | |||
2911 | } | 2912 | } |
2912 | EXPORT_SYMBOL(i2c_smbus_xfer); | 2913 | EXPORT_SYMBOL(i2c_smbus_xfer); |
2913 | 2914 | ||
2915 | int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) | ||
2916 | { | ||
2917 | int ret; | ||
2918 | |||
2919 | if (!client || !slave_cb) | ||
2920 | return -EINVAL; | ||
2921 | |||
2922 | if (!(client->flags & I2C_CLIENT_TEN)) { | ||
2923 | /* Enforce stricter address checking */ | ||
2924 | ret = i2c_check_addr_validity(client->addr); | ||
2925 | if (ret) | ||
2926 | return ret; | ||
2927 | } | ||
2928 | |||
2929 | if (!client->adapter->algo->reg_slave) | ||
2930 | return -EOPNOTSUPP; | ||
2931 | |||
2932 | client->slave_cb = slave_cb; | ||
2933 | |||
2934 | i2c_lock_adapter(client->adapter); | ||
2935 | ret = client->adapter->algo->reg_slave(client); | ||
2936 | i2c_unlock_adapter(client->adapter); | ||
2937 | |||
2938 | if (ret) | ||
2939 | client->slave_cb = NULL; | ||
2940 | |||
2941 | return ret; | ||
2942 | } | ||
2943 | EXPORT_SYMBOL_GPL(i2c_slave_register); | ||
2944 | |||
2945 | int i2c_slave_unregister(struct i2c_client *client) | ||
2946 | { | ||
2947 | int ret; | ||
2948 | |||
2949 | if (!client->adapter->algo->unreg_slave) | ||
2950 | return -EOPNOTSUPP; | ||
2951 | |||
2952 | i2c_lock_adapter(client->adapter); | ||
2953 | ret = client->adapter->algo->unreg_slave(client); | ||
2954 | i2c_unlock_adapter(client->adapter); | ||
2955 | |||
2956 | if (ret == 0) | ||
2957 | client->slave_cb = NULL; | ||
2958 | |||
2959 | return ret; | ||
2960 | } | ||
2961 | EXPORT_SYMBOL_GPL(i2c_slave_unregister); | ||
2962 | |||
2914 | MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); | 2963 | MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); |
2915 | MODULE_DESCRIPTION("I2C-Bus main module"); | 2964 | MODULE_DESCRIPTION("I2C-Bus main module"); |
2916 | MODULE_LICENSE("GPL"); | 2965 | MODULE_LICENSE("GPL"); |
diff --git a/include/linux/i2c.h b/include/linux/i2c.h index b556e0ab946f..a720d9921b47 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h | |||
@@ -46,6 +46,8 @@ struct i2c_client; | |||
46 | struct i2c_driver; | 46 | struct i2c_driver; |
47 | union i2c_smbus_data; | 47 | union i2c_smbus_data; |
48 | struct i2c_board_info; | 48 | struct i2c_board_info; |
49 | enum i2c_slave_event; | ||
50 | typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *); | ||
49 | 51 | ||
50 | struct module; | 52 | struct module; |
51 | 53 | ||
@@ -209,6 +211,8 @@ struct i2c_driver { | |||
209 | * @irq: indicates the IRQ generated by this device (if any) | 211 | * @irq: indicates the IRQ generated by this device (if any) |
210 | * @detected: member of an i2c_driver.clients list or i2c-core's | 212 | * @detected: member of an i2c_driver.clients list or i2c-core's |
211 | * userspace_devices list | 213 | * userspace_devices list |
214 | * @slave_cb: Callback when I2C slave mode of an adapter is used. The adapter | ||
215 | * calls it to pass on slave events to the slave driver. | ||
212 | * | 216 | * |
213 | * An i2c_client identifies a single device (i.e. chip) connected to an | 217 | * An i2c_client identifies a single device (i.e. chip) connected to an |
214 | * i2c bus. The behaviour exposed to Linux is defined by the driver | 218 | * i2c bus. The behaviour exposed to Linux is defined by the driver |
@@ -224,6 +228,7 @@ struct i2c_client { | |||
224 | struct device dev; /* the device structure */ | 228 | struct device dev; /* the device structure */ |
225 | int irq; /* irq issued by device */ | 229 | int irq; /* irq issued by device */ |
226 | struct list_head detected; | 230 | struct list_head detected; |
231 | i2c_slave_cb_t slave_cb; /* callback for slave mode */ | ||
227 | }; | 232 | }; |
228 | #define to_i2c_client(d) container_of(d, struct i2c_client, dev) | 233 | #define to_i2c_client(d) container_of(d, struct i2c_client, dev) |
229 | 234 | ||
@@ -246,6 +251,25 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) | |||
246 | dev_set_drvdata(&dev->dev, data); | 251 | dev_set_drvdata(&dev->dev, data); |
247 | } | 252 | } |
248 | 253 | ||
254 | /* I2C slave support */ | ||
255 | |||
256 | enum i2c_slave_event { | ||
257 | I2C_SLAVE_REQ_READ_START, | ||
258 | I2C_SLAVE_REQ_READ_END, | ||
259 | I2C_SLAVE_REQ_WRITE_START, | ||
260 | I2C_SLAVE_REQ_WRITE_END, | ||
261 | I2C_SLAVE_STOP, | ||
262 | }; | ||
263 | |||
264 | extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb); | ||
265 | extern int i2c_slave_unregister(struct i2c_client *client); | ||
266 | |||
267 | static inline int i2c_slave_event(struct i2c_client *client, | ||
268 | enum i2c_slave_event event, u8 *val) | ||
269 | { | ||
270 | return client->slave_cb(client, event, val); | ||
271 | } | ||
272 | |||
249 | /** | 273 | /** |
250 | * struct i2c_board_info - template for device creation | 274 | * struct i2c_board_info - template for device creation |
251 | * @type: chip type, to initialize i2c_client.name | 275 | * @type: chip type, to initialize i2c_client.name |
@@ -352,6 +376,8 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info, | |||
352 | * into I2C transfers instead. | 376 | * into I2C transfers instead. |
353 | * @functionality: Return the flags that this algorithm/adapter pair supports | 377 | * @functionality: Return the flags that this algorithm/adapter pair supports |
354 | * from the I2C_FUNC_* flags. | 378 | * from the I2C_FUNC_* flags. |
379 | * @reg_slave: Register given client to I2C slave mode of this adapter | ||
380 | * @unreg_slave: Unregister given client from I2C slave mode of this adapter | ||
355 | * | 381 | * |
356 | * The following structs are for those who like to implement new bus drivers: | 382 | * The following structs are for those who like to implement new bus drivers: |
357 | * i2c_algorithm is the interface to a class of hardware solutions which can | 383 | * i2c_algorithm is the interface to a class of hardware solutions which can |
@@ -377,6 +403,9 @@ struct i2c_algorithm { | |||
377 | 403 | ||
378 | /* To determine what the adapter supports */ | 404 | /* To determine what the adapter supports */ |
379 | u32 (*functionality) (struct i2c_adapter *); | 405 | u32 (*functionality) (struct i2c_adapter *); |
406 | |||
407 | int (*reg_slave)(struct i2c_client *client); | ||
408 | int (*unreg_slave)(struct i2c_client *client); | ||
380 | }; | 409 | }; |
381 | 410 | ||
382 | /** | 411 | /** |