diff options
Diffstat (limited to 'drivers/i2c/i2c-core.c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 64 |
1 files changed, 61 insertions, 3 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 229a89e84b0f..39d25a8cb1ad 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> |
@@ -261,7 +262,7 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, | |||
261 | struct acpi_resource *ares; | 262 | struct acpi_resource *ares; |
262 | u32 accessor_type = function >> 16; | 263 | u32 accessor_type = function >> 16; |
263 | u8 action = function & ACPI_IO_MASK; | 264 | u8 action = function & ACPI_IO_MASK; |
264 | acpi_status ret = AE_OK; | 265 | acpi_status ret; |
265 | int status; | 266 | int status; |
266 | 267 | ||
267 | ret = acpi_buffer_to_resource(info->connection, info->length, &ares); | 268 | ret = acpi_buffer_to_resource(info->connection, info->length, &ares); |
@@ -628,6 +629,17 @@ static int i2c_device_probe(struct device *dev) | |||
628 | if (!client) | 629 | if (!client) |
629 | return 0; | 630 | return 0; |
630 | 631 | ||
632 | if (!client->irq && dev->of_node) { | ||
633 | int irq = of_irq_get(dev->of_node, 0); | ||
634 | |||
635 | if (irq == -EPROBE_DEFER) | ||
636 | return irq; | ||
637 | if (irq < 0) | ||
638 | irq = 0; | ||
639 | |||
640 | client->irq = irq; | ||
641 | } | ||
642 | |||
631 | driver = to_i2c_driver(dev->driver); | 643 | driver = to_i2c_driver(dev->driver); |
632 | if (!driver->probe || !driver->id_table) | 644 | if (!driver->probe || !driver->id_table) |
633 | return -ENODEV; | 645 | return -ENODEV; |
@@ -1401,7 +1413,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, | |||
1401 | return ERR_PTR(-EINVAL); | 1413 | return ERR_PTR(-EINVAL); |
1402 | } | 1414 | } |
1403 | 1415 | ||
1404 | info.irq = irq_of_parse_and_map(node, 0); | ||
1405 | info.of_node = of_node_get(node); | 1416 | info.of_node = of_node_get(node); |
1406 | info.archdata = &dev_ad; | 1417 | info.archdata = &dev_ad; |
1407 | 1418 | ||
@@ -1415,7 +1426,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, | |||
1415 | dev_err(&adap->dev, "of_i2c: Failure registering %s\n", | 1426 | dev_err(&adap->dev, "of_i2c: Failure registering %s\n", |
1416 | node->full_name); | 1427 | node->full_name); |
1417 | of_node_put(node); | 1428 | of_node_put(node); |
1418 | irq_dispose_mapping(info.irq); | ||
1419 | return ERR_PTR(-EINVAL); | 1429 | return ERR_PTR(-EINVAL); |
1420 | } | 1430 | } |
1421 | return result; | 1431 | return result; |
@@ -2962,6 +2972,54 @@ trace: | |||
2962 | } | 2972 | } |
2963 | EXPORT_SYMBOL(i2c_smbus_xfer); | 2973 | EXPORT_SYMBOL(i2c_smbus_xfer); |
2964 | 2974 | ||
2975 | int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) | ||
2976 | { | ||
2977 | int ret; | ||
2978 | |||
2979 | if (!client || !slave_cb) | ||
2980 | return -EINVAL; | ||
2981 | |||
2982 | if (!(client->flags & I2C_CLIENT_TEN)) { | ||
2983 | /* Enforce stricter address checking */ | ||
2984 | ret = i2c_check_addr_validity(client->addr); | ||
2985 | if (ret) | ||
2986 | return ret; | ||
2987 | } | ||
2988 | |||
2989 | if (!client->adapter->algo->reg_slave) | ||
2990 | return -EOPNOTSUPP; | ||
2991 | |||
2992 | client->slave_cb = slave_cb; | ||
2993 | |||
2994 | i2c_lock_adapter(client->adapter); | ||
2995 | ret = client->adapter->algo->reg_slave(client); | ||
2996 | i2c_unlock_adapter(client->adapter); | ||
2997 | |||
2998 | if (ret) | ||
2999 | client->slave_cb = NULL; | ||
3000 | |||
3001 | return ret; | ||
3002 | } | ||
3003 | EXPORT_SYMBOL_GPL(i2c_slave_register); | ||
3004 | |||
3005 | int i2c_slave_unregister(struct i2c_client *client) | ||
3006 | { | ||
3007 | int ret; | ||
3008 | |||
3009 | if (!client->adapter->algo->unreg_slave) | ||
3010 | return -EOPNOTSUPP; | ||
3011 | |||
3012 | i2c_lock_adapter(client->adapter); | ||
3013 | ret = client->adapter->algo->unreg_slave(client); | ||
3014 | i2c_unlock_adapter(client->adapter); | ||
3015 | |||
3016 | if (ret == 0) | ||
3017 | client->slave_cb = NULL; | ||
3018 | |||
3019 | return ret; | ||
3020 | } | ||
3021 | EXPORT_SYMBOL_GPL(i2c_slave_unregister); | ||
3022 | |||
2965 | MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); | 3023 | MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); |
2966 | MODULE_DESCRIPTION("I2C-Bus main module"); | 3024 | MODULE_DESCRIPTION("I2C-Bus main module"); |
2967 | MODULE_LICENSE("GPL"); | 3025 | MODULE_LICENSE("GPL"); |