Merge branches 'pm-domains', 'powercap' and 'pm-tools'
[cascardo/linux.git] / drivers / i2c / i2c-core.c
index f43b4e1..39d25a8 100644 (file)
@@ -24,6 +24,7 @@
    (c) 2013  Wolfram Sang <wsa@the-dreams.de>
    I2C ACPI code Copyright (C) 2014 Intel Corp
    Author: Lan Tianyu <tianyu.lan@intel.com>
+   I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com>
  */
 
 #include <linux/module.h>
@@ -49,6 +50,7 @@
 #include <linux/acpi.h>
 #include <linux/jump_label.h>
 #include <asm/uaccess.h>
+#include <linux/err.h>
 
 #include "i2c-core.h"
 
@@ -260,7 +262,7 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command,
        struct acpi_resource *ares;
        u32 accessor_type = function >> 16;
        u8 action = function & ACPI_IO_MASK;
-       acpi_status ret = AE_OK;
+       acpi_status ret;
        int status;
 
        ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
@@ -403,6 +405,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
                return -ENOMEM;
        }
 
+       acpi_walk_dep_device_list(handle);
        return 0;
 }
 
@@ -626,6 +629,17 @@ static int i2c_device_probe(struct device *dev)
        if (!client)
                return 0;
 
+       if (!client->irq && dev->of_node) {
+               int irq = of_irq_get(dev->of_node, 0);
+
+               if (irq == -EPROBE_DEFER)
+                       return irq;
+               if (irq < 0)
+                       irq = 0;
+
+               client->irq = irq;
+       }
+
        driver = to_i2c_driver(dev->driver);
        if (!driver->probe || !driver->id_table)
                return -ENODEV;
@@ -1368,63 +1382,67 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
 /* OF support code */
 
 #if IS_ENABLED(CONFIG_OF)
-static void of_i2c_register_devices(struct i2c_adapter *adap)
+static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
+                                                struct device_node *node)
 {
-       void *result;
-       struct device_node *node;
+       struct i2c_client *result;
+       struct i2c_board_info info = {};
+       struct dev_archdata dev_ad = {};
+       const __be32 *addr;
+       int len;
 
-       /* Only register child devices if the adapter has a node pointer set */
-       if (!adap->dev.of_node)
-               return;
+       dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
 
-       dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
+       if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
+               dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
+                       node->full_name);
+               return ERR_PTR(-EINVAL);
+       }
 
-       for_each_available_child_of_node(adap->dev.of_node, node) {
-               struct i2c_board_info info = {};
-               struct dev_archdata dev_ad = {};
-               const __be32 *addr;
-               int len;
+       addr = of_get_property(node, "reg", &len);
+       if (!addr || (len < sizeof(int))) {
+               dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
+                       node->full_name);
+               return ERR_PTR(-EINVAL);
+       }
 
-               dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
+       info.addr = be32_to_cpup(addr);
+       if (info.addr > (1 << 10) - 1) {
+               dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
+                       info.addr, node->full_name);
+               return ERR_PTR(-EINVAL);
+       }
 
-               if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
-                       dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
-                               node->full_name);
-                       continue;
-               }
+       info.of_node = of_node_get(node);
+       info.archdata = &dev_ad;
 
-               addr = of_get_property(node, "reg", &len);
-               if (!addr || (len < sizeof(int))) {
-                       dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
-                               node->full_name);
-                       continue;
-               }
+       if (of_get_property(node, "wakeup-source", NULL))
+               info.flags |= I2C_CLIENT_WAKE;
 
-               info.addr = be32_to_cpup(addr);
-               if (info.addr > (1 << 10) - 1) {
-                       dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
-                               info.addr, node->full_name);
-                       continue;
-               }
+       request_module("%s%s", I2C_MODULE_PREFIX, info.type);
 
-               info.irq = irq_of_parse_and_map(node, 0);
-               info.of_node = of_node_get(node);
-               info.archdata = &dev_ad;
+       result = i2c_new_device(adap, &info);
+       if (result == NULL) {
+               dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
+                       node->full_name);
+               of_node_put(node);
+               return ERR_PTR(-EINVAL);
+       }
+       return result;
+}
 
-               if (of_get_property(node, "wakeup-source", NULL))
-                       info.flags |= I2C_CLIENT_WAKE;
+static void of_i2c_register_devices(struct i2c_adapter *adap)
+{
+       struct device_node *node;
 
-               request_module("%s%s", I2C_MODULE_PREFIX, info.type);
+       /* Only register child devices if the adapter has a node pointer set */
+       if (!adap->dev.of_node)
+               return;
 
-               result = i2c_new_device(adap, &info);
-               if (result == NULL) {
-                       dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
-                               node->full_name);
-                       of_node_put(node);
-                       irq_dispose_mapping(info.irq);
-                       continue;
-               }
-       }
+       dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
+
+       for_each_available_child_of_node(adap->dev.of_node, node)
+               of_i2c_register_device(adap, node);
 }
 
 static int of_dev_node_match(struct device *dev, void *data)
@@ -1944,6 +1962,52 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
 }
 EXPORT_SYMBOL(i2c_clients_command);
 
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
+                        void *arg)
+{
+       struct of_reconfig_data *rd = arg;
+       struct i2c_adapter *adap;
+       struct i2c_client *client;
+
+       switch (of_reconfig_get_state_change(action, rd)) {
+       case OF_RECONFIG_CHANGE_ADD:
+               adap = of_find_i2c_adapter_by_node(rd->dn->parent);
+               if (adap == NULL)
+                       return NOTIFY_OK;       /* not for us */
+
+               client = of_i2c_register_device(adap, rd->dn);
+               put_device(&adap->dev);
+
+               if (IS_ERR(client)) {
+                       pr_err("%s: failed to create for '%s'\n",
+                                       __func__, rd->dn->full_name);
+                       return notifier_from_errno(PTR_ERR(client));
+               }
+               break;
+       case OF_RECONFIG_CHANGE_REMOVE:
+               /* find our device by node */
+               client = of_find_i2c_device_by_node(rd->dn);
+               if (client == NULL)
+                       return NOTIFY_OK;       /* no? not meant for us */
+
+               /* unregister takes one ref away */
+               i2c_unregister_device(client);
+
+               /* and put the reference of the find */
+               put_device(&client->dev);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+static struct notifier_block i2c_of_notifier = {
+       .notifier_call = of_i2c_notify,
+};
+#else
+extern struct notifier_block i2c_of_notifier;
+#endif /* CONFIG_OF_DYNAMIC */
+
 static int __init i2c_init(void)
 {
        int retval;
@@ -1961,6 +2025,10 @@ static int __init i2c_init(void)
        retval = i2c_add_driver(&dummy_driver);
        if (retval)
                goto class_err;
+
+       if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+               WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier));
+
        return 0;
 
 class_err:
@@ -1974,6 +2042,8 @@ bus_err:
 
 static void __exit i2c_exit(void)
 {
+       if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+               WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier));
        i2c_del_driver(&dummy_driver);
 #ifdef CONFIG_I2C_COMPAT
        class_compat_unregister(i2c_adapter_compat_class);
@@ -2902,6 +2972,54 @@ trace:
 }
 EXPORT_SYMBOL(i2c_smbus_xfer);
 
+int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
+{
+       int ret;
+
+       if (!client || !slave_cb)
+               return -EINVAL;
+
+       if (!(client->flags & I2C_CLIENT_TEN)) {
+               /* Enforce stricter address checking */
+               ret = i2c_check_addr_validity(client->addr);
+               if (ret)
+                       return ret;
+       }
+
+       if (!client->adapter->algo->reg_slave)
+               return -EOPNOTSUPP;
+
+       client->slave_cb = slave_cb;
+
+       i2c_lock_adapter(client->adapter);
+       ret = client->adapter->algo->reg_slave(client);
+       i2c_unlock_adapter(client->adapter);
+
+       if (ret)
+               client->slave_cb = NULL;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i2c_slave_register);
+
+int i2c_slave_unregister(struct i2c_client *client)
+{
+       int ret;
+
+       if (!client->adapter->algo->unreg_slave)
+               return -EOPNOTSUPP;
+
+       i2c_lock_adapter(client->adapter);
+       ret = client->adapter->algo->unreg_slave(client);
+       i2c_unlock_adapter(client->adapter);
+
+       if (ret == 0)
+               client->slave_cb = NULL;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i2c_slave_unregister);
+
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus main module");
 MODULE_LICENSE("GPL");