]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/i2c/i2c-core.c
staging: board: disable as it breaks the build
[karo-tx-linux.git] / drivers / i2c / i2c-core.c
index 5fb80b8962a2ad7d8e78dcee01df68cb639d3602..7c7f4b856badaea86063483e3b37c49485e411d3 100644 (file)
 #include <linux/rwsem.h>
 #include <linux/pm_runtime.h>
 #include <linux/acpi.h>
+#include <linux/jump_label.h>
 #include <asm/uaccess.h>
 
 #include "i2c-core.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/i2c.h>
 
 /* core_lock protects i2c_adapter_idr, and guarantees
    that device detection, deletion of detected devices, and attach_adapter
@@ -62,6 +65,18 @@ static DEFINE_IDR(i2c_adapter_idr);
 static struct device_type i2c_client_type;
 static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
 
+static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE;
+
+void i2c_transfer_trace_reg(void)
+{
+       static_key_slow_inc(&i2c_trace_msg);
+}
+
+void i2c_transfer_trace_unreg(void)
+{
+       static_key_slow_dec(&i2c_trace_msg);
+}
+
 /* ------------------------------------------------------------------------- */
 
 static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
@@ -1686,6 +1701,7 @@ static void __exit i2c_exit(void)
        class_compat_unregister(i2c_adapter_compat_class);
 #endif
        bus_unregister(&i2c_bus_type);
+       tracepoint_synchronize_unregister();
 }
 
 /* We must initialize early, because some subsystems register i2c drivers
@@ -1716,6 +1732,19 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        unsigned long orig_jiffies;
        int ret, try;
 
+       /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
+        * enabled.  This is an efficient way of keeping the for-loop from
+        * being executed when not needed.
+        */
+       if (static_key_false(&i2c_trace_msg)) {
+               int i;
+               for (i = 0; i < num; i++)
+                       if (msgs[i].flags & I2C_M_RD)
+                               trace_i2c_read(adap, &msgs[i], i);
+                       else
+                               trace_i2c_write(adap, &msgs[i], i);
+       }
+
        /* Retry automatically on arbitration loss */
        orig_jiffies = jiffies;
        for (ret = 0, try = 0; try <= adap->retries; try++) {
@@ -1726,6 +1755,14 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        break;
        }
 
+       if (static_key_false(&i2c_trace_msg)) {
+               int i;
+               for (i = 0; i < ret; i++)
+                       if (msgs[i].flags & I2C_M_RD)
+                               trace_i2c_reply(adap, &msgs[i], i);
+               trace_i2c_result(adap, i, ret);
+       }
+
        return ret;
 }
 EXPORT_SYMBOL(__i2c_transfer);
@@ -1941,6 +1978,13 @@ static int i2c_detect_address(struct i2c_client *temp_client,
                struct i2c_client *client;
 
                /* Detection succeeded, instantiate the device */
+               if (adapter->class & I2C_CLASS_DEPRECATED)
+                       dev_warn(&adapter->dev,
+                               "This adapter will soon drop class based instantiation of devices. "
+                               "Please make sure client 0x%02x gets instantiated by other means. "
+                               "Check 'Documentation/i2c/instantiating-devices' for details.\n",
+                               info.addr);
+
                dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
                        info.type, info.addr);
                client = i2c_new_device(adapter, &info);
@@ -2521,6 +2565,14 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
        int try;
        s32 res;
 
+       /* If enabled, the following two tracepoints are conditional on
+        * read_write and protocol.
+        */
+       trace_smbus_write(adapter, addr, flags, read_write,
+                         command, protocol, data);
+       trace_smbus_read(adapter, addr, flags, read_write,
+                        command, protocol);
+
        flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
 
        if (adapter->algo->smbus_xfer) {
@@ -2541,15 +2593,24 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
                i2c_unlock_adapter(adapter);
 
                if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
-                       return res;
+                       goto trace;
                /*
                 * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't
                 * implement native support for the SMBus operation.
                 */
        }
 
-       return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
-                                      command, protocol, data);
+       res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
+                                     command, protocol, data);
+
+trace:
+       /* If enabled, the reply tracepoint is conditional on read_write. */
+       trace_smbus_reply(adapter, addr, flags, read_write,
+                         command, protocol, data);
+       trace_smbus_result(adapter, addr, flags, read_write,
+                          command, protocol, res);
+
+       return res;
 }
 EXPORT_SYMBOL(i2c_smbus_xfer);