/* Retry automatically on arbitration loss */
        orig_jiffies = jiffies;
        for (ret = 0, try = 0; try <= adap->retries; try++) {
-               ret = adap->algo->master_xfer(adap, msgs, num);
+               if (i2c_in_atomic_xfer_mode() && adap->algo->master_xfer_atomic)
+                       ret = adap->algo->master_xfer_atomic(adap, msgs, num);
+               else
+                       ret = adap->algo->master_xfer(adap, msgs, num);
+
                if (ret != -EAGAIN)
                        break;
                if (time_after(jiffies, orig_jiffies + adap->timeout))
 
                     unsigned short flags, char read_write,
                     u8 command, int protocol, union i2c_smbus_data *data)
 {
+       int (*xfer_func)(struct i2c_adapter *adap, u16 addr,
+                        unsigned short flags, char read_write,
+                        u8 command, int size, union i2c_smbus_data *data);
        unsigned long orig_jiffies;
        int try;
        s32 res;
 
        flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
 
-       if (adapter->algo->smbus_xfer) {
+       xfer_func = adapter->algo->smbus_xfer;
+       if (i2c_in_atomic_xfer_mode()) {
+               if (adapter->algo->smbus_xfer_atomic)
+                       xfer_func = adapter->algo->smbus_xfer_atomic;
+               else if (adapter->algo->master_xfer_atomic)
+                       xfer_func = NULL; /* fallback to I2C emulation */
+       }
+
+       if (xfer_func) {
                /* Retry automatically on arbitration loss */
                orig_jiffies = jiffies;
                for (res = 0, try = 0; try <= adapter->retries; try++) {
-                       res = adapter->algo->smbus_xfer(adapter, addr, flags,
-                                                       read_write, command,
-                                                       protocol, data);
+                       res = xfer_func(adapter, addr, flags, read_write,
+                                       command, protocol, data);
                        if (res != -EAGAIN)
                                break;
                        if (time_after(jiffies,
 
  * @master_xfer: Issue a set of i2c transactions to the given I2C adapter
  *   defined by the msgs array, with num messages available to transfer via
  *   the adapter specified by adap.
+ * @master_xfer_atomic: same as @master_xfer. Yet, only using atomic context
+ *   so e.g. PMICs can be accessed very late before shutdown. Optional.
  * @smbus_xfer: Issue smbus transactions to the given I2C adapter. If this
  *   is not present, then the bus layer will try and convert the SMBus calls
  *   into I2C transfers instead.
+ * @smbus_xfer_atomic: same as @smbus_xfer. Yet, only using atomic context
+ *   so e.g. PMICs can be accessed very late before shutdown. Optional.
  * @functionality: Return the flags that this algorithm/adapter pair supports
  *   from the I2C_FUNC_* flags.
  * @reg_slave: Register given client to I2C slave mode of this adapter
  * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
  * to name two of the most common.
  *
- * The return codes from the @master_xfer field should indicate the type of
- * error code that occurred during the transfer, as documented in the kernel
- * Documentation file Documentation/i2c/fault-codes.
+ * The return codes from the @master_xfer{_atomic} fields should indicate the
+ * type of error code that occurred during the transfer, as documented in the
+ * Kernel Documentation file Documentation/i2c/fault-codes.
  */
 struct i2c_algorithm {
        /*
         */
        int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
                           int num);
+       int (*master_xfer_atomic)(struct i2c_adapter *adap,
+                                  struct i2c_msg *msgs, int num);
        int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr,
                          unsigned short flags, char read_write,
                          u8 command, int size, union i2c_smbus_data *data);
+       int (*smbus_xfer_atomic)(struct i2c_adapter *adap, u16 addr,
+                                unsigned short flags, char read_write,
+                                u8 command, int size, union i2c_smbus_data *data);
 
        /* To determine what the adapter supports */
        u32 (*functionality)(struct i2c_adapter *adap);