diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt
index 7326974..6c0e995 100644
--- a/Documentation/scsi/ufs.txt
+++ b/Documentation/scsi/ufs.txt
@@ -17,6 +17,7 @@ Contents
   3.4 SCSI Error handling
 4. UFSHCD User Interface
   4.1 UFS Query IOCTL
+  4.2 UFS Auto-Hibern8 IOCTL
 
 
 1. Overview
@@ -174,6 +175,52 @@ host and device using IOCTL interface.
   This enables user to control some of the UFS specific features inaccessible
   in other way.
 
+4.2 UFS Auto-Hibern8 IOCTL
+
+  This interface enables user to get/set information about UFS Host
+  Auto-Hibern8 feature for capable hosts. You can use following snippet
+  to comunicate with this interface:
+
+	#include <sys/ioctl.h>
+	#include <scsi/ufs/ioctl.h>
+	#include <scsi/ufs/ufshci.h>
+
+	static int handleWrite(int fd, uint8_t scale, uint16_t timer_val)
+	{
+		ufs_ioctl_auto_hibern8_data hibern8_data;
+
+		/* State, that we want to write the data */
+		hibern8_data.write = true;
+
+		/* Timer scale (check <scsi/ufs/ufshci.h>) */
+		hibern8_data.scale = *scale;
+
+		/* Timer value (max. 0x3fff) */
+		hibern8_data.timer_val = *timer_val;
+
+		/* [fd] used here shall be opened UFS device */
+		return ioctl(fd, UFS_IOCTL_AUTO_HIBERN8, &hibern8_data);
+	}
+
+	static int handleRead(int fd, uint8_t *scale, uint16_t *timer_val)
+	{
+		ufs_ioctl_auto_hibern8_data hibern8_data;
+		int error;
+
+		/* State, that we want to read data  */
+		hibern8_data.write = false;
+
+		/* [fd] used here shall be opened UFS device */
+		error = ioctl(fd, UFS_IOCTL_AUTO_HIBERN8, &hibern8_data);
+
+		if (!error) {
+			*scale = hibern8_data.scale;
+			*timer_val = hibern8_data.timer_val;
+		}
+
+		return error;
+	}
+
 
 UFS Specifications can be found at,
 UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf
diff --git a/drivers/scsi/ufs/ufshcd-ioctl.c b/drivers/scsi/ufs/ufshcd-ioctl.c
index ae70bf5..71f4026 100644
--- a/drivers/scsi/ufs/ufshcd-ioctl.c
+++ b/drivers/scsi/ufs/ufshcd-ioctl.c
@@ -273,6 +273,62 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
 	return err;
 }
 
+static int ufshcd_auto_hibern8_ioctl(struct ufs_hba *hba, void __user *buffer)
+{
+	struct ufs_ioctl_auto_hibern8_data *ioctl_data;
+	int err = 0;
+	u32 status = 0;
+
+	if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+		return -ENOTSUPP;
+
+	if (!buffer)
+		return -EINVAL;
+
+	ioctl_data = kzalloc(sizeof(struct ufs_ioctl_auto_hibern8_data),
+				GFP_KERNEL);
+	if (!ioctl_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* extract params from user buffer */
+	if (copy_from_user(ioctl_data, buffer, sizeof(*ioctl_data))) {
+		err = -EFAULT;
+		goto out_release_mem;
+	}
+
+	if (ioctl_data->write) {
+		if (ioctl_data->timer_val > UFSHCD_AHIBERN8_TIMER_MASK ||
+		    (ioctl_data->scale >= UFSHCD_AHIBERN8_SCALE_MAX)) {
+			err = -EINVAL;
+			goto out_release_mem;
+		}
+
+		/* Write valid state to host */
+		ufshcd_setup_auto_hibern8(hba, ioctl_data->scale,
+			ioctl_data->timer_val);
+	} else {
+		status = ufshcd_read_auto_hibern8_state(hba);
+		ioctl_data->scale =
+			(status & UFSHCD_AHIBERN8_SCALE_MASK) >> 10;
+		ioctl_data->timer_val =
+			(status & UFSHCD_AHIBERN8_TIMER_MASK);
+
+		/* Copy state to user */
+		err = copy_to_user(buffer, ioctl_data, sizeof(*ioctl_data));
+	}
+
+out_release_mem:
+	kfree(ioctl_data);
+out:
+	if (err)
+		dev_err(hba->dev, "Auto-Hibern8 request failed (error: %d)",
+			err);
+
+	return err;
+}
+
 /**
  * ufshcd_ioctl - ufs ioctl callback registered in scsi_host
  * @dev: scsi device required for per LUN queries
@@ -281,6 +337,7 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
  *
  * Supported commands:
  * UFS_IOCTL_QUERY
+ * UFS_IOCTL_AUTO_HIBERN8
  */
 int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
 {
@@ -297,6 +354,11 @@ int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
 				buffer);
 		pm_runtime_put_sync(hba->dev);
 		break;
+	case UFS_IOCTL_AUTO_HIBERN8:
+		pm_runtime_get_sync(hba->dev);
+		err = ufshcd_auto_hibern8_ioctl(hba, buffer);
+		pm_runtime_put_sync(hba->dev);
+		break;
 	default:
 		err = -EOPNOTSUPP;
 		break;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9f3a39d..6fcbeb5 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -933,6 +933,30 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
 }
 
 /**
+ * ufshcd_read_auto_hibern8_state - Reads hosts auto-hibern8 feature state
+ * @hba: per adapter instance
+ */
+u32 ufshcd_read_auto_hibern8_state(struct ufs_hba *hba)
+{
+	return ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER);
+}
+
+/**
+ * ufshcd_setup_auto_hibern8 - Sets up hosts auto-hibern8 feature
+ * @hba: per adapter instance
+ * @scale: timer scale (1/10/100us/1/10/100ms)
+ * @timer_val: value to be multipled with scale (idle timeout)
+ */
+void ufshcd_setup_auto_hibern8(struct ufs_hba *hba, u8 scale, u16 timer_val)
+{
+	u32 val = (scale << 10) & UFSHCD_AHIBERN8_SCALE_MASK;
+
+	val |= timer_val & UFSHCD_AHIBERN8_TIMER_MASK;
+
+	ufshcd_writel(hba, val, REG_AUTO_HIBERNATE_IDLE_TIMER);
+}
+
+/**
  * ufshcd_is_devfreq_scaling_required - check if scaling is required or not
  * @hba: per adapter instance
  * @scale_up: True if scaling up and false if scaling down
@@ -5338,6 +5362,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
 static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
 {
 	hba->errors = UFSHCD_ERROR_MASK & intr_status;
+
 	if (hba->errors)
 		ufshcd_check_errors(hba);
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bf8a670..392f702 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -860,6 +860,10 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
 u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun);
 u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id);
 
+/* Expose Auto-Hibern8 API */
+void ufshcd_setup_auto_hibern8(struct ufs_hba *hba, u8 scale, u16 timer_val);
+u32 ufshcd_read_auto_hibern8_state(struct ufs_hba *hba);
+
 /* Wrapper functions for safely calling variant operations */
 static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
 {
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index f60145d..789bbd8 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -36,6 +36,8 @@
 #ifndef _UFSHCI_H
 #define _UFSHCI_H
 
+#include <scsi/ufs/ufshci.h>
+
 enum {
 	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
 	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
@@ -86,6 +88,7 @@ enum {
 enum {
 	MASK_TRANSFER_REQUESTS_SLOTS		= 0x0000001F,
 	MASK_TASK_MANAGEMENT_REQUEST_SLOTS	= 0x00070000,
+	MASK_AUTO_HIBERN8_SUPPORT		= 0x00800000,
 	MASK_64_ADDRESSING_SUPPORT		= 0x01000000,
 	MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT	= 0x02000000,
 	MASK_UIC_DME_TEST_MODE_SUPPORT		= 0x04000000,
@@ -136,9 +139,9 @@ enum {
 #define CONTROLLER_FATAL_ERROR			UFS_BIT(16)
 #define SYSTEM_BUS_FATAL_ERROR			UFS_BIT(17)
 
-#define UFSHCD_UIC_PWR_MASK	(UIC_HIBERNATE_ENTER |\
-				UIC_HIBERNATE_EXIT |\
-				UIC_POWER_MODE)
+#define UFSHCD_UHS_MASK		(UIC_HIBERNATE_EXIT | UIC_HIBERNATE_ENTER)
+
+#define UFSHCD_UIC_PWR_MASK	(UFSHCD_UHS_MASK | UIC_POWER_MODE)
 
 #define UFSHCD_UIC_MASK		(UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
 
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index f128e9e..43f87ad 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -255,7 +255,7 @@ static inline int scsi_is_wlun(u64 lun)
  * Here are some scsi specific ioctl commands which are sometimes useful.
  *
  * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
- * include/uapi/scsi/ufs/ioctl.h defines 0x53A0
+ * include/uapi/scsi/ufs/ioctl.h defines 0x53A0 - 0x53A1
  */
 
 /* Used to obtain PUN and LUN info.  Conflicts with CDROMAUDIOBUFSIZ */
diff --git a/include/uapi/scsi/ufs/Kbuild b/include/uapi/scsi/ufs/Kbuild
index cc3ef20..07a2ce3 100644
--- a/include/uapi/scsi/ufs/Kbuild
+++ b/include/uapi/scsi/ufs/Kbuild
@@ -1,3 +1,4 @@
 # UAPI Header export list
 header-y += ioctl.h
 header-y += ufs.h
+header-y += ufshci.h
diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h
index 1c65505..f3583de 100644
--- a/include/uapi/scsi/ufs/ioctl.h
+++ b/include/uapi/scsi/ufs/ioctl.h
@@ -8,6 +8,7 @@
  *  SCSI_IOCTL_GET_PCI
  */
 #define UFS_IOCTL_QUERY			0x53A0
+#define UFS_IOCTL_AUTO_HIBERN8		0x53A1
 
 /**
  * struct ufs_ioctl_query_data - used to transfer data to and from user via
@@ -58,4 +59,34 @@ struct ufs_ioctl_query_data {
 	__u8 *buffer;
 };
 
+/**
+ * struct ufs_ioctl_auto_hibern8_data - used to hold Auto-Hibern8 feature
+ * configuration
+ *
+ * @write: flag indicating whether config should be written or read
+ * @scale: scale of the timer (length of one tick)
+ * @timer_val: value of the timer to be multipled by scale (0x0000-0x3FFF)
+ *
+ * Received/Submitted: scale, timer_val
+ */
+struct ufs_ioctl_auto_hibern8_data {
+	/*
+	 * This flag indicates whether configuration wirtten in this structure
+	 * should be written, or overwritten by reading currently written
+	 */
+	bool write;
+
+	/*
+	 * Scale of the timer. Prease refer to <uapi/scsi/ufs/ufshci.h> for
+	 * correct values and their meaning.
+	 */
+	__u8 scale;
+
+	/*
+	 * Actual timer value, which will be multipled by the scale.
+	 * Maximal value: 1023. 0 will disable the feature.
+	 */
+	__u16 timer_val;
+};
+
 #endif /* UAPI_UFS_IOCTL_H_ */
diff --git a/include/uapi/scsi/ufs/ufshci.h b/include/uapi/scsi/ufs/ufshci.h
new file mode 100644
index 0000000..c50065b
--- /dev/null
+++ b/include/uapi/scsi/ufs/ufshci.h
@@ -0,0 +1,17 @@
+#ifndef _UAPI_UFSHCI_H
+#define _UAPI_UFSHCI_H
+
+enum {
+	UFSHCD_AHIBERN8_SCALE_1US	= 0,
+	UFSHCD_AHIBERN8_SCALE_10US	= 1,
+	UFSHCD_AHIBERN8_SCALE_100US	= 2,
+	UFSHCD_AHIBERN8_SCALE_1MS	= 3,
+	UFSHCD_AHIBERN8_SCALE_10MS	= 4,
+	UFSHCD_AHIBERN8_SCALE_100MS	= 5,
+	UFSHCD_AHIBERN8_SCALE_MAX,
+};
+
+#define UFSHCD_AHIBERN8_TIMER_MASK		0x03ff
+#define UFSHCD_AHIBERN8_SCALE_MASK		0x1C00
+
+#endif
